Award Winning FjordsWords & Wisdom by Thomas Reynoldshttp://awardwinningfjords.com/2017-09-26T00:00:00ZT00:00:00-08:00Thomas ReynoldsProgramming With Facts/2017/09/26/programming-with-facts.html2017-09-26T00:00:00ZT00:00:00-08:002017-09-26T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Redux is an infinitely deep tree and every piece of code that accesses it needs to know where to find each piece of data.</p>
<p>MobX is a set of inter-dependent silos which prefer to be singletons and require a lot of magic (such as decorators and observables...</p><p>Redux is an infinitely deep tree and every piece of code that accesses it needs to know where to find each piece of data.</p>
<p>MobX is a set of inter-dependent silos which prefer to be singletons and require a lot of magic (such as decorators and observables).</p>
<p>I could write several thousand words on the difficulties of building large Redux or MobX apps, but I'm sure there are a couple hundred such posts already online.</p>
<p>Instead, I want to try to envision another possible approach to the problem of client-side state management.</p>
<p>My goals are to:</p>
<ul>
<li>Avoid nested data structures.</li>
<li>Avoid silos, and the schemas those silos require.</li>
<li>Avoid <code>class</code>es and <code>decorators</code> because they are a little too magical in JS.</li>
<li>Be "reactive", but not require MobX <code>computed</code>, Redux <code>selectors</code> or RxJS pipelines.</li>
</ul>
<p>My solution, is to borrow from Datomic's schemaless fact-based database. If you know anything about logic programming, this is going to look a bit familiar.</p>
<h2 id="what-is-a-fact">What is a Fact?</h2>
<p>What if we had a completely flat database? Any piece of code could relate any data to any specific object in the system. If module A needs users to have email addresses and module B needs users to have physical address, a schema-less approach will allow them to work without ever having to step on each others toes.</p>
<p>Simply put, a fact is a record (or database row) with a unique id (think guid or whatever their primary key would be), the name of the fact (such as <code>email</code>) and the value of that fact (<code>demo@example.com</code>).</p>
<div class="highlight"><pre class="highlight plaintext"><code>[ uniqueId, variableName, value ]
</code></pre></div>
<p>If I were going to model myself, it might look something like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>[ 1, "name", "Thomas" ]
[ 1, "email", "me@tdreyno.com" ]
[ 1, "url", "https://awardwinningfjords.com" ]
</code></pre></div>
<p>That's just about it. Imagine your entire Redux store as a long list of facts known about the application state.</p>
<p>Because the format is flat and simple, it would be very easy to build tooling to inspect, debug and add time traveling abilities.</p>
<p>All values must be primitives, meaning serialization is trival. Simply <code>JSON.stringify</code> to localstorage and "offline" mode is pretty much done. Want to upload offline changes to the server? Count the number of rows on the server, count the number on the client. Fill the server in on the X number of new changes.</p>
<h2 id="querying">Querying</h2>
<p>Okay, okay. So constantly searching over a massive list of rows for the data you're looking for isn't going to be very fast. It should be surprising that a solution that mimicks a database will need a query language.</p>
<p>Querying looks almost exactly like the data format, but with variables linking rows together.</p>
<p>For example, if I wanted to query for all the data on a single user, I can use the wildcard <code>_</code> character:</p>
<div class="highlight"><pre class="highlight plaintext"><code>[1, _, _]
</code></pre></div>
<p>Which will get me all rows with <code>1</code> in the id position.</p>
<p>If I wanted all emails in the system:</p>
<div class="highlight"><pre class="highlight plaintext"><code>[_, "email", _]
</code></pre></div>
<p>In addition to wildcards, you can also write functions to narrow down queries. If I wanted all the <code>url</code>s on SSL, I could ask:</p>
<div class="highlight"><pre class="highlight plaintext"><code>[_, "url", contains("https://")]
</code></pre></div>
<p>Finally, variables can be used to relate multiple queries. If I wanted the <code>email</code> of people named <code>Thomas</code>:</p>
<div class="highlight"><pre class="highlight plaintext"><code>["?id", "name", "Thomas"]
["?id", "email", "?email"]
</code></pre></div>
<p>Strings starting with <code>?</code> are variables. If the variable appears in more than 1 row, they will create subqueries. Because the first row only matches the id <code>1</code>, the second row will ask for the <code>email</code> of row <code>1</code>. The result will be an object with all matched variables:</p>
<div class="highlight"><pre class="highlight plaintext"><code>{ id: 1, email: "me@tdreyno.com" }
</code></pre></div>
<p>These queries are automatically cached/computed using a Rete network. They will be automatically recalculated reactively when values which are not wildcards are changed (new users named "Thomas" and new emails).</p>
<h2 id="rules">Rules</h2>
<p>The final piece of the puzzle is adding derived state. With Redux these live in selectors. In MobX they are <code>computed</code>. In this system, they are just more rows in the database.</p>
<p>Say I wanted to provide a fact about whether the user uses SSL. I can write a Rule which, when matched, will add a fact. When the facts triggering the rule change, the derived fact can be cleaned up. Other pieces of code don't need to know the difference between "real" state and derived state.</p>
<p>Here's an example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>rule(
["?id", "url", contains("https://")]
).then(match =>
[match.id, "usesSSL", true]
)
</code></pre></div>
<p>Now, for every user <code>id</code> which has a url containing <code>https://</code>, a coresponding <code>usesSSL</code> fact will be created for that <code>id</code>.</p>
<p>If the value of <code>url</code> changes, or if the user is removed, the derived fact will be cleaned up.</p>
<h2 id="demo">Demo</h2>
<p>The now requisite TodoMVC demo can be found at: </p>
<ul>
<li><a href="https://satelite.netlify.com">TodoMVC Demo</a></li>
<li><a href="https://github.com/tdreyno/satelite/tree/master/demo/todomvc/src">TodoMVC Source Code</a></li>
</ul>
<p>The React integration layer provides the <code>subscribe</code> HOC which turns a query into React props. For example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>subscribe(
["global", "ui/filter", "?todoFilter"],
["global", "doneCount", "?completedCount"],
["global", "activeCount", "?activeTodoCount"],
collect("?completed", [_, "todo/completed", true]),
)
</code></pre></div>
<p>Which creates props for three pieces of UI state (<code>todoFilter</code>, <code>completedCount</code> and <code>activeTodoCount</code>). It also uses <code>collect</code> to turn a subquery into an array. In this example, an array of all todos which have <code>completed</code> set to <code>true</code>.</p>
<h2 id="next-steps">Next Steps</h2>
<p>My plans are to find a mid-sized side project, or convert an existing Redux or MobX project, to get a better feeling for how the approach works on non-toy projects.</p>
<p>I'd love feedback! Thanks for reading.</p>
<h2 id="further-reading">Further reading</h2>
<ul>
<li><a href="http://docs.datomic.com/query.html#queries">Datomic Queries</a></li>
<li><a href="https://en.wikipedia.org/wiki/Prolog">Prolog</a></li>
<li><a href="https://en.wikipedia.org/wiki/Rete_algorithm">Rete Network</a></li>
</ul>
Middleman v4/2015/12/16/middleman-v4.html2015-12-16T00:00:00ZT00:00:00-08:002015-12-16T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Middleman v4 Alpha 1 was released 16 months ago. Development hasn't really slowed in that time. I didn't mean to create a massively different codebase for what amounts to a handful of nice user-facing improvements, but, of course, I fell victim to...</p><p>Middleman v4 Alpha 1 was released 16 months ago. Development hasn't really slowed in that time. I didn't mean to create a massively different codebase for what amounts to a handful of nice user-facing improvements, but, of course, I fell victim to one of the most common traps in Open Source: The Grand Rewrite.</p>
<p>v4 started it's life near when 3.3 shipped. We had stability, a growing community and a mature extension API which was providing a ton of value. At that point, the Middleman codebase was 6-7 years old. A lot of the code was bad, "idiomatic" Ruby from before we knew better. Much of the code was Pull Request-ed features that I really should have reviewed more closely. So I decided, to start cleaning things up.</p>
<p>One thing that always bugged me about the codebase was the number of global variables and singleton classes. Practically, you could only run one request at a time against Middleman without fear that the state would get corrupted. The "template scope" was also the "config scope" which was also the main app. Templates could set "private" values that the config relied on or mess with other templates that were already in the act of rendering.</p>
<p>The first big rewrite was pulling these pieces apart. Now we have a template scope, which is a clean sandbox that is unique per template render. We have a config scope, which is unique per <code>config.rb</code> parsing. And the app no longer allows anyone but itself to set its settings.</p>
<p>Next, I went about implementing every piece of functionality in the project in terms of the official extension API. No backdoors, which had the side effect of empowering use extensions even more.</p>
<p>A lot of core functionality relied on a processing step such as ERb or Sass before helper methods could run. Core extensions such as <code>asset_hash</code> required that the user use custom methods, such as <code>asset_url</code> in conjunction with correctly configuring Compass to work. I decided to make Compass support an extension and in doing so, had to re-implement a ton of functionality in a generic way. Now, most of the output manipulation takes place in a piece of Rack middleware. Anything that needs to manipulate asset paths can do so on any content, including non-templated files such as SVGs or raw HTML.</p>
<p>Then, I got ambitious. I added type definitions to the entire codebase. It was (and remains) a fantastic decision, but it made merging from stable increasingly difficult.</p>
<p>Next, I tried to find the pieces of state that could be accidently overwritten and I turned these into Immutable Data Structures using the Hamster library.</p>
<p>Finally, I replaced some old "hash with indifferent access" data with wrappers from the hashie project.</p>
<p>All of that, and not a single user-facing feature mentioned. Sure, we added some cool stuff, but, mostly v4 is about making the Middleman core somewhere I want to work. I don't want to dread the dev environment that I need to spend hours every day in.</p>
<p>I do have to admit to making 1 drastic change nobody will like. I've dropped support for Sprockets from core. I intend to open the existing extension to the community, but that library is really the mosy unpleasant code I've ever had to work with. Every 2 months for the past 7 years, it's caused me heartache. I never use it. If you use it, please reach out about taking over maintance of it. Personally, I'll be using Webpack with our new <code>external_pipeline</code> feature for all JS in the future.</p>
<p>That's basically it. I hope you all enjoy v4, I know I enjoyed making it. Hopefully we don't have too make "dot oh" bugs and that migration from v3 isn't too painful.</p>
My Weird Ruby/2015/03/03/my-weird-ruby.html2015-03-03T00:00:00ZT00:00:00-08:002015-03-03T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Over the past year, I've been rewriting large portions of the Middleman codebase to better reflect how I like to write code (as opposed to the silly version of me who did the original version 6 years ago). I've learned a lot since then, spent pretty...</p><p>Over the past year, I've been rewriting large portions of the Middleman codebase to better reflect how I like to write code (as opposed to the silly version of me who did the original version 6 years ago). I've learned a lot since then, spent pretty much every day writing mostly Javascript and trying to find any excuse to play with Clojure. As a result, my form of Ruby looks pretty strange these days.</p>
<p>Here's a representative piece of code from Middleman v4:</p>
<div class="highlight"><pre class="highlight plaintext"><code># The standard "record" that contains information about a file on disk.
SourceFile = Struct.new :relative_path, :full_path,
:directory, :types
# Find a file given a type and path.
#
# @param [Symbol] type The file "type".
# @param [String] path The file path.
# @param [Boolean] glob If the path contains wildcard or glob.
# @return [Middleman::SourceFile, nil]
Contract Symbol, String, Maybe[Bool] => Maybe[SourceFile]
def find(type, path, glob=false)
watchers
.lazy
.select { |d| d.type == type }
.map { |d| d.find(path, glob) }
.reject(&:nil?)
.first
end
</code></pre></div>
<p>Let's talk about some unfamiliar patterns.</p>
<h2 id="records">Records</h2>
<p>A Record, represented as a <code>Struct</code> in Ruby, is simply a Hash which has pre-defined its keys. This allows you to treat data that represents some item in a predictable way rather than constantly checking for keys or creating a Class which "models" the data.</p>
<div class="highlight"><pre class="highlight plaintext"><code># The standard "record" that contains information about a file on disk.
SourceFile = Struct.new :relative_path, :full_path,
:directory, :types
</code></pre></div>
<p>These days, I'm not a big fan of Classes or inheritance, so the idea of attaching methods to a Class that only works in one context is not appealing. When I use a Record instead, I just get pure data, which is well named, and my methods can either pretend it is a normal Hash or ask if it's a <code>SourceFile</code> and do something special.</p>
<h2 id="laziness-chaining">Laziness & Chaining</h2>
<p>Chaining provides a nice, readable way of describing how data is transformed. The only downside is that iterating over large datasets, just to find one element, is slow. That's where laziness comes in. In ruby, we can call <code>.lazy</code> on an array, then when we iterate it does to lazily. In the following code, <code>.first</code> will run once select has found 1 item, which mapped to a non-nil value, rather than looping over the entire list 3 times (once for <code>select</code>, <code>map</code> and <code>reject</code>).</p>
<div class="highlight"><pre class="highlight plaintext"><code>watchers
.lazy
.select { |d| d.type == type }
.map { |d| d.find(path, glob) }
.reject(&:nil?)
.first
</code></pre></div>
<h2 id="design-by-contract">Design by Contract</h2>
<p>The Ruby <code>contracts</code> gem adds the ability to decorate methods with code that checks that the inputs and the output match what the contract specifies. This is a simple, opt-in way of adding some type checks without going down the rabbit hole of Static Typing everything. At some point, <code>contracts</code> may be able to directly read the YARD doc strings (like Google's Closure and Facebook's Flow do), but for now we have to duplicate this information:</p>
<div class="highlight"><pre class="highlight plaintext"><code># @param [Symbol] type The file "type".
# @param [String] path The file path.
# @param [Boolean] glob If the path contains wildcard or glob.
# @return [Middleman::SourceFile, nil]
Contract Symbol, String, Maybe[Bool] => Maybe[SourceFile]
def find(type, path, glob=false)
</code></pre></div>
<p>Basically, I'm saying that the <code>find</code> method takes 3 parameters, the last of which might be <code>nil</code> (also known as <code>Maybe</code>). The return value will either be a Record of the <code>SourceFile</code> type of <code>nil</code>, which is typed as <code>Maybe[Sourcefile]</code>.</p>
<p>When I started adding Contracts to the code base, I immediately found dozens of tiny bugs and plenty of places where the docs were out of date with the code. I can't see myself ever working on another Ruby project without this type safety net in place. Like testing, I believe you should add just enough contracts/test to cover your ass and not worry about things like 100% coverage.</p>
<h2 id="the-future">The Future</h2>
<p>Going forward, I'd love to see some features from other languages make their way into Ruby. I agree with most everything Erik Michaels-Ober mentions in his talk: <a href="https://rubyconf.eventer.com/rubyconf-australia-2015-1223/towards-a-higher-level-language-by-erik-michaels-ober-1746">Towards a Higher-Level Language</a>. Replace <code>nil</code> with <code>Maybe</code> in the language. Kill Symbol. Fix the standard numbers (this goes for almost every language using IEEE floats).</p>
<p>I also agree with the goals of <a href="http://x.rubini.us">Rubinius X</a>. I want Immutable Data in Ruby. We NEED a real dependency system. If not as robust as Clojure's, let's atleast reach parity with Python. Even Javascript is beating Ruby now :(</p>
<p>I'd like to see optional typing of inputs/outputs.</p>
<p>And finally, pie in the sky, can we solve packaging apps up into distributable binaries, please? Rust and Go are making us look bad.</p>
<p>Thanks for reading.</p>
Book Stuff: 2014/2014/12/26/book-stuff.html2014-12-26T00:00:00ZT00:00:00-08:002014-12-26T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Started some long series (Honor Harrington and Discword), while finishing others (Vorkosigan).</p>
<h2 id="books">Books</h2>
<ul>
<li>First Lord's Fury</li>
<li>Cryoburn</li>
<li>Small Favor</li>
<li>Nexus</li>
<li>Turn Coat</li>
<li>Changes</li>
<li>Crux</li>
<li>Ghost Story</li>
<li>Among Others</li>
<li>The Color of Magic</li>
<li>The Goblin Emperor</li>
<li>Skin Game</li>
<li>The...</li>
</ul><p>Started some long series (Honor Harrington and Discword), while finishing others (Vorkosigan).</p>
<h2 id="books">Books</h2>
<ul>
<li>First Lord's Fury</li>
<li>Cryoburn</li>
<li>Small Favor</li>
<li>Nexus</li>
<li>Turn Coat</li>
<li>Changes</li>
<li>Crux</li>
<li>Ghost Story</li>
<li>Among Others</li>
<li>The Color of Magic</li>
<li>The Goblin Emperor</li>
<li>Skin Game</li>
<li>The Crimson Campaign</li>
<li>A Natural History of Dragons</li>
<li>The Light Fantastic</li>
<li>Prince of Thorns</li>
<li>Words of Radiance</li>
<li>King of Thorns</li>
<li>Half a King</li>
<li>Emperor of Thorns</li>
<li>Full Fathom Five</li>
<li>Prince of Fools</li>
<li>The Broken Eye</li>
<li>Ancillary Sword</li>
<li>Cibola Burn</li>
<li>Mitosis</li>
<li>Curtsies & Conspiracies</li>
<li>The Magician's Land</li>
<li>London Falling</li>
<li>On Basilisk Station</li>
<li>The Severed Streets</li>
<li>The Long Way to a Small, Angry Planet</li>
<li>The Honor of the Queen</li>
</ul>
<h2 id="trends">Trends</h2>
<ul>
<li>4 Books by Mark Lawrence</li>
<li>15 Audio Books</li>
</ul>
<h2 id="stats">Stats</h2>
<ul>
<li>Total Pages: <strong>13974</strong> </li>
<li>Average Pages per Day: <strong>38</strong></li>
</ul>
Best Albums of the Year: 2014/2014/12/24/best-albums-of-the-year-2014.html2014-12-24T00:00:00ZT00:00:00-08:002014-12-24T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Another year, another handful of albums to listen to. Here's my ranking, from 10 to 1.</p>
<ul class="albums">
<li>
<div class="cover">
<img src="/albums/2014/10.jpg"><div></div>
</div>
<div class="content">
<h6>Weezer</h6>
<h4>Everything Will Be Alright In The End</h4>
<p>Explain to me how Weezer can make a good album after 18 years of garbage...</p>
</div>
</li>
</ul><p>Another year, another handful of albums to listen to. Here's my ranking, from 10 to 1.</p>
<ul class="albums">
<li>
<div class='cover'>
<img src='/albums/2014/10.jpg' /><div></div>
</div>
<div class='content'>
<h6>Weezer</h6>
<h4>Everything Will Be Alright In The End</h4>
<p>Explain to me how Weezer can make a good album after 18 years of garbage? Whatever, this one is great seems to be a long apology to fans for all the crap they've been doing since Pinkerton.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2014/9.jpg' /><div></div>
</div>
<div class='content'>
<h6>Adebisi Shank</h6>
<h4>This Is The Third Album of a Band Called Adebisi Shank</h4>
<p>Adebisi Shank gets a little smoother and electronic.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2014/8.jpg' /><div></div>
</div>
<div class='content'>
<h6>Insomnium</h6>
<h4>Shadows of the Dying Sun</h4>
<p>I don't know enough about metal to talk about this album, but I certainly enjoy listening to it.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2014/7.jpg' /><div></div>
</div>
<div class='content'>
<h6>Son of Aurelius</h6>
<h4>Under a Western Sun</h4>
<p>Ditto.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2014/6.jpg' /><div></div>
</div>
<div class='content'>
<h6>Fallujah</h6>
<h4>The Flesh Prevails</h4>
<p>Ditto, again. Metal rock block!</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2014/5.jpg' /><div></div>
</div>
<div class='content'>
<h6>Rx Bandits</h6>
<h4>Gemini, Her Majesty</h4>
<p>Turns out my favorite band of all time decided they weren't quite ready to stay retired. For the first time since Progress (I think), the band has recorded a record that doesn't try to immitate their live show. Instead, Gemini is a simpler, but more varied album that the increasingly complicated albums their tried to end their career with the first time.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2014/4.jpg' /><div></div>
</div>
<div class='content'>
<h6>Run the Jewels</h6>
<h4>Run the Jewels 2</h4>
<p>Back to back appearances by Mike and El-P.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2014/3.jpg' /><div></div>
</div>
<div class='content'>
<h6>The Hotelier</h6>
<h4>Home, Like Noplace Is There</h4>
<p>Best emo album this year or best emo album ever?</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2014/2.jpg' /><div></div>
</div>
<div class='content'>
<h6>Taylor Swift</h6>
<h4>1989</h4>
<p>Haters gonna hate.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2014/1.jpg' /><div></div>
</div>
<div class='content'>
<h6>United Nations</h6>
<h4>The Next Four Years</h4>
<p>It took 4 years, but it's finally here!</p>
</div>
</li>
</ul>
Functional Programming in Javascript === Garbage/2014/04/21/functional-programming-in-javascript-equals-garbage.html2014-04-21T00:00:00ZT00:00:00-08:002014-04-21T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Functional Programming is great. It allows for simpler programs which are easy to test and reason about. Unfortunately, not all languages are created equal. I've been writing a bit of Clojure and really enjoying myself. As I've ported my learnings...</p><p>Functional Programming is great. It allows for simpler programs which are easy to test and reason about. Unfortunately, not all languages are created equal. I've been writing a bit of Clojure and really enjoying myself. As I've ported my learnings and approaches to Javascript, I've encountered a handful of issues which I'd like to talk about.</p>
<h2 id="strong-preference-for-immutable-data">Strong Preference for Immutable Data</h2>
<p>A core design goal for any Functional system is to avoid global mutable state. That is, global variables which any piece of code may change at any time. With the values of these globals outside of your function's control, it makes it hard to return consistent values and reason about your program.</p>
<p>The solution is to not allow state to mutate (and to avoid global variables if possible). What this means is that pushing an item into an array doesn't overwrite the original array, but instead copies it and appends a new item. Javascript is not very good at deep copying its data structures and doing so will create a ton of intermediate variables which are only used once and then garbage collected.</p>
<p>Clojure uses Persistent Data Structures, which avoids deep copying the whole structure and instead builds upon the previous data by creating a new structure that is the new data, plus the previous value. Since these pieces of data are immutable, we can be assured these references will always be correct. Now, when a change is made, no copy needs to happen. Garbage is avoided and memory usage optimized.</p>
<p>ClojureScript, a version of Clojure which compiles to Javascript, includes Persistent Data Structures if you'd like to experiment. There is also the <a href="https://github.com/swannodette/mori">Mori</a> project which takes the ClojureScript structures, compiles to a single-file library and gives them a nice Javascript API.</p>
<p>Without Immutable Data, writing Functional programs in Javascript requires lots of attention in avoiding functions which overwrite values or being comfortable with a lot of expensive copying and garbage generation.</p>
<h2 id="recursion-tail-call-elimination">Recursion & Tail Call Elimination</h2>
<p>Once you begin working with functions, you'll begin passing references of them to other functions. These are called Higher Order Functions and you may already be familiar with them. Take, for example, <code>jQuery.fn.each</code>:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function logElem() {
console.log(this);
}
jQuery("elem").each(logElem);
</code></pre></div>
<p>This is not very functional, since it relies on setting the <code>this</code> value, but you get the idea. For a more functional version, take a look at Underscore's <code>_.each</code>.</p>
<p>If I were getting FP-happy, I might start writing an <code>accumulator</code> or <code>reducer</code> which are both names for a function which takes a list of items and returns a value by iterating over the list.</p>
<p>A <code>map</code> will return an updated value for each item:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function plus1(a) { return a + 1; }
map(plus1, [1,2,3]); // => [2,3,4]
</code></pre></div>
<p>A <code>filter</code> will return a subset of the list, depending on the truthiness of the function.</p>
<div class="highlight"><pre class="highlight plaintext"><code>function even(a) { return a % 2 === 0; }
filter(even, [1,2,3]); // => [2]
</code></pre></div>
<p>These can both be written as a reducer.</p>
<div class="highlight"><pre class="highlight plaintext"><code>function map(f, list) {
return reduce(function(val, sum) {
sum.push(f(val));
return sum;
}, list, []);
}
</code></pre></div>
<p>The reducer takes a function which can update a value <code>sum</code> which starts at <code>[]</code> and is updated once for each item in the list.</p>
<p>Okay, that was a long lead in. Here's how you could naively implement a reducer:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function reduce(f, list, sum) {
if (list.length < 1) {
return sum;
} else {
var val = list.shift();
return reduce(f, list, f(val, list));
}
}
</code></pre></div>
<p>Nice and clean (other than the mutating of the list). However, by using recursion in Javascript, we've introduce a time bomb into our code. Each time JS steps deeper into <code>reduce</code>, it retains the old stack of calls. Depending on the browser, the version and the amount of available memory, the browser may decide your stack is too deep and throw an unexpected exception. This may not show up in tests and is really scary to consider.</p>
<p>Languages with Tail Call Elimination will recognize this situation and basically rewrite the function into a <code>while</code> loop. Since this is a low-level function, we should do the same, but sometimes it's hard to know when you're recurring dangerously.</p>
<p>Another way to avoid the issue is to use an approach called <code>Trampolining</code>. Writing a reducer in this way means each iteration does not return a value, instead it returns a function which calls the next iteration. It would look like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function trampoline(f) {
return function() {
var result = f.apply(this, arguments);
while (result instanceof Function) {
result = result();
}
return result;
};
}
var reduce = trampoline(function myself(f, list, sum) {
if (list.length < 1) {
return sum;
} else {
return function() {
var val = list.shift();
return myself(f, list, f(val, list));
};
}
});
</code></pre></div>
<p>At this point in time, we're feeling pretty damn proud of ourselves. Our recursive functions won't randomly explode. We've got a core iteration method we can build <code>map</code>, <code>filter</code> and more upon. But we've introduced a critical flaw: more garbage.</p>
<p>Now, every single time we iterate over a list, we create 1 temporary function for each item in the list. If you do something like the following, you're going to generate a ton of garbage and drop frames:</p>
<div class="highlight"><pre class="highlight plaintext"><code>requestAnimationFrame(function() {
each(tickPhysics, worldEntities);
});
</code></pre></div>
<p>Therefore, to avoid garbage generation, we need to remember to avoid recursion in our low-level iterators and use a simple, but not very functional, <code>while</code> loop. For a much more in-depth discussion of Trampolines in JS, read <a href="http://raganwald.com/2013/03/28/trampolines-in-javascript.html">Reginald Braithwaite's article</a>.</p>
<h2 id="function-composition-partial-application">Function Composition & Partial Application</h2>
<p>Instead of passing anonymous functions to iterators, many Functional programmers use Composition and Partial Application to generate new functions instead. Above we had the example of <code>plus</code>, this could be written like so:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function plus(a, b) { return a + b; }
var plus1 = partial(plus, 1);
map(plus1, [1,2,3]); // => [2,3,4]
</code></pre></div>
<p>Now, we have a <code>plus1</code> function which is simply the <code>plus</code> function with the first argument already filled in. An implementation of <code>partial</code> would look like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function partial() {
var args = Array.prototype.slice.call(arguments, 0);
var f = args.shift();
return function partialExecute_() {
var args2 = Array.prototype.slice.call(arguments, 0);
return f.apply(this, args.concat(args2));
};
}
</code></pre></div>
<p>Notice that we create an Array and a Function every time we call partial and an additional array each time the <code>partial</code>ed function is called. This isn't a critical problem, but it is something to be careful of.</p>
<p>Function composition is similar, it allows you to take two functions and create a new function which calls both of them.</p>
<div class="highlight"><pre class="highlight plaintext"><code>function plus1(a) { return a + 1; };
function mult2(a) { return a * 2; };
var addThenMult = compose(mult2, plus1);
map(addThenMult, [1,2,3]); // => [4,6,8]
</code></pre></div>
<p>A simple implementation would be:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function compose() {
var fns = Array.prototype.slice.call(arguments, 0);
return function composedExecute_(value) {
for (var i = fns.length - 1; i >= 0; --i) {
value = fns[i](value);
}
return value;
};
}
</code></pre></div>
<p>More Arrays and more Functions. Again, not a big deal, but if you are doing a lot of <a href="http://en.wikipedia.org/wiki/Tacit_programming">Point-free Programming</a>, then your loops have the possibility of generating a ton of garbage.</p>
<h2 id="conclusion">Conclusion</h2>
<p><strong>Never forget that Javascript hates you.</strong> Functional programming can be a nice way to write a system, but always remember the language you are running on. Most of these issues can be overcome with a little attention.</p>
<p>Finally, I'll use this opportunity to plug Reginald Braithwaite's wonderful book on Functional Programming: <a href="https://leanpub.com/javascript-allonge/read">Javascript Allongé</a>. It's free to read, so you should probably do that.</p>
Still Reading/2013/12/31/still-reading.html2013-12-31T00:00:00ZT00:00:00-08:002013-12-31T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I read a lot this year. Not as much as last year, but still not too shabby.</p>
<h2 id="books">Books</h2>
<ul>
<li>Best Served Cold</li>
<li>A Civil Campgaign</li>
<li>The Heroes</li>
<li>Diplomatic Immunity</li>
<li>Red Country</li>
<li>The Human Division</li>
<li>Etiquette & Espionage</li>
<li>Caliban's War</li>
<li>Warbreaker</li>
<li>The Rithmatist</li>
<li>Elantris</li>
</ul><p>I read a lot this year. Not as much as last year, but still not too shabby.</p>
<h2 id="books">Books</h2>
<ul>
<li>Best Served Cold</li>
<li>A Civil Campgaign</li>
<li>The Heroes</li>
<li>Diplomatic Immunity</li>
<li>Red Country</li>
<li>The Human Division</li>
<li>Etiquette & Espionage</li>
<li>Caliban's War</li>
<li>Warbreaker</li>
<li>The Rithmatist</li>
<li>Elantris</li>
<li>Throne of the Crescent Moon</li>
<li>Abbadon's Gate</li>
<li>Captain Vorpatril's Alliance</li>
<li>Three Parts Dead</li>
<li>The Killing Moon</li>
<li>Steelheart</li>
<li>The Curse of Chalion</li>
<li>The Thousand Names</li>
<li>The Republic of Theives</li>
<li>Two Serpents Rise</li>
<li>Ancillary Justice</li>
<li>The Black Prism</li>
<li>The Blinding Knife</li>
<li>Promise of Blood</li>
</ul>
<h2 id="trends">Trends</h2>
<ul>
<li>3 Books by Joe Abercrombie</li>
<li>4 Books by Brandon Sanderson</li>
<li>4 Books by Lois McMaster Bojold</li>
<li>5 Audio Books (remaining Codex Alera books)</li>
</ul>
<h2 id="stats">Stats</h2>
<ul>
<li>Total Pages: <strong>12551</strong> </li>
<li>Average Pages per Day: <strong>34</strong></li>
</ul>
Made Some Websites in 2013/2013/12/22/made-some-websites.html2013-12-22T00:00:00ZT00:00:00-08:002013-12-22T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Looking back over 2013, I'm pretty proud of the projects I was able to work on. Of course, I've had no meaningful output on this blog since April, but other than that I was quite busy. Most of these projects were group efforts with multiple developers...</p><p>Looking back over 2013, I'm pretty proud of the projects I was able to work on. Of course, I've had no meaningful output on this blog since April, but other than that I was quite busy. Most of these projects were group efforts with multiple developers and the rest of my co-workers at <a href="http://weareinstrument.com">Instrument</a>.</p>
<h2 id="how-search-works"><a href="http://www.google.com/insidesearch/howsearchworks/thestory/">How Search Works</a></h2>
<p>This 13,000px tall website tells the story of how Google searches the internet in an accurate, but whimsical, way. I was an attempt on our behalf to so a "super scroll narrative" without the 1-to-1 parallax scrolling effect so popular at the time.</p>
<p><a href="http://www.google.com/insidesearch/howsearchworks/thestory/"><img src="/images/2013-sites/hsw.jpg" alt="How Search Works" /></a></p>
<h2 id="google-i-o"><a href="https://developers.google.com/events/io/experiment">Google I/O</a></h2>
<p>This was my second year working on the I/O experiment. This year, we build a Wario World-inspired series of mobile games which could be unlocked by entering binary patterns into the new I/O logo.</p>
<p><a href="https://developers.google.com/events/io/experiment"><img src="/images/2013-sites/io.jpg" alt="Google I/O" /></a></p>
<h2 id="coke-mobile-experiments">Coke Mobile Experiments</h2>
<p>I built 2 mobile toys for the Coke ahh.com campaign this summer. These, especially Flip The Cap, were really fun on mobile.</p>
<p><a href="http://www.ahhhhhhhhhhhhhhhhhhh.com"><img src="/images/2013-sites/flip.jpg" alt="Flip The Cap" /></a> <a href="http://www.ahhhhhhhhhhhhhhhhhhhhhh.com"><img src="/images/2013-sites/funniest.jpg" alt="You Are The Funniest" /></a></p>
<h2 id="android-com"><a href="http://www.android.com">Android.com</a></h2>
<p>We rebuilt Android's home on the web, kept things simple, brought in some nice moments of suprise & delight... all the while keeping the page weight very light on mobile (250kb homepage!).</p>
<p><a href="http://www.android.com"><img src="/images/2013-sites/android.jpg" alt="Android.com" /></a></p>
<h2 id="google-zeitgeist"><a href="http://www.google.com/zeitgeist">Google Zeitgeist</a></h2>
<p>Discover the top searches and G+ photos in this beautifully animated, infinite grid. It's an absolute joy to use on tablet or with a nice trackpad.</p>
<p><a href="http://www.google.com/zeitgeist"><img src="/images/2013-sites/zeitgeist.jpg" alt="Google Zeitgeist" /></a></p>
Best Albums of the Year: 2013/2013/12/17/best-albums-of-the-year-2013.html2013-12-17T00:00:00ZT00:00:00-08:002013-12-17T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>After my disappointment with 2012, this year came back with some great albums. I'm not going to bother to rank them, but here they are.</p>
<ul class="albums">
<li>
<div class="cover">
<img src="/albums/2013/5.jpg"><div></div>
</div>
<div class="content">
<h6>Jizue</h6>
<h4>Journal</h4>
<p>I've developed a fascination for Japanese Neo-Jazz when...</p>
</div>
</li>
</ul><p>After my disappointment with 2012, this year came back with some great albums. I'm not going to bother to rank them, but here they are.</p>
<ul class="albums">
<li>
<div class='cover'>
<img src='/albums/2013/5.jpg' /><div></div>
</div>
<div class='content'>
<h6>Jizue</h6>
<h4>Journal</h4>
<p>I've developed a fascination for Japanese Neo-Jazz when coding, but since I know no Japanese and little about Jazz, I'm going to have to leave it at that. As hardcore is to post-hardcore, so Jazz is to this genre. Technical, but short.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2013/8.jpg' /><div></div>
</div>
<div class='content'>
<h6>Run the Jewels</h6>
<h4>Run the Jewels</h4>
<p>Basically the sequel to last year's fantastic debut from Killer Mike. I'll let Mike tell you why this album is awesome: "Producer gave me a beat. Said it's the beat of the year. I said El-P didn't do it. So get the fuck outta here." I agree.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2013/9.jpg' /><div></div>
</div>
<div class='content'>
<h6>Streetlight Manifesto</h6>
<h4>The Hands That Thieve</h4>
<p>The last Ska band of any quality has retired and this is their magnum opus. I'm not sure how you feel about Ska, but I'm begging you to give this a chance. The music is varied, technical and inventive. The lyrics are personal and positively atheistic.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2013/10.jpg' /><div></div>
</div>
<div class='content'>
<h6>Ling tosite sigure</h6>
<h4>i'mperfect</h4>
<p>Japaneses post-harcore shreding with Emo vocals. I don't understand a word of it, but honestly, how's that different than most of the metal screaming and growling I listen to. I'm not sure this trio is unheard of, but they were new to me and really made my year.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2013/2.jpg' /><div></div>
</div>
<div class='content'>
<h6>And So I Watch You From Afar</h6>
<h4>All Hail Bright Futures</h4>
<p>This Belfast-based post-hardcore band, in addition to having an absolutely incredible live show, have released three straight albums of frenzied guitar and anthemy vocals. With their latest, they smooth things out and have become much more approachable.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2013/3.jpg' /><div></div>
</div>
<div class='content'>
<h6>The Cat Empire</h6>
<h4>Steal The Light</h4>
<p>I have every single album by this Australian, Cuban-influenced, lounge band with both a scat singer and a middle-eastern-style warbler. They're all fantastic, but this one is accessible to everyone and incredibly charming. See them live. It's an experience.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2013/4.jpg' /><div></div>
</div>
<div class='content'>
<h6>Deafheaven</h6>
<h4>Sunbather</h4>
<p>Somewhere between post-rock, post-hardcore and hipster metal. This album is an absolute riot, drowning out any other thought you might be trying to have. As is becoming a trend with this list, this band is a must-see live.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2013/7.jpg' /><div></div>
</div>
<div class='content'>
<h6>Lorde</h6>
<h4>Pure Heroine</h4>
<p>This is 2013's version of The Postal Service. Great songs with a little electronic flair. I'm sure we'll be getting re-issued vinyl and reunion tours in a decade. Or maybe this 16 year old song-writer and musician will be so huge in 10 years she won't event think about this astounding debut.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2013/6.jpg' /><div></div>
</div>
<div class='content'>
<h6>Kanye West</h6>
<h4>Yeezus</h4>
<p>Duh. Me, along with everyone who reviews music, loves this album. Kanye has balls. After the lush, operatic "Dark Fantasy," he reboots his sound with a sparse, industrial album he basically just threw together at the last minute. Don't over think it.</p>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2013/1.jpg' /><div></div>
</div>
<div class='content'>
<h6>Anamanaguchi</h6>
<h4>Endless Fantasy</h4>
<p>This chip-tune band, which has a spectacular live show with real instruments, finally took the promise of those live shows and put that into an album. Whereas before, they aped gameboy-style sound effects, now they're happy to simply be influenced by those sounds and that era. The album is put together fantastically with great songs throughout, a couple dancey numbers and even vocals this time around. Get the album. Go see them live.</p>
</div>
</li>
</ul>
Google I/O 2013 Experiment Roundup/2013/04/16/google-io-2013-roundup.html2013-04-16T00:00:00ZT00:00:00-08:002013-04-16T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>This year for Google I/O's pre-conference web site, we (Instrument) created a series of mobile-first experiments. It looks like this:</p>
<p><img src="http://instrument.github.io/google-io-2013/article/home.gif" width="480" height="396"></p>
<p>Check out the whole thing at: <a href="https://developers.google.com/events/io/">https://developers.google.com/events/io/</a> and see if you can find all the unlockable...</p><p>This year for Google I/O's pre-conference web site, we (Instrument) created a series of mobile-first experiments. It looks like this:</p>
<p><img src="http://instrument.github.io/google-io-2013/article/home.gif" width="480" height="396"></p>
<p>Check out the whole thing at: <a href="https://developers.google.com/events/io/">https://developers.google.com/events/io/</a> and see if you can find all the unlockable modes via 8-bit I/O patterns.</p>
<h3 id="html5rocks-case-study">HTML5Rocks Case Study</h3>
<p>We wrote about some of the technical details of the project for HTML5Rocks at: <a href="http://www.html5rocks.com/en/tutorials/casestudies/google-io-2013/">http://www.html5rocks.com/en/tutorials/casestudies/google-io-2013/</a></p>
<h3 id="open-source">Open Source</h3>
<p>We also open sourced the code. It's on Github at: <a href="https://github.com/Instrument/google-io-2013">https://github.com/Instrument/google-io-2013</a></p>
<h3 id="make-your-own-mode-tutorial">Make Your Own Mode Tutorial</h3>
<p>Finally, we forked the open source project to add our own "3rd party" experiment called "Flip Mode", which you can check out here: <a href="http://instrument.github.io/google-io-2013-flip-mode/modes/flip.html">http://instrument.github.io/google-io-2013-flip-mode/modes/flip.html</a></p>
<p>The tutorial for how others can create their own modes is on the Instrument Blog: <a href="http://weareinstrument.com/blog/all/google-i-o-2013-open-source">http://weareinstrument.com/blog/all/google-i-o-2013-open-source</a></p>
Middleman Blog Editor v0.4/2013/04/08/middleman-blog-editor-04.html2013-04-08T00:00:00ZT00:00:00-08:002013-04-08T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I'm happy to announce <a href="http://middleman-blog-editor.awardwinningfjords.com">Middleman Blog Editor v0.4</a>, the second feature release of the project. With this release comes two big features and a bump in price to $12. <a href="http://register.tdreyno.com">You can purchase a license here</a>. Existing users get free updates all the way until the...</p><p>I'm happy to announce <a href="http://middleman-blog-editor.awardwinningfjords.com">Middleman Blog Editor v0.4</a>, the second feature release of the project. With this release comes two big features and a bump in price to $12. <a href="http://register.tdreyno.com">You can purchase a license here</a>. Existing users get free updates all the way until the 2.0 release. The next release, the price will be bumped to $18.</p>
<p>The first new feature is the ability to "Open in editor" via a button on the preview pages of the blog entries. If you're looking at <code>/2013-04-08-my-article</code>, there will be an "Edit" link in the top-right to jump you directly into the editor.</p>
<p>The second feature is a big one:</p>
<h3 id="markdown-editing">Markdown Editing</h3>
<p>Now markdown articles, <code>.md</code> and <code>.markdown</code> templates, have their own editor. The default view mirrors your content back to you and allows you to toggle between editing and previewing with a click. There is also a split-screen "focus" mode which allows you to edit articles full screen and stay focused.</p>
<p><img src="/images/blog-editor/markdown.png" alt="Article Editor" />
<img src="/images/blog-editor/fullscreen.png" alt="Full Screen Editor" /></p>
<h3 id="purchase-a-license"><a href="http://register.tdreyno.com">Purchase a license</a></h3>
<h3 id="future-roadmap">Future roadmap:</h3>
<h4 id="0-6-18">0.6 ($18)</h4>
<ul>
<li>Frontmatter Editing</li>
<li>Article Searching (Full Text)</li>
<li>Article Sorting (By Tags, Date, etc)</li>
<li>List Paging</li>
</ul>
<h4 id="0-8-24">0.8 ($24)</h4>
<ul>
<li>Client Accounts & Permission</li>
<li>White-label Admin</li>
</ul>
<h4 id="1-0-30">1.0 ($30)</h4>
<ul>
<li>Final Polish</li>
<li>Full Test-coverage (automated on Travis)</li>
<li>Code docs</li>
</ul>
<h4 id="2-0">2.0</h4>
<ul>
<li>Admin Localization</li>
<li>Wordpress Importer</li>
<li>Disqus Integration</li>
<li>Edit non-local (Git Push/Pull)</li>
<li>Markdown/Textile Editing</li>
</ul>
<h3 id="official-website">Official Website</h3>
<p>Please refer to the official website for documentation and support: <a href="http://middleman-blog-editor.awardwinningfjords.com">http://middleman-blog-editor.awardwinningfjords.com</a></p>
New Features: Image Optimization, CDN and Gzip Support/2013/03/10/fjords-update-optimzation-cdn-gzip.html2013-03-10T00:00:00ZT00:00:00-08:002013-03-10T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Today I'm happy to announce the first round of new <a href="http://fjords.cc">Fjords</a> features. If you're not yet a user, <a href="http://fjords.cc">find out more on the website</a>.</p>
<p>First, you'll need to update the Command-line Tool or Middleman extension to version <strong>1.1.0</strong>. This is as easy as:</p>
<div class="highlight"><pre class="highlight plaintext"><code>gem update...</code></pre></div><p>Today I'm happy to announce the first round of new <a href="http://fjords.cc">Fjords</a> features. If you're not yet a user, <a href="http://fjords.cc">find out more on the website</a>.</p>
<p>First, you'll need to update the Command-line Tool or Middleman extension to version <strong>1.1.0</strong>. This is as easy as:</p>
<div class="highlight"><pre class="highlight plaintext"><code>gem update fjords
</code></pre></div>
<p>For Middleman, update your <code>Gemfile</code> to:</p>
<div class="highlight"><pre class="highlight plaintext"><code>gem "middleman-fjords", "~> 1.1.0"
</code></pre></div>
<p>Now, let's get to the fun stuff.</p>
<h2 id="automatic-image-compression">Automatic Image Compression</h2>
<p>One of our goals going forward is to help make your websites as fast as possible without our users having to worry about it. As of today, all pushes to Fjords will automatically run all images through a bunch of image compression tools: AdvPNG, Pngcrush, extended OptiPNG, JpegOptim, jpegrescan, jpegtran, and Gifsicle.</p>
<p>These tools can losslessly shrink the size of your image assets by about 30%. Photoshop should really do this for you, but it doesn't so we'll pick up the slack. <a href="http://imageoptim.com/tweetbot.html">Check out this article</a> by the ImageOptim developer on the kind of savings you can now expect.</p>
<p>We're investigating an option to automatically minify your CSS, JS & HTML as well.</p>
<h2 id="serve-gzipped-assets">Serve Gzipped Assets</h2>
<p>Gzipping assets is an easy way to drastically cut the size of CSS, JS and HTML assets which the browser has to download. In systems with a dynamic backend, that backend can detect whether the browser wants Gzip content and respond accordingly. Unfortunately, in a purely static system like Fjords, we have to either detect what the browser wants in Javascript or choose to send Gzipped content to all browsers.</p>
<p>Fjords 1.1.0 will allow you to enable Gzip support on your assets. It's as easy as:</p>
<div class="highlight"><pre class="highlight plaintext"><code>fjords gzip:enable my-site.fjords.cc
</code></pre></div>
<p>From now on, all browsers will get Gzipped content. Please be patient as we need to compress and re-deploy all your content in the background.</p>
<p>If you change your mind:</p>
<div class="highlight"><pre class="highlight plaintext"><code>fjords gzip:disable my-site.fjords.cc
</code></pre></div>
<p><strong>Note: If you're using Middleman's <code>:gzip</code> feature, you should disable that before activating this.</strong></p>
<h2 id="cdn-content-delivery-network">CDN (Content Delivery Network)</h2>
<p>CDNs are the fastest way to serve static content. If you want your site to be lightning fast, enabling CDN support will push your content to web servers around the globe. When it comes to hundreds of milliseconds-per-request, having the server with your content physically closer to your users makes a huge difference.</p>
<p>Enabling the CDN for your site will cost $2 per month. It also takes longer to deploy around the world, so it may take up to an hour for your updated content to appear in all locations.</p>
<p>Here's how it works:</p>
<div class="highlight"><pre class="highlight plaintext"><code>fjords cdn:enable my-site.fjords.cc
</code></pre></div>
<p>Now you have two options. <code>my-site.fjords.cc</code> will load the non-CDN version and <code>my-site-cdn.fjords.cc</code> will load the CDN copy. Point your DNS at the newly available <code>-cdn</code> domain.</p>
<p>If you decide the extra speed isn't worth it to you, you can disable it.</p>
<div class="highlight"><pre class="highlight plaintext"><code>fjords cdn:disable my-site.fjords.cc
</code></pre></div>
<h4 id="sound-interesting-find-out-more">Sound Interesting? <a href="http://fjords.cc">Find Out More</a></h4>
A WWDC for the Web/2013/02/13/a-wwdc-for-the-web.html2013-02-13T00:00:00ZT00:00:00-08:002013-02-13T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>The last few years has seen an explosion in what's possible with Web technologies. The Mobile Web will soon be the way the majority of users view your site. HTML5 applications are robust, stable and becoming ubiquitous. Simply put: the Web platform...</p><p>The last few years has seen an explosion in what's possible with Web technologies. The Mobile Web will soon be the way the majority of users view your site. HTML5 applications are robust, stable and becoming ubiquitous. Simply put: the Web platform is maturing.</p>
<p>But here's my concern. The Web community, especially the real world conferences and meetups, has yet to mature.</p>
<p><em>Caveat City: Your conference, your users and your developers are all great. This isn't an insult or an attack. But the breadth of technologies in play has exploded. jQuery is now the bedrock of the platform, a full understanding of it should be assumed and we should be learning and teaching more.</em></p>
<p><em>Caveat City 2: Fun conferences and communities are great. Keep making JS-powered helicopters and browser computer vision prototypes.</em></p>
<h2 id="what-does-mature-look-like">What does Mature look like?</h2>
<p>Maturity is about <strong>shipping</strong>. If it doesn't ship, isn't in use or hasn't been field tested, it's a toy. Shipping is hard. The web platform is spread across hundreds of device-browser-resolution-input combinations and being successful on this platform requires a lot of knowledge and experience.</p>
<p>Once your product goes from prototype to production, you'll end up encountering and hacking around insane browser, device and library bugs. This is part of being mature. Knowing that the world isn't perfect and shipping anyways.</p>
<p>I want a conference that speaks to those of us, and there are so many, shipping real products with real world problems. Somewhere between the Steak & Hookers "industry" conferences of the enterprise world and the indie free-for-all, we need a Web conference for professionals.</p>
<h2 id="how-boring-are-we-talking">How Boring Are We Talking?</h2>
<p>WWDC is a conference for professionals. Sure, there is the media frenzy surrounding the keynote, but after that, the attendees have access to dozens of sessions with very complex topics which are specifically useful to different people. WWDC also provides direct access to the very developers who built the APIs and tools the attendees use.</p>
<p>Would this be boring to the people who just want to add basic interactions to their website? Sure, but it's not for them. You've got a new JS framework to show off? Sorry, talk to me when it's in production on a dozen sites. Keep your flash-y naive demos with CSS Animations that would never work on a real site to yourself.</p>
<p>I want a Web conference with deep talks on the Web Audio API. I want to see behind-the-scenes information on HTML5 game development. All that crazy pipelining Facebook does to speed up their site? I want to know about it. Someone expound on Google's SPDY protocol. How do I use Hypermedia APIs?</p>
<p>I want a lab where the Webkit developers can show me all the little hacks they know and I can show them the list of silly edge case bugs I've found.</p>
<p>I want a conference that knows that its attendees are doing this for a living. They are shipping and if they want to sleep at night, they need to learn more about bigger and more difficult concepts.</p>
<p><em>Caveat City 3: I attended Google I/O last year and the Chrome track was very close to what I suggest above. If only Web WWDC and Chrome I/O could merge, with just a little more "flair"</em></p>
<p>The Web has matured. There are developers working on as complicated and professional projects as the native platforms ever have. We need to step-up the conference game and begin tackling the hard problems. </p>
Fjords: A Simple Service for Sharing Static Websites/2013/02/11/fjords.html2013-02-11T00:00:00ZT00:00:00-08:002013-02-11T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I'm very excited to announce my new project, <a href="http://fjords.cc">Fjords</a>.</p>
<p><a href="http://fjords.cc"><img src="/images/monitor-goblins.png" alt="Fjords"></a></p>
<p>Fjords is a service that lets you upload your static websites to be hosted in the cloud.</p>
<h3 id="use-case-agency-environment">Use Case: Agency Environment</h3>
<p>I happen to work <a href="http://weareinstrument.com">at an agency</a>. As we design and build projects, we constantly...</p><p>I'm very excited to announce my new project, <a href="http://fjords.cc">Fjords</a>.</p>
<p><a href="http://fjords.cc"><img src="/images/monitor-goblins.png" alt="Fjords" /></a></p>
<p>Fjords is a service that lets you upload your static websites to be hosted in the cloud.</p>
<h3 id="use-case-agency-environment">Use Case: Agency Environment</h3>
<p>I happen to work <a href="http://weareinstrument.com">at an agency</a>. As we design and build projects, we constantly need to send our work-in-progress to our clients for their review. With Fjords, we can generate temporary sites for client review. It's easy:</p>
<div class="highlight"><pre class="highlight plaintext"><code>cd my-client-project && fjords push
</code></pre></div>
<p>In a few moments, I'm given a dynamic URL (such as <a href="http://a1a1a1a.fjords.cc">http://a1a1a1a.fjords.cc</a>) which I can send out for review. These sites last for 30-days by default, but can be marked as "permanent" if you're working on a long-term project.</p>
<h3 id="use-case-personal-projects-microsites-blogs">Use Case: Personal Projects, Microsites & Blogs</h3>
<p>As I built Fjords, I began switching all my static sites to it for testing purposes. This blog has been running on Fjords for weeks! Octopress and Middleman are popular static blogging platforms which we've added dead-simple integration for.</p>
<p>With the <code>middleman-fjords</code> plugin, updating and deploying this blog is as easy as:</p>
<div class="highlight"><pre class="highlight plaintext"><code>middleman fjords --rebuild
</code></pre></div>
<p>Octopress & Jekyll are just as easy:</p>
<div class="highlight"><pre class="highlight plaintext"><code>rake fjords
</code></pre></div>
<h2 id="the-dreaded-command-line">The Dreaded Command-line</h2>
<p>As you can see above, all the examples are using the terminal. This makes sense as Middleman, Jekyll and Octopress users were our first target, <strong>but fear not!</strong></p>
<p>Our next round of updates will feature a Mac OS X drag-and-drop application, Dropbox integration and the built-in support of some popular GUI tools for front-end developers.</p>
<p>We're growing the service slowly. No doubt the floodgates will really open when we make Fjords accessible to users unfamiliar with the terminal.</p>
<h3 id="signing-up">Signing Up</h3>
<p>Hopefully, this all sounds interesting to you. <a href="http://fjords.cc/">If you want to run off and sign up right now, I'm not going to stop you</a>. If not, let's talk price.</p>
<p>Fjords is <strong>$6 per month</strong> for unlimited "preview" sites. These are the 30-day (by default, but free to extend) domains hosted under <code>fjords.cc</code>. This plan also include <strong>1 site using your own domain name</strong>. For example, this site has pointed its <code>CNAME</code> record at Fjords, so it can use a custom domain name. Additional custom domain names are <strong>$2 per site</strong>.</p>
<p>This is a small service and we're going to grow safely and slowly, but we'd love to have you join us. I'm available for questions, bug reports and feature requests at <a href="mailto:admin@fjords.cc">admin@fjords.cc</a>.</p>
<h3 id="sign-up-now"><a href="http://fjords.cc">Sign Up Now</a></h3>
Middleman Blog Editor/2013/01/02/middleman-blog-editor.html2013-01-02T00:00:00ZT00:00:00-08:002013-01-02T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I'm incredibly excited to announce my holiday project: the <a href="http://middleman-blog-editor.awardwinningfjords.com">Middleman Blog Editor</a>. This is my first paid extension for <a href="http://middlemanapp.com">Middleman</a> and one that I hope will prove that the community is large and mature enough for 3rd-party features and extensions to have...</p><p>I'm incredibly excited to announce my holiday project: the <a href="http://middleman-blog-editor.awardwinningfjords.com">Middleman Blog Editor</a>. This is my first paid extension for <a href="http://middlemanapp.com">Middleman</a> and one that I hope will prove that the community is large and mature enough for 3rd-party features and extensions to have become valuable.</p>
<p>Middleman Blog Editor is an extension which uses Middleman Blog to provide a beautiful organizational interface and WYSIWYG editing. The UI can currently publish/unpublish articles, edit tags, change the article date and URL.</p>
<p>This extension makes it possible to host a Middleman Blog and give the editor URL to a client so they can add content. Files are modified in-place, so committing those changes to source control or deploying new builds is up to you.</p>
<h2 id="purchase"><a href="http://register.tdreyno.com">Purchase</a></h2>
<p>Help make this experiment a success, you can purchase the extension for <strong>$6</strong> at: <a href="http://register.tdreyno.com">http://register.tdreyno.com</a></p>
<p>There will be 5 feature releases. Pricing will be a simple multiple of the price (<strong>$30</strong>), by the current version. <strong>Free updates for the entire 1.0.x line, after initial purchase.</strong></p>
<h2 id="current-features-and-roadmap">Current Features and Roadmap</h2>
<h3 id="0-4-12">0.4 ($12)</h3>
<ul>
<li>Frontmatter Editing</li>
<li>Direct link to editor from in the site preview</li>
<li>Markdown Preview</li>
</ul>
<h3 id="0-6-18">0.6 ($18)</h3>
<ul>
<li>Article Searching (Full Text)</li>
<li>Article Sorting (By Tags, Date, etc)</li>
<li>List Paging</li>
</ul>
<h3 id="0-8-24">0.8 ($24)</h3>
<ul>
<li>Client Accounts & Permission</li>
<li>White-label Admin</li>
</ul>
<h3 id="1-0-30">1.0 ($30)</h3>
<ul>
<li>Final Polish</li>
<li>Full Test-coverage (automated on Travis)</li>
<li>Code docs</li>
</ul>
<h3 id="2-0">2.0</h3>
<ul>
<li>Admin Localization</li>
<li>Wordpress Importer</li>
<li>Disqus Integration</li>
<li>Edit non-local (Git Push/Pull)</li>
<li>Markdown/Textile Editing</li>
</ul>
<h2 id="official-website">Official Website</h2>
<p>Please refer to the official website for documentation and support: <a href="http://middleman-blog-editor.awardwinningfjords.com">http://middleman-blog-editor.awardwinningfjords.com</a></p>
<h2 id="heres-what-it-looks-like">Here's what it looks like:</h2>
<p><img src="/images/blog-editor/list.png" alt="Article List" />
<img src="/images/blog-editor/wysiwyg.png" alt="WYSIWYG Editor" /></p>
Moar Kindle Dots/2012/12/31/moar-kindle-dots.html2012-12-31T00:00:00ZT00:00:00-08:002012-12-31T00:00:00ZT00:00:00-08:00Thomas Reynolds<h2 id="trends">Trends</h2>
<ul>
<li>5 Books by Brandon Sanderson (plus 1 novella and an audio book)</li>
<li>7 Vorkosigan Novels (Lois McMaster Bujold)</li>
<li>3 Books by John Scalzi</li>
<li>3 Trilogies (Mistborn, The First Law, The Hundred Thousand Kingdoms)</li>
<li>3 Audio Books (Legion, Fool Moon & Grave...</li>
</ul><h2 id="trends">Trends</h2>
<ul>
<li>5 Books by Brandon Sanderson (plus 1 novella and an audio book)</li>
<li>7 Vorkosigan Novels (Lois McMaster Bujold)</li>
<li>3 Books by John Scalzi</li>
<li>3 Trilogies (Mistborn, The First Law, The Hundred Thousand Kingdoms)</li>
<li>3 Audio Books (Legion, Fool Moon & Grave Peril)</li>
</ul>
<h2 id="books">Books</h2>
<table><thead>
<tr>
<th>Title</th>
<th>Pages</th>
</tr>
</thead><tbody>
<tr>
<td>Best Served Cold</td>
<td>640</td>
</tr>
<tr>
<td>The Emperor's Soul</td>
<td>176</td>
</tr>
<tr>
<td>Komarr</td>
<td>328</td>
</tr>
<tr>
<td>Last Argument of Kings</td>
<td>639</td>
</tr>
<tr>
<td>Before They Are Hanged</td>
<td>543</td>
</tr>
<tr>
<td>The Dirty Streets of Heaven</td>
<td>400</td>
</tr>
<tr>
<td>The Blade Itself</td>
<td>531</td>
</tr>
<tr>
<td>Timeless</td>
<td>416</td>
</tr>
<tr>
<td>Heartless</td>
<td>400</td>
</tr>
<tr>
<td>Blameless</td>
<td>384</td>
</tr>
<tr>
<td>Changeless</td>
<td>400</td>
</tr>
<tr>
<td>Soulless</td>
<td>384</td>
</tr>
<tr>
<td>The Kingdom of Gods</td>
<td>592</td>
</tr>
<tr>
<td>The Broken Kingdoms</td>
<td>416</td>
</tr>
<tr>
<td>Memory</td>
<td>399</td>
</tr>
<tr>
<td>The Hundred Thousand Kingdoms</td>
<td>432</td>
</tr>
<tr>
<td>The Way of Kings</td>
<td>1008</td>
</tr>
<tr>
<td>Farthing</td>
<td>320</td>
</tr>
<tr>
<td>Assassin's Apprentice</td>
<td>435</td>
</tr>
<tr>
<td>Mirror Dance</td>
<td>465</td>
</tr>
<tr>
<td>Brothers in Arms</td>
<td>272</td>
</tr>
<tr>
<td>Cetaganda</td>
<td>245</td>
</tr>
<tr>
<td>Furies of Calderon</td>
<td>672</td>
</tr>
<tr>
<td>The Last Colony</td>
<td>336</td>
</tr>
<tr>
<td>The Ghost Brigades</td>
<td>384</td>
</tr>
<tr>
<td>The Alloy of Law</td>
<td>416</td>
</tr>
<tr>
<td>The Hero of Ages</td>
<td>760</td>
</tr>
<tr>
<td>The Well of Ascension</td>
<td>796</td>
</tr>
<tr>
<td>Mistborn: The Final Empire</td>
<td>672</td>
</tr>
<tr>
<td>Redshirts</td>
<td>320</td>
</tr>
<tr>
<td>His Majesty's Dragon</td>
<td>384</td>
</tr>
<tr>
<td>The Vor Game</td>
<td>284</td>
</tr>
<tr>
<td>Red Seas Under Red Skies</td>
<td>786</td>
</tr>
<tr>
<td>The Lies of Locke Lamora</td>
<td>752</td>
</tr>
<tr>
<td>The Warrior's Apprentice</td>
<td>292</td>
</tr>
<tr>
<td>The Rook</td>
<td>504</td>
</tr>
<tr>
<td>Throne of Jade</td>
<td>432</td>
</tr>
</tbody></table>
<ul>
<li>Total Pages: <strong>17615</strong></li>
<li>Average Pages per Day: <strong>48</strong></li>
</ul>
Best Albums of the Year: 2012/2012/12/28/best-albums-of-the-year-2012.html2012-12-28T00:00:00ZT00:00:00-08:002012-12-28T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I think I'm getting old. Last year I only had 7 albums I like, this year is even worse. I listened to a lot of Leonard Cohen and Hall & Oates this year :-p</p>
<p><strong>Honorable Mentions:</strong> Japandroids, Regina Spektor, Between the Buried and Me, Dethklok, Killer...</p><p>I think I'm getting old. Last year I only had 7 albums I like, this year is even worse. I listened to a lot of Leonard Cohen and Hall & Oates this year :-p</p>
<p><strong>Honorable Mentions:</strong> Japandroids, Regina Spektor, Between the Buried and Me, Dethklok, Killer Mike.</p>
<p><strong>Disappointments:</strong> Say Anything, Tenacious D, mewithoutYou, The Mars Volta.</p>
<p><strong>Sad Truth:</strong> My favorite song this year was actually Call Me Maybe. That is not a joke.</p>
<h2 id="top-5">Top 5:</h2>
<ul class="albums">
<li>
<div class='cover'>
<img src='/albums/2012/5.jpg' /><div></div>
</div>
<div class='content'>
<h6>P.O.S.</h6>
<h4>We Don't Even Live Here</h4>
<p>Probably my favorite rapper exchanges the punk-y guitars on his last album for darker sounds and dancier beats. Future classic.</p>
</div>
<div class='player'>
<h6>#5</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2012/4.jpg' /><div></div>
</div>
<div class='content'>
<h6>Ronald Jenkees</h6>
<h4>Days Away</h4>
<p><a href="http://www.youtube.com/watch?v=P0YiWsAM0O8&feature=share&list=UUvKLrpen70sLbTe8sg5TWtQ">YouTube star</a> and heir to Ratatat's throne.</p>
</div>
<div class='player'>
<h6>#4</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2012/3.jpg' /><div></div>
</div>
<div class='content'>
<h6>Fang Island</h6>
<h4>Major</h4>
<p>Fang Island lost a guitar, calmed down a bit, but managed to put out a really fun and cohesive album.</p>
</div>
<div class='player'>
<h6>#3</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2012/2.jpg' /><div></div>
</div>
<div class='content'>
<h6>Coheed and Cambria</h6>
<h4>The Afterman: Ascension</h4>
<p>I was kind of sad Coheed ended their 5-part space opera with the wimper that was Year of the Black Rainbow. Thankfully, they've decided not to call it quits and have come back with a double-album, Ascension being the first part. Other than "Key Entity Extraction I: Domino the Destitute", I wasn't immediately blown away, but I've been coming back to the album over and over; loving it more with each listen.</p>
</div>
<div class='player'>
<h6>#2</h6>
</div>
</li>
<li class="last">
<div class='cover'>
<img src='/albums/2012/1.jpg' /><div></div>
</div>
<div class='content'>
<h6>Fun.</h6>
<h4>Some Nights</h4>
<p>I saw This Past Year in a basement in Mesa, AZ something like 12 years ago. Can't believe it took the world so long to discover Nate Ruess, but I'm happy for those guys that they finally blew up.</p>
<p>Some Nights is basically Dog Problems with a bigger budget and even more self-confidence. It's huge, eclectic and reminds me a lot of Queen in the best possible ways.</p>
</div>
<div class='player'>
<h6>#1</h6>
</div>
</li>
</ul>
Sparkle Motion: A Thousand Points of Light/2012/12/17/thousand-points-of-light.html2012-12-17T00:00:00ZT00:00:00-08:002012-12-17T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>This year, we (<a href="http://weareinstrument.com">Instrument</a>) had the opportunity to work on <a href="http://www.google.com/zeitgeist/2012/">Google's Zeitgeist site</a>. Every year, Google collects the most popular and fastest rising search results and shares them with the world. The site features the results of "The World" & 55 different...</p><p>This year, we (<a href="http://weareinstrument.com">Instrument</a>) had the opportunity to work on <a href="http://www.google.com/zeitgeist/2012/">Google's Zeitgeist site</a>. Every year, Google collects the most popular and fastest rising search results and shares them with the world. The site features the results of "The World" & 55 different countries in a multitude of different languages (including several Right-to-Left languages) and is responsive across all browser sizes. Kudos to my teammates <a href="http://twitter.com/stefhatcher">@stefhatcher</a> and <a href="http://twitter.com/waytoocrowded">@waytoocrowded</a> on managing this extraordinary task.</p>
<p>For my part, I worked on building the <a href="http://www.google.com/zeitgeist/2012/#explore">3D Map Explore</a> feature. I'll write more about what that involved later, but for now I want to discuss the static "twinkling lights" state that you'll see on the homepage.</p>
<p><img src="/projects/twinkle/twinkle.png" alt="Twinkle" /></p>
<p>Basically, there is a map with "lights" which pulse around the world. Here's the <a href="/projects/twinkle/twinkles.js">code I used for this</a>, <a href="/projects/twinkle/">along with a demo</a>. But I want to talk about a higher-level question. <strong>How do you draw points which fill in a map?</strong></p>
<h2 id="option-1-plot-data-points">Option 1: Plot Data Points</h2>
<p>The first option is to find a dataset which will cover and fill the land portions of the map. There are several good sources of data for plotting where people live.</p>
<p>You could plot the lat/long of every city. You could use a population density map.</p>
<p>Basically you just need a bunch of coordinates and then you draw them. I found cool list of <a href="https://gist.github.com/4278655">airports and converted it to JSON</a>.</p>
<p>Once you have your coordinates, you'll need to convert them from lat/long to x/y. This is an easy function:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function getXY(lat, lon) {
var x = (lon * MAP_WIDTH) / 360;
var y = (lat * MAP_HEIGHT) / 180;
return { x: x, y: y };
}
</code></pre></div>
<h2 id="option-2-read-an-image">Option 2: Read an Image</h2>
<p>Sometimes, however, you'll need to cheat. When real data doesn't look quite right, just let a designer draw it and use that information in your visualization. This is the approach we actually used on the site.</p>
<p>The designer makes <a href="/projects/twinkle/pixel-map.png">a map file</a> and we read the coordinates in via canvas:</p>
<div class="highlight"><pre class="highlight plaintext"><code>// Canvas to read pixels from.
var pixelmapLayer = document.createElement('canvas');
// Loadable map.
var myMapImg = new Image();
// Onload
myMapImg.onload = function() {
// Make the canvas and image the same size
pixelmapLayer.width = myMapImg.width;
pixelmapLayer.height = myMapImg.height;
// Draw the image on the canvas.
var pixelmapCtx = pixelmapLayer.getContext('2d');
pixelmapCtx.drawImage(myMapImg, 0, 0);
// Read image data array from canvas
var pmapImageData = pixelmapCtx.getImageData(0, 0,
pixelmapLayer.width,
pixelmapLayer.height);
// Loop over RGBA values 4 at a time
var len = pmapImageData.data.length;
var mapDots = [];
for (var i = 0; i < len; i += 4) {
var r = pmapImageData.data[i],
g = pmapImageData.data[i + 1],
b = pmapImageData.data[i + 2],
a = pmapImageData.data[i + 3];
// If pixel is black and opaque, use it
if ((r === 0) && (g === 0) && (b === 0) && (a >= 255)) {
var pixel = Math.ceil(i / 4);
// Map linear pixel number to 2d x/y
var x = pixel % pixelmapLayer.width;
var y = Math.floor(pixel / pixelmapLayer.width);
mapDots.push({
x: x,
y: y
});
}
}
};
myMapImg.src = 'pixel-map.png';
</code></pre></div>
<p>Now the designer can "paint" denser points in certain areas if he wants. For example, this effect could be behind text and the design may want to avoid twinkling lights there for readability.</p>
<h2 id="demo-source">Demo & Source</h2>
<ul>
<li><a href="/projects/twinkle/">Here's a demo with some fun variables to tweak</a>.</li>
<li><a href="/projects/twinkle/twinkles.js">Here's the source code</a></li>
</ul>
Window Location in UIWebView/2012/10/15/uiwebview-location.html2012-10-15T00:00:00ZT00:00:00-08:002012-10-15T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Which question. How do you get the current URL of a page in a <code>UIWebView</code> context (link followed from Twitter, Facebook, Gmail.app, etc)? If you said, <code>window.location.href</code>, <strong>you'd be wrong</strong>.</p>
<p>In the final hours of testing before a new site launch, users...</p><p>Which question. How do you get the current URL of a page in a <code>UIWebView</code> context (link followed from Twitter, Facebook, Gmail.app, etc)? If you said, <code>window.location.href</code>, <strong>you'd be wrong</strong>.</p>
<p>In the final hours of testing before a new site launch, users with access to the soft launch reported that none of our links worked if they opened the link we sent them in the Gmail iOS app.</p>
<p>We're using <code>#!</code> URLs throughout the single-page site so we can deep-link and support browsers all the way back to oldIE. When you link a link in the app, the URL changes and notifies our code to navigate to a new "page". Our router, the code that maps URL changes to pieces of our code, correctly recieves the <code>onhashchange</code> when someone clicks a link, but when the router goes to lookup the URL, using <code>window.location.href</code>, it gets back: <code>undefined</code>. Uh oh. In fact, all properties on <code>window.location</code> are undefined, including <code>hash</code>, <code>hostname</code>, etc.</p>
<p>For some reason, despite the fact that <code>window.location.href</code> is <strong>writable</strong> and setting it will change the URL as expected, reading it is impossible with a <code>UIWebView</code>.</p>
<h3 id="the-workaround">The Workaround</h3>
<p>I basically looked at every property on <code>window</code> and <code>document</code> to find something URL-y. What I ended up with was: <code>document.URL</code>. I've never heard of it, but <a href="https://developer.mozilla.org/en-US/docs/DOM/document.URL">apparently it's been around forever and is read-only</a>.</p>
<p>Our router code now looks like:</p>
<div class="highlight"><pre class="highlight plaintext"><code>router.recognize(window.location.href || document.URL);
</code></pre></div>
<p>And everythings working great. Crisis averted.</p>
<h3 id="the-offenders">The Offenders</h3>
<p>After a brief look around libraries I've used, I don't see that any of them are aware of, or work around, this problem (unless I'm completely mistaken). Google Closure Library, Ember.js and Sammy all hardcode <code>window.location.href</code> as the canonical source of the current URL. I'll be submitting bugs and pull requests as soon as I make sure I'm not crazy.</p>
<p>It should also be noted that many routers actually prefer HTML5 History/pushState in browsers which support it, only falling back to <code>!#</code> for older browsers. In this case, <code>UIWebView</code> works fine, so my guess is not many people opt-in to an older technology and then expect it to work in an alien environment like a sandboxed mobile browser.</p>
<h3 id="the-debugger">The Debugger</h3>
<p>Another wrinkle, is that <code>UIWebViews</code> aren't remotely debuggable by default. They swallow errors. You can enable remote debugging, in Obj-C, but that doesn't help if you don't control the app (Facebook, Gmail, etc).</p>
<p>To work around this, I used PhoneGap to create my own application which enables remote debugging by default. Now Safari 6 can plug into it and I can inspect values and see exceptions.</p>
How Do I: Structure Applications/2012/10/09/how-do-i-structure.html2012-10-09T00:00:00ZT00:00:00-08:002012-10-09T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>This is part two in a series of "How Do I" articles (<a href="/2012/10/01/how-do-i-animate.html">part one, Animation, is here</a>). These are how I, Thomas Reynolds, accompish certain tasks. This isn't about comparing multiple technique or even justifying my prefered approach. This is a brain dump...</p><p>This is part two in a series of "How Do I" articles (<a href="/2012/10/01/how-do-i-animate.html">part one, Animation, is here</a>). These are how I, Thomas Reynolds, accompish certain tasks. This isn't about comparing multiple technique or even justifying my prefered approach. This is a brain dump.</p>
<h3 id="structure-philosophy">Structure Philosophy</h3>
<p>These days, I think the difference between a "Site" and an "Application" is very small. Sites may start small, be less interactive and have less state than Applications, so they don't necessarily need tools and libraries to handle those advanced issues. But it certainly doesn't hurt.</p>
<p>Site or Application, I try to start with the same tools and structure.</p>
<h3 id="build-system-dependency-management">Build System & Dependency Management</h3>
<p>These two systems are often bundled together. I use <a href="http://middlemanapp.com">Middleman</a>, which is perfect for my needs because I wrote it. For the Ruby-adverse, or Javascript-masochists, <a href="http://yeoman.io">Yeoman</a> is gaining traction.</p>
<p>Modern applications include many libraries and, of course, developers should be modularizing their code into many, independent files as well. You <em>could</em> simply include a bunch of <code>script</code> tags in your HTML and make sure they stay in the right order, but that's immature and doesn't scale. Instead, the modules need to define what their dependencies are and let some other system make sure they load in the correct order.</p>
<p>Middleman includes <a href="https://github.com/sstephenson/sprockets">Sprockets</a> and <a href="https://github.com/livingsocial/rake-pipeline">Rake-Pipeline</a>. I flip flop on which one I use and I'm not really happy with either of them. That said, they do their job and get out of the way.</p>
<p>The Build step is very important. It takes your code, libraries and file layout—which are optimized for your development process and speed—and converts them into fewer, smaller files optimized for bandwidth and load time.</p>
<p>Middleman makes this step simple. In my config, I add:</p>
<div class="highlight"><pre class="highlight plaintext"><code>configure :build do
activate :minify_css
activate :minify_js
end
</code></pre></div>
<p>And we're done. In more complicated projects, this step can also compress images, generate pre-gzipped assets and automatically run tests.</p>
<p>Regarding Javascript compilation and minification, Middleman defaults to <a href="https://github.com/mishoo/UglifyJS">UglifyJS</a>, which is pretty much the standard for open source Javascript libraries (such as jQuery, HTML5Boilerplate, etc). I still prefer <a href="https://developers.google.com/closure/compiler/">Google's Closure Compiler</a>, which has long been the best for file size, at the cost of developer happiness and the annoyances of working with a large Java tool. However, these days, Javascript file size is dwarfed my image assets so that's less important and UglifyJS is rapidly approaching Closure's efficiency.</p>
<h3 id="core-libraries">Core Libraries</h3>
<ul>
<li>DOM Wrapper (<a href="https://developers.google.com/closure/library/">Closure</a> or jQuery)</li>
<li>Browser Feature Detection (<a href="http://modernizr.com">Modernizr</a>)</li>
<li>Animation Framework (<a href="https://github.com/sole/tween.js/">tween.js</a>) </li>
<li>CSS Transform 2d/3d Support (<a href="https://github.com/sproutcore/TransformJS">TransformJS</a>)</li>
<li>Statechart (<a href="https://github.com/etgryphon/stativus">Stativus</a> or <a href="http://emberjs.com">Ember.js</a>)</li>
<li>View Layer (Ember.js or something custom)</li>
<li>URL Router (Ember.js or <a href="https://github.com/joshbuddy/sherpa">Sherpa</a>)</li>
<li>Templating Library (<a href="https://developers.google.com/closure/templates/">Soy</a> or <a href="http://handlebarsjs.com">Handlebars</a>)</li>
<li>Asset Loader (<a href="http://thinkpixellab.com/pxloader/">PxLoader</a>)</li>
</ul>
<h4 id="dom-wrapper">DOM Wrapper</h4>
<p>Paves over cross-browser issues with the most basic interactions with the browser. A no-brainer. I use Closure or jQuery, depending on what the client wants, but I prefer jQuery. That said, I don't use jQuery for animation or code structure (<code>$.fn.plugins</code>).</p>
<h4 id="browser-feature-detection">Browser Feature Detection</h4>
<p><a href="http://modernizr.com">Modernizr</a> detects available features and makes it easy to fallback to lesser technologies through either a Javascript or CSS interface. It also provides an HTML5 shim for older browsers. Here's a quick example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>// JS
if (Modernizr.touch) { $(elem).on('touchstart', handler); }
</code></pre></div>
<p>Or</p>
<div class="highlight"><pre class="highlight plaintext"><code>/* CSS */
.svg { background-image: url(bg.svg); }
.no-svg { background-image: url(bg.png); }
</code></pre></div>
<p>Another no-brainer, this should be on every site on the web.</p>
<h4 id="animation-framework">Animation Framework</h4>
<p>As <a href="/2012/10/01/how-do-i-animate.html">I said before</a>, I use a Tween library to get the animation effects I want. jQuery doesn't use <code>requestAnimationFrame</code>, so I have to use something third-party. <a href="https://github.com/sole/tween.js/">tween.js</a> is great. See the previous article for examples.</p>
<h4 id="css-transform-2d-3d-support">CSS Transform 2d/3d Support</h4>
<p>If you want to animate rotation and scale, you're going to need CSS Transforms. Using these transforms also has the side-effect of moving their rendering to the GPU, so replacing animations of position <code>top</code> and <code>left</code> can be faster if transforming <code>translateY</code> and <code>translateX</code> are used instead. <a href="https://github.com/sproutcore/TransformJS">TransformJS</a> is a polyfill that uses the best available technique. 3d transforms for those which support it, falling back to 2d transforms and finally top/left positioning. The API looks like:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$(elem).css({ transformX: 100, scale: 2 });
</code></pre></div>
<h4 id="statechart">Statechart</h4>
<p>I love Statecharts. Every single project should have them. They simplify events and messaging, give you a central place for "controller" code and never leave you between states. They also pair wonderfully with a Router (see below). Ember.js has a fantastic implementation, if that's not available, the <a href="https://github.com/etgryphon/stativus">Stativus</a> project is basically the same code abstracted to be library agnostic.</p>
<p>One of these days, I'm going to be able to write about Statecharts well. Until then, <a href="http://www.itsgotwhatplantscrave.com/2009/02/22/building-sproutcore-apps-with-statecharts-part-2/">try this article</a>.</p>
<h4 id="view-layer">View Layer</h4>
<p>Like the Statechart, the View Layer is all about centralizing code related. A view handles what content should be in a HTML area, how to show it, how to hide it and how to handle events in that area. Without a View Layer, you'll end up with jQuery-itis, spaghetti code which all different parts of your codebase are updating the same DOM elements. This provides a nice simple API to your controllers and Statecharts:</p>
<div class="highlight"><pre class="highlight plaintext"><code>tooltipView.refresh();
tooltipView.show();
$(document).one('click', function() { tooltipView.hide(); });
</code></pre></div>
<p>Ember.js has my favorite implementation due to its ability to bind and auto-update elements. Backbone has a less magical, but still very-solid version.</p>
<h4 id="url-router">URL Router</h4>
<p>Applications should be deep-linkable when possible and since many Sites are becoming "single page" site which load other pages dynamically, they both need some mechanism for responding to URL changes on the client-side. Ember.js comes with a great router, if that's not available, I use <a href="https://github.com/joshbuddy/sherpa">Sherpa</a> which works in both the browser and on NodeJS. It's got a nice API:</p>
<div class="highlight"><pre class="highlight plaintext"><code>var sherpa = new Sherpa.Router();
sherpa.add('/test/:variable').to('testing');
sherpa.recognize('/test/hello'); /*=> {
"destination": "testing",
"params": {
"variable": "hello"
}
}*/
</code></pre></div>
<h4 id="templating-library">Templating Library</h4>
<p>String concatination is not okay. It's ugly, hard to update, littered with double quotes, single quotes, escape characters, whitespace and plus signs. <a href="http://handlebarsjs.com">Handlebars</a> is a wonderfully powerful implementation of Mustache templates. Nice clean HTML:</p>
<div class="highlight"><pre class="highlight plaintext"><code><div class="entry">
<h1>{{title}}</h1>
<div class="body">
{{body}}
</div>
</div>
</code></pre></div>
<p>If the project relies on Google Closure, then their Soy templates are the only option.</p>
<h4 id="asset-loader">Asset Loader</h4>
<p>You <em>could</em> just include normal <code>img</code> tags and CSS <code>background-images</code>, especially if the site was very traditional. But with an Application that has user data or many sections, it is probably a better idea to only load what you need. Multipage Sites would also benefit from waiting to load images on subsequent pages until the visitor actually requests them. Having a place to centralize all this loading (and queueing and prioritizing) is really useful. I use <a href="http://thinkpixellab.com/pxloader/">PxLoader</a>, which came out of the HTML5 version of Cut the Rope. I still use <code>img</code> tags and CSS for items which are always visible, but the Asset Loader can provide niceties like loading percentage bars and a central place for optimization.</p>
<h3 id="conclusion">Conclusion</h3>
<p>You might be saying, "that's quite a bit of stuff!" The nice thing about having a consistent stack is that it can be refined and improved from project to project. You don't have to be constantly writing some half-broken, untested implementation of a single piece of the stack. Just suck it up and let your dependency management and compiler deal with optimizing out the pieces you aren't using. We've got 500kb Retina images on these sites, don't let worrying about 5kb of Javascript make your development more difficult than it needs to be.</p>
Facebook the Devourer/2012/10/04/facebook-the-devourer.html2012-10-04T00:00:00ZT00:00:00-08:002012-10-04T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I can't find a way to write this article without it sounding like a rant, so why fight it? <strong>The views and opinions expressed are my own and do not necessarily represent the views of my employer.</strong></p>
<p>Facebook is a social network with 1 billion users. It...</p><p>I can't find a way to write this article without it sounding like a rant, so why fight it? <strong>The views and opinions expressed are my own and do not necessarily represent the views of my employer.</strong></p>
<p>Facebook is a social network with 1 billion users. It devours everything it touches and produces nothing of value, including—ironically—their stock price.</p>
<p>I'm not going to argue that people are wasting time playing FarmVille, but I am going to argue that for such a massive collection of users, the output isn't very impressive. <a href="http://www.huffingtonpost.com/2012/10/04/facebooks-new-ad-things-that-connect-us-chairs-universe_n_1939862.html">Look at this idiotic commercial</a>. They really want to project the idea that they're somehow making a difference in exchange for harvesting our personal life for advertisers.</p>
<h3 id="devouring-the-internet">Devouring The Internet</h3>
<p>Facebook's famous for their walled garden. A walled garden filled with ads. To keep people on their pages, staring at those ads, they've tried to take the Internet and move it inside Facebook.</p>
<p>They tried to move instant messaging inside Facebook. Calendaring. Photos. Booty calls. We had Google Calendar, Instagram, Flickr and SMS, they didn't do anyone a great service by ripping them off and locking them and the content inside Facebook.</p>
<p>Why are people sharing links to The Washington Post, a fucking print newspaper, that require installing a Facebook app to read! Because Facebook wants to eat that content, and Instagram posts, and all your check-in data, and your music playlists and pretend like everything's inside the garden so why would you go outside.</p>
<p>In Africa, they're going further to <a href="http://qz.com/5180/facebooks-plan-to-find-its-next-billion-users-convince-them-the-internet-and-facebook-are-the-same/">actively conflate Facebook with The Internet</a>.</p>
<h3 id="devouring-culture">Devouring Culture</h3>
<p>As Christopher Poole mentioned at XOXO, we should take a look at the creative output of different communities. 4chan is a meme machine, constantly grinding to establish the culture of the internet. Youtube has launched not only memes, but entire careers. Reddit is quickly becoming the go-to place for creators and politicians to reach out to the Internet community with their AMAs. Folks are writing books in real-time on Google Docs. Twitter help people organize revolutions.</p>
<p>What memes, musicians or debates have come out of Facebook? Even Myspace had it's success stories. Rather, Facebook is happy to take people's boredom and opinions and funnel it inward into endless comment threads. Do they care that nothing useful is coming from this? Not as long as everyone's refreshing new ads.</p>
<h3 id="devouring-people">Devouring People</h3>
<p>I said I wasn't going to complain about the wasted time on Facebook, but I will complain about the wasted talent on Facebook. The best and brightest have been lured into the beast with giant paychecks, childish perks and the idea that somehow a new blue square button on Facebook is the best possible way they can change the world.</p>
<h3 id="remember-facebook">Remember Facebook?</h3>
<p>There are websites that have become core pieces of the Internet, without which we would be left with a giant hole. Imagine an Internet without Google, Amazon or Wikipedia. Sure, they could be replaced in time, but the absence would be felt.</p>
<p>If Facebook disappeared tomorrow, nobody would give a shit. They would move on, like they moved on from Myspace. They would find another instant messaging app. They would find a different calendar. They'd use email. And they'd do it overnight because they're simply a pile of communication technologies for which we have plenty of replacements already. There's nothing special about Facebook to miss and for a giant, wealthy company with a billion users… that's pretty sad.</p>
How Do I: Animate/2012/10/01/how-do-i-animate.html2012-10-01T00:00:00ZT00:00:00-08:002012-10-01T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>This is the first piece in a series of "How Do I" articles. Since that phrase can be taken multiple ways, let me explain: this is how I, Thomas Reynolds, accompish certain tasks. This isn't about comparing multiple technique or even justifying my prefered...</p><p>This is the first piece in a series of "How Do I" articles. Since that phrase can be taken multiple ways, let me explain: this is how I, Thomas Reynolds, accompish certain tasks. This isn't about comparing multiple technique or even justifying my prefered approach. This is a brain dump.</p>
<h3 id="animation-philosophy">Animation Philosophy</h3>
<p>When animating, either massive thousand-part experiences or single on-off effects, I prioritize framerate and the ability get the right "feel" from the animation. Both goals are about Control, so I do nearly all of my animations in Javascript instead of CSS.</p>
<p>Javascript allows me to control all of my animations from a single place, a Tween engine, and run them from a single place, <code>requestAnimationFrame</code>. Using a Tween engine, instead of CSS, allows me to define very specific timing functions which influence the "feel" of the animation. Does is bounce? Move as if gravity is pulling it down? These are important. Simply defaulting to jQuery's "swing" or CSS's "ease-in-out" aren't good enough.</p>
<p>You can look at the recent <a href="/2012/09/23/fuelstream.html">Nike+ Fuelstream</a> project for an example of a site using tons of Javascript animations.</p>
<h3 id="tween-js">tween.js</h3>
<p>My preferred Tweening engine is <a href="https://github.com/sole/tween.js/">tween.js</a>, but pretty much any of them will do. jQuery's built-in, generic, <code>$.animate</code> function is worth a look too.</p>
<p>Using tween.js, you can construct animations like so:</p>
<div class="highlight"><pre class="highlight plaintext"><code>var elem = document.getElementById('box');
var tween = new TWEEN.Tween({ height: 100 })
.to({ height: 200 }, 1000)
.easing(TWEEN.Easing.Elastic.InOut)
.onUpdate(function() {
elem.style.height = this.height + 'px';
}).start();
</code></pre></div>
<p>You may notice, I'm using <code>TWEEN.Easing.Elastic.InOut</code>. Its timing curve looks like:</p>
<p><img src="/images/elastic.png" alt="Elastic.InOut" /></p>
<p>You can see that it travels below and above the lines, representing 0 and 1. For a long time, this kind of timing was impossible with CSS transitions. That's changed, but some of the more mathmatically complicated easing methods still have to be done in Javascript. <a href="http://sole.github.com/tween.js/examples/03_graphs.html">Here are the timing curves for all of tween.js' built-in functions</a>.</p>
<h3 id="requestanimationframe">requestAnimationFrame</h3>
<p>Of course, if you actually ran this code, nothing would happen. That's because tween.js needs to be told "what time is it" to know which point in the animation we are at. For that, I use <code>requestAnimationFrame</code>.</p>
<p><code>requestAnimationFrame</code> is a browser feature which will run our code at 60 frames per second. As a nice fallback, if it detects that the browser is too slow to run our animation at 60fps, it will automatically fallback to 30fps. Using a <code>requestAnimationFrame</code> loop syncs our animations so they all paint at once and at the same frequency as our displays. Simply put, this is the best possible way to run animations if you prioritize framerate.</p>
<p>We can run the above Tween with <code>requestAnimationFrame</code> like so:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function animate(timestamp) {
if (!timestamp) {
timestamp = +(new Date());
}
// Update/draw all Tweens
TWEEN.update(timestamp);
// Next frame
requestAnimationFrame(animate);
}
// Start rAF
requestAnimationFrame(animate);
</code></pre></div>
<p>One caveat, with a loop like this, <code>requestAnimationFrame</code> will always be running and eating up CPU cycles and battery. It's a better practice to only be using it when you actually need to animate something.</p>
<h3 id="one-off-animations">One-off Animations</h3>
<p>Unless you're doing large, sequenced animations, you probably just want a quick one-off tween. This is how most people using jQuery's <code>animate</code>. I've written a simple function which abstracts the Tween engine, sets up the tween and runs <code>requestAnimationFrame</code> for the duration of the animation, then exits.</p>
<div class="highlight"><pre class="highlight plaintext"><code>function oneOffAnimation(from, to, duration,
easing, onUpdate,
onComplete) {
var t = new TWEEN.Tween(from)
.to(to, duration)
.easing(easing)
.onUpdate(onUpdate)
.onComplete(function _onComplete() {
t.done = true;
});
var self = this;
function tick(ts) {
if (!ts) {
ts = +(new Date());
}
t.update(ts);
if (t.done) {
onComplete();
} else {
requestAnimationFrame(tick);
}
}
t.start();
requestAnimationFrame(tick);
return t;
};
</code></pre></div>
<p>Which would make the above tween look like:</p>
<div class="highlight"><pre class="highlight plaintext"><code>var elem = document.getElementById('box');
oneOffAnimation(
{ height: 100 },
{ height: 200 },
1000,
TWEEN.Easing.Elastic.InOut,
function _onUpdate() {
elem.style.height = this.height + 'px';
},
function _onComplete() {
// All done!
}
);
</code></pre></div>
<h3 id="css-animations">CSS Animations</h3>
<p>The only place I would use CSS transitions are for simple, reversable hover effects. Changing the color of links or adding hover states to "clickable" elements. However, given the move to touch-based devices, I'd still do many interaction animations in Javascript which allows touch and gesture detection code to respond with the correct animation. It seems Android and iOS treat <code>:hover</code> differently. iOS makes you touch once to activate <code>:hover</code> then touch again to activate <code>click</code>. Android seems to request holding down to activate <code>:hover</code> and a single touch causes <code>click</code>. Doing this kind of work in Javascript also keeps things consistent.</p>
<h3 id="past-problems-future-bug-fixes">Past Problems, Future Bug Fixes</h3>
<ul>
<li><p>In the past, I've seen speed conflicts between CSS animations and <code>requestAnimationFrame</code>. For some reason, using both at the same time (I was animating a game and using CSS Animations for UI), caused massive loss of framerate. I'm sure this will be, or alread is, resolved.</p></li>
<li><p><code>requestAnimationFrame</code> is relatively new, oldIE and older versions of Safari don't support it. Using the <a href="http://paulirish.com/2011/requestanimationframe-for-smart-animating/">standard requestAnimationFrame polyfill</a> will fallback to <code>setInterval</code> for scheduling frames. This isn't great for consistent timing. Additionally, older browsers are also likely to have slower Javascript engines so the resulting effect is even further degraded.</p></li>
<li><p>When you run a bunch of Tweens at 60fps, there is a very strong possibility of creating either memory leaks or <a href="https://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript">Garbage Collector slowdowns</a>. Be careful. Brush up on your understanding of Javascript memory management. Use a battle-hardened Tween engine.</p></li>
</ul>
Beware of CoffeeScript Comprehensions/2012/05/08/beware-coffeescript-comprehensions.html2012-05-08T00:00:00ZT00:00:00-08:002012-05-08T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I've recently spent some time addressing bugs and speed issues with the first large CoffeeScript project (nearly 10,000 lines of code) I've worked on with multiple developers.</p>
<p>For the most part, the process was painless. CoffeeScript hides a great...</p><p>I've recently spent some time addressing bugs and speed issues with the first large CoffeeScript project (nearly 10,000 lines of code) I've worked on with multiple developers.</p>
<p>For the most part, the process was painless. CoffeeScript hides a great deal of complexity beneath it's glossy syntax, which is great for writing simple and readable code. But there is always tension between high-level languages and raw performance. If you're an experienced Javascript developer, the compiled output of a snippet of CoffeeScript code should be recognizable, readable and pretty much what you'd write if you wrote Javascript directly.</p>
<p>Here's an example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>list = [1..3]
console.log(i) for i in list
</code></pre></div>
<p>Becomes:</p>
<div class="highlight"><pre class="highlight plaintext"><code>var i, list, _i, _len;
list = [1, 2, 3];
for (_i = 0, _len = list.length; _i < _len; _i++) {
i = list[_i];
console.log(i);
}
</code></pre></div>
<p>Great, a simple for loop which avoids recalculating <code>list.length</code> on every iteration. However, CoffeeScript also overloads the <code>for</code> loop with the ability to do <a href="http://coffeescript.org/#loops">Comprehensions</a>. Comprehensions allow you to manipulate the items being iterated over, provide a native way of running <code>map</code>, <code>filter</code>, <code>reject</code> and other manipulative functions on a collection. <strong>Whether a <code>for</code> loop acts as a comprehension is dependent on context.</strong></p>
<p>Here are some examples:</p>
<h2 id="assigning-a-for-loop-to-a-variable">Assigning a <code>for</code> loop to a variable:</h2>
<div class="highlight"><pre class="highlight plaintext"><code>list = [1..3]
output = for i in list
console.log(i)
</code></pre></div>
<p>Becomes:</p>
<div class="highlight"><pre class="highlight plaintext"><code>var i, list, output;
list = [1, 2, 3];
output = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = list.length; _i < _len; _i++) {
i = list[_i];
_results.push(console.log(i));
}
return _results;
})();
</code></pre></div>
<p>Notice that we now create an empty array to hold the result of the comprehension, then the last line of the <code>for</code> loop is used as the value which is pushed into that array. Additionally, there is a wrapping anonymous function which immediately executes to keep some of the loop variables from leaking out of their scope.</p>
<p>This result can also be triggered as a one-liner wrapped in parenthesis:</p>
<div class="highlight"><pre class="highlight plaintext"><code>list = [1..3]
output = (console.log(i) for i in list)
</code></pre></div>
<p>For the most part, this makes sense. You are requesting an output variable, so one is created, even if the results aren't meaningful (just the return value of <code>console.log</code>). I would like to point out that this code will create 1 anonymous function every single time it is executed. If this loop were used frequently enough, such as inside a <code>setInterval</code> or <code>requestAnimationFrame</code> loop, it could begin producing and throwing away up to 60 anonymous functions per second, per usage. Eventually, <a href="http://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript">the Javascript Garbage Collector will cleanup these unused functions, causing the framerate to stutter</a>.</p>
<p>If you want to avoid this, you can write the <code>push</code> portion of your array building manually:</p>
<div class="highlight"><pre class="highlight plaintext"><code>list = [1..3]
output = []
output.push(i+1) for i in list
</code></pre></div>
<p>Becomes:</p>
<div class="highlight"><pre class="highlight plaintext"><code>var i, list, output, _i, _len;
list = [1, 2, 3];
output = [];
for (_i = 0, _len = list.length; _i < _len; _i++) {
i = list[_i];
output.push(i + 1);
}
</code></pre></div>
<h2 id="implicitly-returning-comprehensions">Implicitly Returning Comprehensions</h2>
<p>Here's where you need to pay close attention. <strong>If you have a <code>for</code> loop as the last piece of code in a function, it will be used as the return value and generate a resulting array, even when not explicitly requests.</strong></p>
<p>For example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>printI = ->
list = [1..3]
console.log(i) for i in list
</code></pre></div>
<p>Becomes:</p>
<div class="highlight"><pre class="highlight plaintext"><code>var printI;
printI = function() {
var i, list, _i, _len, _results;
list = [1, 2, 3];
_results = [];
for (_i = 0, _len = list.length; _i < _len; _i++) {
i = list[_i];
_results.push(console.log(i));
}
return _results;
};
</code></pre></div>
<p>In our codebase, this happened very often. The above code is simply for debugging, there is no need to create, build and return an array every single time it is called. Our code had a render tree, on every frame, we would render the root object, then use a <code>for</code> loop to render each of that object's children. <strong>Which means we were building and discarding these implicit comprehension arrays once for every single drawn component in our system every single frame.</strong> It adds up.</p>
<h2 id="solution">Solution</h2>
<p>My suggestion is to document all method return values and set them explicitly when writing CoffeeScript. Here is how the above methods <strong>should</strong> look:</p>
<div class="highlight"><pre class="highlight plaintext"><code># Log each item in the array
#
# list - An array of integers to be logged
#
# Returns undefined.
printI = (list) ->
console.log(i) for i in list
undefined
printI([1..3])
</code></pre></div>
<p>Which becomes a simple loop with no return value:</p>
<div class="highlight"><pre class="highlight plaintext"><code>var printI;
printI = function(list) {
var i, _i, _len;
for (_i = 0, _len = list.length; _i < _len; _i++) {
i = list[_i];
console.log(i);
}
return;
};
printI([1, 2, 3]);
</code></pre></div>
<h3 id="check-your-own-code">Check Your Own Code</h3>
<p>Try searching through your output Javascript for <code>return _results</code>, that will reveal if your code might be accidentally returning unnecessary comprehensions.</p>
Middleman 3.0 Beta 2/2012/04/23/middleman-3-beta-2.html2012-04-23T00:00:00ZT00:00:00-08:002012-04-23T00:00:00ZT00:00:00-08:00Thomas Reynolds<h3 id="what-is-middleman">What is Middleman?</h3>
<p>Middleman is a small tool for developing stand-alone, static websites. It's great for separating frontend development from the backend, developing blazingly fast static websites or quickly creating prototypes. Middleman brings all...</p><h3 id="what-is-middleman">What is Middleman?</h3>
<p>Middleman is a small tool for developing stand-alone, static websites. It's great for separating frontend development from the backend, developing blazingly fast static websites or quickly creating prototypes. Middleman brings all of the power of Rails to provide an incredibly powerful development environment with access to:</p>
<ul>
<li>Templating engines and layouts (ERb, Slim, Haml, anything supported by Tilt)</li>
<li>Preprocessors (CoffeeScript, Sass, Less, Stylus, etc)</li>
<li>Compression (Minify CSS, JS and images)</li>
<li>Post-compile callbacks for deployment</li>
<li>And lots of new stuff in 3.0</li>
</ul>
<h3 id="install-the-beta">Install the Beta</h3>
<p>Before getting in to all the new features, here's how you can install the beta:</p>
<div class="highlight"><pre class="highlight plaintext"><code>gem install middleman --pre
</code></pre></div>
<p><strong>Remember:</strong> This is a beta and there are bound to be bugs and possible regressions. 3.0 should be fully backwards compatible with 2.x. Please submit any issues you run into on <a href="https://github.com/middleman/middleman/issues">the Github issue tracker</a>.</p>
<h3 id="new-features-since-beta-1">New Features Since Beta 1</h3>
<p><strong>Read about the other 3.0 features, discussed in <a href="/2012/01/03/middleman-3-beta.html">the Beta 1 announcement</a>.</strong></p>
<p>First, and foremost, I want to recognize the incredible contributions Ben Hollis has made to Middleman in the past 6 months. He's been <a href="https://github.com/middleman/middleman/commits/master?author=bhollis">writing tons code</a>, including some of the features below, as well as managing the community and helping keep me some making stupid errors by commenting on my commits. He's also refactoring the <code>middleman-blog</code> extension, which will be 3.0-compatible very soon.</p>
<p>So, here are some new features:</p>
<ul>
<li><h4 id="bundler-required">Bundler Required</h4>
<p>Most non-Rubyists, and many active Rubyists, are constantly fighting with Rubygems when using Middleman. Our solution in 2.0 was to allow the use of Bundler Gemfiles to lock down the Middleman environment. This was great, but only Ruby developers knew how to use it. In 3.0, Bundler in built directly into Middleman. All new projects generate a Gemfile. In the future, we hope to provide CLI commands for managing a Middleman project, such as: <code>middleman upgrade</code>, to rebundle a project with a newer release of Middleman. </p></li>
<li><h4 id="i18n-built-in">i18n Built-in</h4>
<p>The <code>middleman-i18n</code> extension has been merged into core. We hope to further expand its functionality to make Middleman the best possible solution for building multi-lingual websites.</p></li>
<li><h4 id="gzip-and-asset_hash-extensions"><code>gzip</code> and <code>asset_hash</code> extensions</h4>
<p>Two new optimization extensions are available in Beta 2. </p>
<p><code>gzip</code> will compress your assets during a build, but it will be up to you to serve them. </p>
<p><code>asset_hash</code> is an alternative cache-busting scheme, targeting CDNs. The current <code>cache_buster</code> extension simply adds a querystring to asset paths, which busts the cache in browsers. CDNs actually require that the name of the file is changed. <code>asset_hash</code> will insert a hash of the file into the file names of your assets during build.</p></li>
<li><h4 id="implied-output-extensions">Implied output extensions</h4>
<p>Templating engines can now set a default output extension. For example, <code>.erb</code> now implies <code>.html</code> so <code>my-template.erb</code> will ouput to <code>my-template.html</code>. The 2.0 functionality, of including both the template extension and the output extension in the file name is still prefered. </p></li>
<li><h4 id="miscellaneous-changes">Miscellaneous Changes</h4>
<ul>
<li>Activate mobile html5boilerplate template</li>
<li>Update html5boilerplate template to version 3</li>
<li>Don't re-minify files with ".min" in their name</li>
<li>Automatically load helper modules in helpers/ directory</li>
<li>Add pid for cleanup</li>
<li>Use guard/listen for file watching</li>
<li>Errors stop the build and print a stacktrace rather than silently getting printed into files.</li>
<li><code>with_layout</code> works with globs or regexes.</li>
<li>Setting <code>directory_index</code> from <code>page</code> with a glob or regex now works.</li>
<li>Properly output Compass-generated sprited images.</li>
<li>Include vendored assets in sprockets path.</li>
<li>Switch built-in CSS compressor to Rainpress.</li>
<li>Automatically load helper modules from <code>helpers/</code>, like Rails.</li>
<li><code>ignore</code> and <code>page</code> both work with file globs or regexes.</li>
<li><code>layout</code>, <code>ignore</code>, and <code>directory_index</code> can be set from front matter.</li>
<li>JavaScript and CSS are minified no matter where they are in the site, including in inline code blocks.</li>
</ul></li>
</ul>
Canvas Hit Tracking/2012/03/21/canvas-hit-tracking.html2012-03-21T00:00:00ZT00:00:00-08:002012-03-21T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><em>NOTE: Code samples are in CoffeeScript</em></p>
<p>One of the most fundamental interactions of any game is the ability to click (or touch) an on-screen component to manipulate it. Sounds simple enough, but when building HTML5 Canvas-based games, you'd be wrong...</p><p><em>NOTE: Code samples are in CoffeeScript</em></p>
<p>One of the most fundamental interactions of any game is the ability to click (or touch) an on-screen component to manipulate it. Sounds simple enough, but when building HTML5 Canvas-based games, you'd be wrong.</p>
<p>The HTML5 Canvas allows us to easily draw shapes and images, but it does not provide an object model. What this means is, when I write code to draw a circle:</p>
<div class="highlight"><pre class="highlight plaintext"><code>ctx.arc(10, 10, 10, 0, Math.PI * 2) # Arcs are in Radians
ctx.fill()
</code></pre></div>
<p><img src="/projects/hit-tracking/one.png" alt="Single Circle" /></p>
<p>That code will draw the circle on the canvas immediately, but there is no link between what is displayed and what code caused it to be drawn.</p>
<p>Let's encapsulate drawing a circle into an Object we can reuse. We will also create an array of Objects being displayed.</p>
<h2 id="a-simple-drawing-object">A Simple Drawing Object</h2>
<div class="highlight"><pre class="highlight plaintext"><code>class Circle
constructor: (@opt={}) ->
draw: (ctx) ->
ctx.arc(
@opt.x ? 10, # Default to 10
@opt.y ? 10, # Default to 10
@opt.radius ? 10, # Default to 10
0, Math.PI * 2
)
ctx.fill()
</code></pre></div>
<p>Which can be used like so:</p>
<div class="highlight"><pre class="highlight plaintext"><code>c = new Circle(x: 50, y: 50, radius: 50)
</code></pre></div>
<h2 id="the-world-a-collection-of-objects">The World: A Collection of Objects</h2>
<p>To keep track of our objects for drawing, we'll use a simple array:</p>
<div class="highlight"><pre class="highlight plaintext"><code>theWorld = {
items: []
draw: ->
canvasElement = document.getElementById("world")
ctx = canvasElement.getContext("2d")
# Clear previously drawn
ctx.clearRect(
0, 0,
canvasElement.width+1, canvasElement.height+1
)
# Draw everything
obj.draw(ctx) for obj in @items
}
</code></pre></div>
<p>Now let's add our circle to the world:</p>
<div class="highlight"><pre class="highlight plaintext"><code>theWorld.items.push(c)
</code></pre></div>
<p>Finally, let's draw the world:</p>
<div class="highlight"><pre class="highlight plaintext"><code>theWorld.draw()
</code></pre></div>
<h2 id="naive-hit-tracking">Naive Hit Tracking</h2>
<p>So, now that we have an object representing a circle that we can manipulate and redraw, how do we figure out if clicking (or touching) a specific point on the canvas will "hit" a specific object?</p>
<p>A first solution might involve Bounding Boxes. A Bounding Box is a rectangular container which our drawn object would fill. In the circle example above, the bounding box of a circle drawn at <code>x=50</code>, <code>y=50</code> and with a <code>radius=5</code> would be: </p>
<ul>
<li>Top left: { x: 0, y: 0 }</li>
<li>Top right: { x: 100, y: 0 }</li>
<li>Bottom left: { x: 0, y: 100 }</li>
<li>Bottom right: { x: 100, y: 100 }</li>
</ul>
<p>Let's add code to our Circle object to calculate this:</p>
<div class="highlight"><pre class="highlight plaintext"><code># class Circle
getBounds: ->
{
top: @y - @radius
left: @x - @radius
width: @radius * 2
height: @radius * 2
}
</code></pre></div>
<p>Remember, HTML5 Canvas draws circles from their center. The above can be used like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>c = new Circle(x: 50, y: 50, radius: 50)
c.getBounds() # => { top: 0, left: 0, width: 100, height: 100 }
</code></pre></div>
<p>Now, using simple math, we can calculate whether a click is inside that bounding box. Let's add more to Circle:</p>
<div class="highlight"><pre class="highlight plaintext"><code># class Circle
didHit: (targetX, targetY) ->
b = @getBounds()
(
(b.top <= targetY <= b.top + b.height) &&
(b.left <= targetX <= b.left + b.width)
)
</code></pre></div>
<p>Running a few hit tests should return expected results:</p>
<div class="highlight"><pre class="highlight plaintext"><code>c.didHit(5, 5) # => true
c.didHit(0, 0) # => true
c.didHit(10, 10) # => true
c.didHit(100, 100) # => false
</code></pre></div>
<h3 id="the-problem-with-bounding-boxes">The Problem With Bounding Boxes</h3>
<p>Our choice of shapes, a circle, should give you a hint as to the issues with using bounding boxes for hit testing. Circles are not rectangles, as such, they will give "false" positives at the points inside their bounds, but outside their arcs such as: <code>x=0,y=0</code>. The problem is fourth magnified as soon as we start drawing complex shapes or using images with transparent regions.</p>
<h3 id="the-great-thing-about-bounding-boxes">The Great Thing About Bounding Boxes</h3>
<p>Fear not! The above code is not useless. HTML5 Canvas has the ability to clear specific portions of an already drawn canvas. For performance reasons, you'll want to clear and redraw only the portions that change rather than clearing the whole canvas (as our <code>theWorld</code> example does). The method for clear is <code>clearRect</code> and as you may guess, it takes a bounding box rectangle.</p>
<p>If we had drawn our circle, we could they clear its bounding box like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code># class Circle
clear: (ctx) ->
b = @getBounds()
ctx.clearRect(
b.left,
b.top,
b.left + b.width,
b.top + b.height
)
</code></pre></div>
<p>That said, let's move on to a pixel-perfect hit test. We'll need to refactor our Circle and world first.</p>
<h2 id="offscreen-canvases">Offscreen Canvases</h2>
<p>Another common HTML5 Canvas performance technique you'll encounter is using "offscreen canvases" to reduce the amount of drawing that drawing the whole world would require. Offscreen canvases are simply canvas elements which have not been added to the DOM. In this approach, each Object actually has its own canvas which contains only itself. Drawing the entire world simply copies each Object's canvas onto the main "onscreen canvas."</p>
<p>Let's look at a beefed-up Circle class which uses an offscreen canvas:</p>
<div class="highlight"><pre class="highlight plaintext"><code># class Circle
constructor: (@opt={}) ->
@canvas = document.createElement("canvas")
# @canvas.width needs to be same side as world canvas
# @canvas.height needs to be same side as world canvas
@ctx = @canvas.getContext("2d")
@drawOffscreen()
drawOffscreen: ->
@ctx.arc(
@opt.x ? 10,
@opt.y ? 10,
@opt.radius ? 10,
0, Math.PI * 2
)
@ctx.fill()
# Note: Drawing the entire offscreen canvas onto the
# entire world canvas will get progressively slower as
# the dimensions of the canvas grows. Consider only
# drawing the image slice which represents this object's
# bounding box.
copyOffscreen: (ctx) ->
ctx.drawImage(@canvas, 0, 0)
</code></pre></div>
<p>This time, we create an offscreen canvas for each Circle. <code>drawOffscreen</code> will render to that canvas and <code>copyOffscreen</code> will copy that image to the world canvas (passed in as ctx). <code>drawOffscreen</code> only needs to be called when the parameters which describe the Object change.</p>
<p>The world can now be drawn like so:</p>
<div class="highlight"><pre class="highlight plaintext"><code>theWorld = {
items: []
draw: ->
canvasElement = document.getElementById("world")
ctx = canvasElement.getContext("2d")
# Clear Objects
obj.clear(ctx) for obj in @items
# Draw everything
obj.copyOffscreen(ctx) for obj in @items
}
</code></pre></div>
<p>Finally, we're getting close to a modern, reusable and extensible system for managing Objects, how they clear themselves and how they draw themselves (offscreen and only on parameter change).</p>
<h2 id="per-object-canvas-hit-testing">Per-Object Canvas Hit Testing</h2>
<p>Enough of the preamble, here's the meat. Now that we have an offscreen canvas for each Object that only contains itself, we can use that to check if we are "hitting" the drawn item. If there is a visible pixel at the point of the hit, then we return true.</p>
<div class="highlight"><pre class="highlight plaintext"><code># class Circle
didHit: (targetX, targetY) ->
imageData = @ctx.getImageData(targetX, targetY, 1, 1)
(imageData.data[3] > 0)
</code></pre></div>
<p>The <code>getImageData</code> method returns the RGBA values for the requested range of pixels on a canvas. In the above code, we ask for the target X/Y only. The resulting data is an array <code>[R, G, B, A]</code>. <code>imageData.data[3]</code> is the alpha value of the pixel, if it is greater than zero then that means we drew something there and the hit test is true.</p>
<h2 id="putting-it-all-together">Putting It All Together</h2>
<p>Let's make an addition to <code>theWorld</code> to allow it to test all of its Objects and return only the items which we click on.</p>
<div class="highlight"><pre class="highlight plaintext"><code># theWorld
hitTestObjects: (targetX, targetY) ->
i for i in @items when i.hitTest(targetX, targetY)
</code></pre></div>
<p>There we go, here's a complicated example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>c1 = new Circle(x: 50, y: 50, radius: 50)
c2 = new Circle(x: 100, y: 50, radius: 50)
c3 = new Circle(x: 150, y: 50, radius: 50)
theWorld.push(c1)
theWorld.push(c2)
theWorld.push(c3)
theWorld.hitTestObjects(0, 0) # => []
theWorld.hitTestObjects(50, 50) # => [c1, c2]
theWorld.hitTestObjects(100, 50) # => [c1, c2, c3]
theWorld.hitTestObjects(150, 50) # => [c2, c3]
</code></pre></div>
<p><img src="/projects/hit-tracking/three.png" alt="Three Circles" /></p>
<p>I could go further and try things out with arcs, empty stroked rectangles, donuts and semi-transparent images, but it would work exactly the same.</p>
<p>There's plenty of room for caching, memoization and other optimizations in this system, but conceptually this is common approach. I hope this was enlightening.</p>
Image Sequences: Let Me Count The Ways/2012/03/08/image-sequences.html2012-03-08T00:00:00ZT00:00:00-08:002012-03-08T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Everyone's very excited by their "Pure CSS" <a href="http://lab.victorcoulon.fr/css/path-menu/">this</a> and "Pure CSS" <a href="http://clear.youyuxi.com/">that</a>, but if we are front-end developers really want to start taking on traditionally Flash use-cases, we're going to need to step out animation game up a notch.</p>
<p>Enter the Image Sequence...</p><p>Everyone's very excited by their "Pure CSS" <a href="http://lab.victorcoulon.fr/css/path-menu/">this</a> and "Pure CSS" <a href="http://clear.youyuxi.com/">that</a>, but if we are front-end developers really want to start taking on traditionally Flash use-cases, we're going to need to step out animation game up a notch.</p>
<p>Enter the Image Sequence. An Image Sequence is exactly what it sounds like, a series of images, each representing a single frame of an animation. Usually these will be exported from a high-level application like Adobe After Effects. For memory and performance reasons, these images are usually combined into a single Sprite Sheet. You may have heard of this technique, because <a href="http://en.wikipedia.org/wiki/Sprite_(computer_graphics)">we've been using it for decades</a>.</p>
<p>This week I implemented Image Sequences in 3 different ways. And just yesterday, Apple started using another technique on their <a href="http://www.apple.com/ipad/">iPad product page</a>.</p>
<h2 id="the-animation">The Animation</h2>
<p>I'll be animating a "bouncing" particle. Here's a look at the first frame:</p>
<p><img src="/projects/sequence/particle-hover/particle_hover_04_00000.png"></p>
<p>Each frame is 104x124. </p>
<p>Here's <a href="/projects/sequence/particle-hover.zip">a zip of the entire 60 frame sequence</a>.</p>
<p>Finally, here's <a href="/projects/sequence/particle-hover-frames.jpg">a 560kb Sprite Sheet containing all the frames</a>. We'll be using this in all the examples except for Apple's newest implementation.</p>
<h2 id="1-pure-csssass-animation">1: Pure <del>CSS</del>Sass Animation</h2>
<p>Did I say CSS? I'm way too lazy for that, let's use Sass.</p>
<p>The current versions of all desktop browsers, except IE, <a href="http://caniuse.com/#feat=css-animation">support CSS3 Animations</a>. The syntax for this in CSS looks like the following (you'll need to add your own vendor prefixes):</p>
<div class="highlight"><pre class="highlight plaintext"><code>@keyframes animate-particle {
0% { opacity: 0; }
100% { opacity: 1; }
}
</code></pre></div>
<p>This will define a simple fadeIn animation which you can control on each element which implements it:</p>
<div class="highlight"><pre class="highlight plaintext"><code>#my-particle {
width: 104px;
height: 124px;
background: url(particle-hover_04_00000.png);
animation-duration: 1s;
animation-iteration-count: infinite;
animation-name: animate-particle;
}
</code></pre></div>
<p>This will run the 1 second animation infinitely.</p>
<p>So, how can we use this to animate our Sprite Sheet? We'll simply animate the background-position offset of the element 1 frame at a time. If you opened <a href="/projects/sequence/particle-hover-frames.jpg">the Sprite Sheet</a>, you'll remember we've stacked all 60 frames vertically. So our keyframes would look something like: </p>
<div class="highlight"><pre class="highlight plaintext"><code>@keyframes animate-particle {
0% { background-position: 0 0; }
1.69% { background-position: 0 -124px; }
3.39% { background-position: 0 -248px; }
...
}
</code></pre></div>
<p>We need to animate across 60 frames over the 100% range of the animation, which means each frame is 1.695%. This could get nasty and verbose very quickly. Let's use Sass:</p>
<div class="highlight"><pre class="highlight plaintext"><code>@keyframes animate-particle {
@for $i from 0 through 59 {
$s: ($i * 100) / 59 + "%";
#{$s} { background-position: 0 ($i * -124px); }
}
}
</code></pre></div>
<p>You can see <a href="https://gist.github.com/2002296">the entire output here</a>. Now, let's reference that on our element. We've double checked with our designer that the animation is at 30fps, so that means our 60 frames should last 2 seconds.</p>
<div class="highlight"><pre class="highlight plaintext"><code>#my-particle {
width: 104px;
height: 124px;
background: url(particle-hover-frames.jpg);
animation-duration: 2s;
animation-iteration-count: infinite;
animation-timing-function: step-start;
animation-name: animate-particle;
}
</code></pre></div>
<p>There is one piece of special sauce above and that is:</p>
<div class="highlight"><pre class="highlight plaintext"><code>animation-timing-function: step-start;
</code></pre></div>
<p>Normally, CSS animations will attempt to tween between states, which is great for smooth transitions in opacity or scale, but we need the animate to jump immediately from frame to frame. That is what <code>step-start</code> does.</p>
<h4 id="view-the-pure-css-animation-image-sequence-demo"><a href="/projects/sequence/css.html">View the Pure CSS Animation Image Sequence Demo</a>.<br><br></h4>
<h2 id="2-canvas-animation">2: Canvas Animation</h2>
<p>The Canvas element is just a blank slate you can draw pixels on to. Drawing image data from individual files or sprite sheets is very easy. We'll use the same Sprite Sheet from above.</p>
<div class="highlight"><pre class="highlight plaintext"><code>function drawFrame(ctx, image, width, height, num) {
var offsetX = 0,
offsetY = num * height;
ctx.drawImage(image,
offsetX, offsetY,
width, height,
0, 0,
width, height);
}
</code></pre></div>
<p>The above function will take a Canvas context, an Image object, the dimensions of each frame and the frame to draw. We'll use <a href="http://paulirish.com/2011/requestanimationframe-for-smart-animating/">requestAnimationFrame</a> for smooth animations.</p>
<div class="highlight"><pre class="highlight plaintext"><code>function rightNow() {
if (window['performance'] && window['performance']['now']) {
return window['performance']['now']();
} else {
return +(new Date());
}
}
var fps = 30,
currentFrame = 0,
totalFrames = 60,
img = document.getElementById("frames"),
canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
currentTime = rightNow();
(function animloop(time){
var delta = (time - currentTime) / 1000;
currentFrame += (delta * fps);
var frameNum = Math.floor(currentFrame);
if (frameNum >= totalFrames) {
currentFrame = frameNum = 0;
}
requestAnimationFrame(animloop);
drawFrame(ctx, img, 104, 124, frameNum);
currentTime = time;
})(currentTime);
</code></pre></div>
<h4 id="view-the-canvas-animation-image-sequence-demo"><a href="/projects/sequence/canvas.html">View the Canvas Animation Image Sequence Demo</a>.<br><br></h4>
<h2 id="3-javascript-dom-animation">3: Javascript DOM Animation</h2>
<p>The next solution is to implement the CSS version in Javascript. We'll use the exact same approach. Take a div element, animate its background image. The advantage here is that this will work in every browser (assuming you have the <a href="http://paulirish.com/2011/requestanimationframe-for-smart-animating/">requestAnimationFrame polyfill</a>).</p>
<div class="highlight"><pre class="highlight plaintext"><code>#my-particle2 {
width: 104px;
height: 124px;
background: url(particle-hover-frames.jpg);
}
</code></pre></div>
<p>Similar CSS, minus the CSS Animation code. Now for the JS (which is similar to the Canvas implementation): </p>
<div class="highlight"><pre class="highlight plaintext"><code>function rightNow() {
if (window['performance'] && window['performance']['now']) {
return window['performance']['now']();
} else {
return +(new Date());
}
}
var fps = 30,
currentFrame = 0,
totalFrames = 60,
elem = document.getElementById("my-particle2"),
currentTime = rightNow();
(function animloop(time){
var delta = (time - currentTime) / 1000;
currentFrame += (delta * fps);
var frameNum = Math.floor(currentFrame);
if (frameNum >= totalFrames) {
currentFrame = frameNum = 0;
}
requestAnimationFrame(animloop);
elem.style.backgroundPosition = "0 -" + (frameNum * 124) + "px";
currentTime = time;
})(currentTime);
</code></pre></div>
<h4 id="view-the-javascript-dom-animation-image-sequence-demo"><a href="/projects/sequence/elem.html">View the Javascript DOM Animation Image Sequence Demo</a>.<br><br></h4>
<h2 id="4-apple-style-img-animation">4: Apple-style IMG Animation</h2>
<p>Finally, let's take a look at Apple's implementation. They actually use the more straightforward approach. The preload the individual images, and directly set the chosen frame on a normal Image element. Simple, eh?</p>
<p>Traditionally, this approach has been considered too slow to smoothly animate, but it looks like the combination of requestAnimationFrame, Webkit's incredible speed, Apple's ability to target Safari and the decline of older IE versions has made this technique "fast enough".</p>
<p>Here's an implementation:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function rightNow() {
if (window['performance'] && window['performance']['now']) {
return window['performance']['now']();
} else {
return +(new Date());
}
}
var fps = 30,
currentFrame = 0,
totalFrames = 60,
img = document.getElementById("myImage"),
currentTime = rightNow();
(function animloop(time){
var delta = (time - currentTime) / 1000;
currentFrame += (delta * fps);
var frameNum = Math.floor(currentFrame);
if (frameNum >= totalFrames) {
currentFrame = frameNum = 0;
}
requestAnimationFrame(animloop);
img.src = "/projects/sequence/particle-hover/particle_hover_04_000" +
(frameNum < 10 ? "0" : "") + frameNum + ".png";
currentTime = time;
})(currentTime);
</code></pre></div>
<h4 id="view-the-apple-style-animation-image-sequence-demo"><a href="/projects/sequence/apple.html">View the Apple-style Animation Image Sequence Demo</a>.<br><br></h4>
<h2 id="conclusion">Conclusion</h2>
<p>Each of the above techniques has a specific use-case. </p>
<p>Pure CSS <em>should</em> be GPU accelerated and lets you keep all your animations together in CSS. The downside is that you have to generate all the frame percentages in CSS (or Sass) and that it only works in modern browsers. I've also encountered performance issues where the CSS method is causing redraw/repaint events which slow other animations on the screen.</p>
<p>The Canvas implementation is great for games, where you'll be drawing most of your components directly to the canvas.</p>
<p>The Javascript DOM method works best when you want to load the large Sprite Sheet and avoid too many HTTP requests.</p>
<p>The Apple-style method will probably become very popular. You can start the animation after the page loads and use it as a form of progressive enhancement.</p>
Best Albums of the Year: 2011/2012/01/07/best-albums-of-the-year-2011.html2012-01-07T00:00:00ZT00:00:00-08:002012-01-07T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I almost didn't write this article because I was so disappointed in 2011. Here it is anyways for posterity, I couldn't even manage to find 10 albums I like enough to list.</p>
<h2 id="top-7">Top 7:</h2>
<ul class="albums">
<li>
<div class="cover">
<img src="/albums/2011/7.jpg"><div></div>
</div>
<div class="content">
<h6>The Dear Hunter</h6>
<h4>The Color Spectrum</h4>
</div>
</li>
</ul><p>I almost didn't write this article because I was so disappointed in 2011. Here it is anyways for posterity, I couldn't even manage to find 10 albums I like enough to list.</p>
<h2 id="top-7">Top 7:</h2>
<ul class="albums">
<li>
<div class='cover'>
<img src='/albums/2011/7.jpg' /><div></div>
</div>
<div class='content'>
<h6>The Dear Hunter</h6>
<h4>The Color Spectrum</h4>
<p>Progressive rockers decided to take a "small" break in the middle of their 6 concept album cycle to write a 9 concept album cycle. The Color Spectrum is 9 EPs, each representing a color on the spectrum, containing 36 total songs clocking in at 2.5hrs of music. And yet, it's listenable all the way through. I particularly like the straight rock of Red and the hopeful feeling in the closing White.</p>
</div>
<div class='player'>
<h6>#7</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2011/6.jpg' /><div></div>
</div>
<div class='content'>
<h6>Glassjaw</h6>
<h4>Coloring Book / Our Color Green</h4>
<p>Glassjaw reemerged with 2 EPs to satisfy fans along with a handful of music videos and promises that a full-length is coming soon. Glassjaw is much darker, heavier and crushing in both theses EPs. I'm loving the direction.</p>
</div>
<div class='player'>
<h6>#6</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2011/5.png' /><div></div>
</div>
<div class='content'>
<h6>Pianos Become The Teet</h6>
<h4>The Lack Long After</h4>
<p>Caught somewhere between post-rock and post-hardcore, Pianos Become The Teeth continued to refine their sounds: beautiful interludes punctuated by explosive vocals.</p>
</div>
<div class='player'>
<h6>#5</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2011/4.jpg' /><div></div>
</div>
<div class='content'>
<h6>Portugal. The Man</h6>
<h4>In The Mountain In The Cloud</h4>
<p>Another year, another Portugal. The Man album. This year they released their "big label" debut which feels less free and more produced than past work. However, it doesn't really matter because the songs continue to be great and always fresh.</p>
</div>
<div class='player'>
<h6>#4</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2011/3.jpg' /><div></div>
</div>
<div class='content'>
<h6>Touché Amoré</h6>
<h4>Parting The Sea Between Brightness And Me</h4>
<p>Hardcore songs are short and fast. Touché Amoré decided that 3 minutes was still too long and condensed everything on this album to less than 2 minutes, some only 60-70 seconds long. The result is pure energy that leaves you wanting to restart the album after it's 20 minute play-time.</p>
</div>
<div class='player'>
<h6>#3</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2011/2.jpg' /><div></div>
</div>
<div class='content'>
<h6>Trey Parker, Matt Stone & Company</h6>
<h4>The Book of Mormon Soundtrack</h4>
<p>Matt & Trey are very good at musicals. Cannibal the Musical is great and they wrote that with no budget in college. The South Park musical is exceptional, way better than that shitty Phil Collins' Tarzan soundtrack. The Book of Mormon blows both those away, along with a lot of the other musical theater classics. I can't wait to see the thing live.</p>
</div>
<div class='player'>
<h6>#2</h6>
</div>
</li>
<li class="last">
<div class='cover'>
<img src='/albums/2011/1.jpg' /><div></div>
</div>
<div class='content'>
<h6>Bomb The Music Industry!</h6>
<h4>Vacation</h4>
<p>I'm going to echo a million other reviews, this is punk rock's Pet Sounds.</p>
</div>
<div class='player'>
<h6>#1</h6>
</div>
</li>
</ul>
Middleman 3.0 Beta/2012/01/03/middleman-3-beta.html2012-01-03T00:00:00ZT00:00:00-08:002012-01-03T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Middleman is a small tool for developing stand-alone, static websites. It's great for separating frontend development from the backend, developing blazingly fast static websites or quickly creating prototypes. Middleman brings all of the power of Rails...</p><p>Middleman is a small tool for developing stand-alone, static websites. It's great for separating frontend development from the backend, developing blazingly fast static websites or quickly creating prototypes. Middleman brings all of the power of Rails to provide an incredibly powerful development environment with access to:</p>
<ul>
<li>Templating engines and layouts (ERb, Slim, Haml, anything supported by Tilt)</li>
<li>Preprocessors (CoffeeScript, Sass, Less, Stylus, etc)</li>
<li>Compression (Minify CSS, JS and images)</li>
<li>Post-compile callbacks for deployment</li>
<li>And lots of new stuff in 3.0</li>
</ul>
<h3 id="install-the-beta">Install the Beta</h3>
<p>Before getting in to all the new features, here's how you can install the beta:</p>
<div class="highlight"><pre class="highlight plaintext"><code>gem install middleman --pre
</code></pre></div>
<p><strong>Remember:</strong> This is a beta and there are bound to be bugs and possible regressions. 3.0 should be fully backwards compatible with 2.x. Please submit any issues you run into on <a href="https://github.com/middleman/middleman/issues">the Github issue tracker</a>.</p>
<h3 id="new-features">New Features</h3>
<p>Let's dive in.</p>
<ul>
<li><h4 id="middleman-core-middleman-more">middleman-core & middleman-more</h4>
<p>The middleman gem has been split into 2 smaller gems. middleman-core contains everything you need to run a simple Middleman project, but does not include any templating languages other than ERb or any compiled extensions. This means you <em>should</em> be able to install middleman-core on systems without a compiler. You won't have access to things like CoffeeScript, Sass, Sprockets or asset compression, but many users don't need these extra features. The full dependency list for middleman-core is: activesupport, fssm, rack, rack-test, thor & tilt.</p>
<p>middleman-more contains everything not in middleman-core. Combining the two will work exactly as middleman 2.x did. In fact, this is exactly what installing the middleman gem directly does.</p></li>
<li><h4 id="direct-preview">Direct Preview</h4>
<p>Sometimes you just want to host a directory of web assets on localhost without doing anything fancy. In 3.0, Middleman will do just this if you run it from a directory with a <code>config.rb</code> file. For example: </p>
<div class="highlight"><pre class="highlight plaintext"><code> # Download the Zurb Foundation: http://foundation.zurb.com/
cd foundation
middleman server
</code></pre></div>
<p>Now the <a href="http://foundation.zurb.com/">Zurb Foundation</a> will be available at: <a href="http://localhost:4567/">http://localhost:4567/</a></p></li>
<li><h4 id="sass-compass-and-sprockets">Sass, Compass and Sprockets</h4>
<p>Sass and Scss file now have access to Sprockets dependency management and to CSS located in gems which support the Rails 3.1 Asset Pipeline. Given a "source/stylesheets/main.css.scss":</p>
<div class="highlight"><pre class="highlight plaintext"><code> /**
*= require "some_partial"
*
* Using Zurb as an example: gem install zurb-foundation
*= require "foundation/typography"
*/
body {
/* My code */
}
</code></pre></div></li>
<li><h4 id="nested-layouts">Nested Layouts</h4>
<p>As an alternative to partials and content_for blocks, we've added something from the Django world. Say I have a template named "source/index.html.erb" and it's layout is located at "source/layouts/default.erb". Normally, the contents of the layout will wrap the contents of the template. With nested layouts, I can add the following to the layout and wrap the contents yet again:</p>
<div class="highlight"><pre class="highlight plaintext"><code><% wrap_layout :admin do %>
I am the Defaul Layout
<%= yield %>
<% end %>
</code></pre></div>
<p>Now, the final contents will be the template, wrapped in the default layout, wrapped in the admin layout. This can continue indefinitely.</p></li>
<li><h4 id="the-sitemap">The Sitemap</h4>
<p>The Sitemap is a new, internal cache of all the pages in your project. It can be inspected for building navigation, scraping pages for frontmatter or all manner of metaprogramming. When you add, remove or change a file, the sitemap is automatically updated.</p>
<p>Here's a quick example for building an index page which displays an automatically updating list of it's child pages.</p>
<div class="highlight"><pre class="highlight plaintext"><code><% for page in current_page.children %>
<%= link_to page.data.title, page.url %>
<% end %>
</code></pre></div>
<p>As you'll notice, the page object has access to that page's frontmatter. This means we can use frontmatter to provide categorization and work with that data. Say we have several pages with the following frontmatter (and several without it):</p>
<div class="highlight"><pre class="highlight plaintext"><code>---
category: internal
---
</code></pre></div>
<p>Now we can select only the pages with that category to display in our list of links:</p>
<div class="highlight"><pre class="highlight plaintext"><code><h1>Internal</h1>
<% for page in current_page.children.select { |x| x.data.category == "internal" } %>
<%= link_to page.data.title, page.url %>
<% end %>
</code></pre></div></li>
<li><h4 id="miscellaneous-changes">Miscellaneous Changes</h4>
<ul>
<li>Rewritten to work directly with Rack (Sinatra apps can still be mounted)</li>
<li>Yard code docs: <a href="http://rubydoc.info/github/middleman/middleman">http://rubydoc.info/github/middleman/middleman</a></li>
<li>3rd Party Command Line Tools</li>
<li>Activate mobile html5boilerplate template</li>
<li>Support for placekitten.com</li>
<li>Activating extensions can now take an options hash</li>
<li>Don't re-minify files with ".min" in their name</li>
<li>Enable chained templates outside of sprockets (file.html.markdown.erb)</li>
<li>Removed old 1.x mm- binaries, please use the main "middleman" binary from now on</li>
</ul></li>
</ul>
Ember.js Live Collections/2011/12/27/emberjs-collections.html2011-12-27T00:00:00ZT00:00:00-08:002011-12-27T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>If you're writing a client-side application, there are two common tasks you can expect to perform. First, modern web applications are expected to show updated information as quickly as possible without a full page reload. (Think about Twitter or Facebook...</p><p>If you're writing a client-side application, there are two common tasks you can expect to perform. First, modern web applications are expected to show updated information as quickly as possible without a full page reload. (Think about Twitter or Facebook: as you're reading the updates, newer updates continue to arrive at the top of the page.) Second, you'll be sending the current user's updates to everyone else's streams.</p>
<p>You can probably imagine how often you'll need to implement these patterns: mail clients, chat rooms; anything that updates, really.</p>
<p>Over the weekend, my friends at Bocoup <a href="http://weblog.bocoup.com/backbone-live-collections">posted an article</a> called <em>Backbone.js Live Collections</em> which discussed how to use Backbone.js<sup>1</sup> to poll Twitter for new tweets and update a list of those tweets on the page. <strike>I don't know their official stance on Backbone.js, so I'm going to assume they used it as an example because it was either code extracted from one of their projects or they simply decided to use Backbone.js because of its popularity.</strike> <strong>[Edit: Ben Alman of Bocoup has clarified their position saying: "FWIW, we decided to use Backbone after a ton of research and experimentation."]</strong> Go ahead and read that article… I'll wait.</p>
<p>Back? Good.</p>
<p>Assuming that Bocoup simply chose Backbone.js for familiarity's sake, I glibly summed up the article as "In other words, use Ember.js :-p" and ruffled more feathers than I intended. I was invited to write this article to express my point better than a tweet could, so here we go.</p>
<h2 id="ember-js-amber-js-sproutcore-2-0">Ember.js <strike>Amber.js</strike> <strike>Sproutcore 2.0</strike></h2>
<p><a href="http://www.emberjs.com/">Ember.js</a> is what happened when SproutCore decided to be less Apple Cocoa and more jQuery. The result is a web framework which retains very important high-level concepts such as observers, bindings and state charts, while delivering a concise API. SproutCore started its life as the development framework behind an early client-side email application. Then, Apple used it to build MobileMe (and then iCloud), both of which include email clients. Needless to say, they've figured out that collections which update from the server are very important. In my opinion, SproutCore/Ember.js are the best solution for anything needing collections of data rendered into the DOM. Thus my glib tweet above.</p>
<p>Below, I've recreated the Bocoup example using Ember.js. I think it expresses the intent of the initial application more concisely and
understandably. You'll note that there is no code that interacts with the DOM at all; instead, making in changes in JavaScript causes
the DOM to be updated to reflect the new state automatically.</p>
<h3 id="app">App</h3>
<div class="highlight"><pre class="highlight plaintext"><code>// Setup a global namespace for our code.
Twitter = Em.Application.create({
// When everything is loaded.
ready: function() {
// Start polling Twitter
setInterval(function() {
Twitter.searchResults.refresh();
}, 2000);
// The default search is empty, let's find some cats.
Twitter.searchResults.set("query", "cats");
// Call the superclass's `ready` method.
this._super();
}
});
</code></pre></div>
<p>The app is the core of any Ember.js project. It provides a ready event, much like jQuery's, and sets up event delegation behind the scenes. Its primary use in this example is to namespace all our classes and variables under the <code>Twitter</code> namespace.</p>
<h3 id="template-view">Template View</h3>
<div class="highlight"><pre class="highlight plaintext"><code><script type="text/x-handlebars">
<ul class="tweets">
{{#each Twitter.searchResults}}
<li class="tweet">{{text}}</li>
{{/each}}
</ul>
</script>
</code></pre></div>
<p>Ember.js templates are written in <a href="http://www.handlebarsjs.com/">Handlebars.js</a>. You can use a <code>text/x-handlebars</code> script tag anywhere in your document and it will be replaced with a live-updating View. The above code will watch for a variable called <code>Twitter.searchResults</code> and when it changes, it will update the list items in the <code>ul</code>. See what I mean about Ember.js being optimized for collections and lists?</p>
<h3 id="model">Model</h3>
<div class="highlight"><pre class="highlight plaintext"><code>Twitter.Tweet = Em.Object.extend();
</code></pre></div>
<p>This is entirely a naming/convenience issue. We're not writing any custom code for handling each tweet. We simply take its JSON and use it directly.</p>
<h3 id="controller">Controller</h3>
<div class="highlight"><pre class="highlight plaintext"><code>// An instance of ArrayController which handles collections.
Twitter.searchResults = Em.ArrayController.create({
// Default collection is an empty array.
content: [],
// Default query is blank.
query: null,
// Simple id-to-model mapping for searches and duplicate checks.
_idCache: {},
// Add a Twitter.Tweet instance to this collection.
// Most of the work is in the built-in `pushObject` method,
// but this is where we add our simple duplicate checking.
addTweet: function(tweet) {
// The `id` from Twitter's JSON
var id = tweet.get("id");
// If we don't already have an object with this id, add it.
if (typeof this._idCache[id] === "undefined") {
this.pushObject(tweet);
this._idCache[id] = tweet.id;
}
},
// Public method to fetch more data. Get's called in the loop
// above as well as whenever the `query` variable changes (via
// an observer).
refresh: function() {
var query = this.get("query");
// Only fetch if we have a query set.
if (Em.empty(query)) {
this.set("content", []);
return;
}
// Poll Twitter
var self = this;
var url = "http://search.twitter.com/search.json?q=" + query + "&callback=?";
$.getJSON(url, function(data) {
// Make a model for each result and add it to the collection.
for (var i = 0; i < data.results.length; i++) {
self.addTweet(Twitter.Tweet.create(data.results[i]));
}
});
}.observes("query")
});
</code></pre></div>
<p>Here's the meat of the solution. Most of this is simply setting up a nice API and doing the JSON request. The simplest version of the code above would look like:</p>
<div class="highlight"><pre class="highlight plaintext"><code>Twitter.searchResults = Em.ArrayController.create();
$.getJSON("http://search.twitter.com/search.json?q=cats&callback=?", function(d) {
Twitter.searchResults.pushObjects(d.results);
});
</code></pre></div>
<h2 id="step-3-profit">Step 3, Profit</h2>
<p>There is no step three!</p>
<p><a href="/projects/emberjs-live-collection.html">Check out the demo</a></p>
<p>I'm not saying Ember.js is the best solution for every problem, but when it comes to collections updating the DOM, they've nailed it.</p>
<h3 id="footnotes">Footnotes</h3>
<ol>
<li><p>Backbone.js is a client-side Model-View-Controller framework for Javascript. It is incredibly popular. The <a href="http://peepcode.com/products/backbone-js">PeepCode screencasts</a> are a wonderful way to get started.</p></li>
<li><p>Thanks to <a href="https://twitter.com/#!/tomdale">Tom Dale</a> of the Tilde, and a developer on the Ember.js project, for proofing this article.</p></li>
</ol>
The Tweets They Are A-Changin'/2011/12/26/the-tweets-they-are-a-changin.html2011-12-26T00:00:00ZT00:00:00-08:002011-12-26T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>How you do add more meaning to 140 characters optimizing for brevity over clarity? You can infer meaning and intention from what you know about the author. If you know the author in real life, often you can hear the way they would have said a certain...</p><p>How you do add more meaning to 140 characters optimizing for brevity over clarity? You can infer meaning and intention from what you know about the author. If you know the author in real life, often you can hear the way they would have said a certain word or imagine the way their eyes sparkled when turning a clever phrase. Even then, careless writing can confuse even those who know you best. It doesn't help that we often affect a certain style in our writing that is absent from our speaking.</p>
<p>Twitter's original purpose was to broadcast your short opinions to a selection of people who wanted to hear what you had to say. This small tribe were likely to know you well enough to read between the lines or, if they couldn't, they would simply to stop following you. </p>
<p>But Twitter grew up. Rather than providing a way for small, mostly overlapping, groups of people to communicate, they've decided to push the idea of one, massive, system-wide conversation organized by Trending Topics. This means a message between friends can find its way in front of thousands of unfriendly eyeballs unwilling to treat a pithy statement as something they does not require a response.</p>
<p>As Twitter's growth accelerates, it seems the number of angry conversations I am having on it are increasing as well. For the most part, something I say intended for friends or developers is retweeted and suddenly some Tea Party moron I've never met is yelling at me for infringing on his freedoms.</p>
<p>I guess there isn't much I can do to fix this situation. The universe tends towards entropy and human conversation tends towards anger, indigence and a lack of basic respect for others' opinions. That said, I have developed my own kind of "emotional inference style guide" and I'm going to tell you about it.</p>
<h2 id="personal-opinion-expressed-anger-direct-attack">Personal Opinion, Expressed Anger & Direct Attack</h2>
<p>Let's say my iPhone crashed. Here are three ways I might tweet about it. Each has its own meaning to me, though others may read them all identically.</p>
<ul>
<li><em>"My iPhone just crashed. Fuck <strong>Apple</strong>."</em></li>
<li><em>"My iPhone just crashed. Fuck <strong>@Apple</strong>."</em></li>
<li><em>"My iPhone just crashed. Fuck <strong>@apple<em>store</em>emplyoee<em>john</em>doe</strong>."</em></li>
</ul>
<p>In the first case, I am complaining out loud about a mass corporation who I would never expect to give a damn. I can say whatever I want, it's venting plain and simple.</p>
<p>In the second case, I'm complaining directly to an account for that company. Likely this will be a Customer Relations person and there is an off chance they will respond. I've seen organizations like Comcast doing actual troubleshooting and refunds over their official Twitter accounts.</p>
<p>In the third case, I am directly attacking a human being with a Twitter account. They should take this personally and I wouldn't be surprised if they fight back.</p>
<h3 id="the-example-prompting-this-article">The Example Prompting This Article</h3>
<p>Earlier today I had a similar issue. @BoazSender, a friend who I've met at several conferences, retweeted a blog article from his company's official account. I chose to express my opinion at the company @Bocoup account because I wanted to attribute the original tweet, but I also didn't want to address the author himself because that would be too confrontational.</p>
<p>Needless to say, nobody but myself knows my own internal logic so my glib opinion landed as an insult instead. Even worse, since all the employees follow their official account, they all took it personally. Twitter multiplexed my opinion into a dozen tiny insults. Whoops. Sorry guys.</p>
<h3 id="auto-searches-and-passing-along-hate">Auto-Searches and Passing Along Hate</h3>
<p>The above example is probably my fault. I tried to fix it as quickly as possible. However, there are even worse ways in which my system fails. In my first example, I did not reference a real Twitter account and assumed that a real human would not read or respond to it. It turns out that I am very wrong. Many people seem to be running automatic searches for their names on Twitter and then responding to anyone who mentions them. This seems like a good way to go crazy unless you are universally loved.</p>
<p>Now my first, and least insulting, example has suddenly jumped to the most insulting level. Still, if you're searching for people talking about you, you deserve what you get. All I can say is, I have opinions and I will express them and I did not intend to be confrontational.</p>
<p>Finally, there are toadies who follow me even when the recipient of my opinion does not. I know big wigs don't follow my little account, so I feel safe to call them out on things. But then a fan of whoever I insult reads my tweet and passes it along to the target. Whereas my original statement was vaguely directed, the retweet basically says "Hey X, so and so thinks you suck." It's hard to recover from that kind of introduction.</p>
<h2 id="conclusion-poor-john-gruber">Conclusion (Poor John Gruber)</h2>
<p>All I can say is, everyone should try to assume opinions are just opinions and take disagreements as gracefully as possible.</p>
<p>That said, I'm starting to feel back for John Gruber. John writes the incredibly popular <a href="http://daringfireball.net">Daring Fireball</a> blog. He has a @daringfireball work account and a @gruber personal account. He has strong opinions and tweets them from his personal account. His blog and that account are usually well-reasoned and researched.</p>
<p>And yet, he receives tons of directly targeted hate tweets. The internet is a mean place. It was nice when it was in the Youtube Comment Ghetto, but really sucks when it spills over into your personal communication.</p>
<p>Most of these assholes (fuck those guys) message @gruber directly with some raw hate about his blog. In my system I wouldn't feel bad saying "I think John Gruber is wrong," if I felt that way. If an article needed a correction, I'd message @daringfireball. But never would I say mean things to @gruber for something he wrote on @daringfireball.</p>
<p>Twitter is becoming the defacto source for Ad Hominem attacks.</p>
Kindle Dots/2011/12/25/kindle-dots.html2011-12-25T00:00:00ZT00:00:00-08:002011-12-25T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I used to tear through several books at a time. I'd collect and organize as many as I could get my hands on and keep them in as pristine condition as possible.</p>
<p>My dad loved comics and sci-fi, so I started there. Then, I became interested in pop-science...</p><p>I used to tear through several books at a time. I'd collect and organize as many as I could get my hands on and keep them in as pristine condition as possible.</p>
<p>My dad loved comics and sci-fi, so I started there. Then, I became interested in pop-science biology and cosmology. In school, I studied computer science and comparative religion. At some point after college, I exhausted the genres I was interested in.</p>
<p>Not having something to read was frustrating, but nothing I picked up would hold my interest. Eventually, I got tired of lugging dozens of boxes of books around and sold them all back to Amazon. </p>
<p>Last Christmas, I got a 3rd generation Kindle from my wife. Suddenly my library was infinite and accessible anywhere. I started reading the <em>Song of Ice and Fire</em> books in preparation for the HBO series and discovered something rather amazing about the Kindle. Because the Kindle allows different font face and size settings, it does keep a page count, rather it shows your relative position in the book with highlighted dots. This means the 1200 page fantasy novel that I would have found daunting and awkward to carry around is suddenly small and portable. The mental weight of all those pages was reduced to "do I want to read the next page."</p>
<p>I read a lot of long books this year, mostly fantasy, some sci-fi and some steampunk. I decided to check Amazon for the actual printed page lengths of these books.</p>
<table><thead>
<tr>
<th>Title</th>
<th>Pages</th>
</tr>
</thead><tbody>
<tr>
<td>A Storm of Swords</td>
<td>1216</td>
</tr>
<tr>
<td>A Feast for Crows</td>
<td>784</td>
</tr>
<tr>
<td>A Dance with Dragons</td>
<td>1040</td>
</tr>
<tr>
<td>The Windup Girl</td>
<td>300</td>
</tr>
<tr>
<td>The Half-Made World</td>
<td>480</td>
</tr>
<tr>
<td>The Magicians</td>
<td>416</td>
</tr>
<tr>
<td>The Magician King</td>
<td>416</td>
</tr>
<tr>
<td>The Black Company</td>
<td>320</td>
</tr>
<tr>
<td>Shadows Linger</td>
<td>319</td>
</tr>
<tr>
<td>The White Rose</td>
<td>320</td>
</tr>
<tr>
<td>The Name of the Wind</td>
<td>672</td>
</tr>
<tr>
<td>The Dresden Files: Storm Front</td>
<td>384</td>
</tr>
<tr>
<td>Old Man's War</td>
<td>320</td>
</tr>
<tr>
<td>Wise Man's Fear</td>
<td>993</td>
</tr>
<tr>
<td>The Hunger Games</td>
<td>384</td>
</tr>
<tr>
<td>Catching Fire</td>
<td>391</td>
</tr>
</tbody></table>
<ul>
<li>Total Pages: <strong>8755</strong></li>
<li>Average Pages per Day: <strong>23.9</strong></li>
</ul>
Experiment: Particle Rider/2011/11/30/particle-rider-experiment.html2011-11-30T00:00:00ZT00:00:00-08:002011-11-30T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Here's a little particle system I built to experiment with <a href="http://paperjs.org/">Paper.js</a>. Move the mouse to draw a path and watch as the particles follow it. Trapping the particles in infinite loops is fun.</p>
<p><a href="/projects/particle-rider.html"><img src="/projects/particle-rider/particle-rider.png"></a></p>
<p>Here's a little particle system I built to experiment with <a href="http://paperjs.org/">Paper.js</a>. Move the mouse to draw a path and watch as the particles follow it. Trapping the particles in infinite loops is fun.</p>
<p><a href="/projects/particle-rider.html"><img src="/projects/particle-rider/particle-rider.png"></a></p>
Just Launched: The License Lab/2011/11/03/just-launched-thelicenselab.html2011-11-03T00:00:00ZT00:00:00-08:002011-11-03T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>My first project, that I can talk about, with <a href="http://weareinstrument.com">Instrument</a> has just launched. <a href="http://licenselab.com">The License Lab</a> is a searchable, music catalog which can be licensed for a variety of uses. Vistors can browse and preview hundreds of available songs. Registered users can organize songs into playlists and share them with others.</p>
<p>As the focus is on the songs, the heart of the website is the music search functionality which includes: type-ahead autocomplete search, graphical tuning knobs and filtering by genre and instruments.</p>
<p>Go ahead and check it out!</p>
<p><a href="http://licenselab.com/search/"><img src="/images/licenselab.jpg"></a></p>
<p></p><p>My first project, that I can talk about, with <a href="http://weareinstrument.com">Instrument</a> has just launched. <a href="http://licenselab.com">The License Lab</a> is a searchable, music catalog which can be licensed for a variety of uses. Vistors can browse and preview hundreds of available songs. Registered users can organize songs into playlists and share them with others.</p>
<p>As the focus is on the songs, the heart of the website is the music search functionality which includes: type-ahead autocomplete search, graphical tuning knobs and filtering by genre and instruments.</p>
<p>Go ahead and check it out!</p>
<p><a href="http://licenselab.com/search/"><img src="/images/licenselab.jpg"></a></p>
<p></p>
<p>Many thanks to the following open-source projects:</p>
<ul>
<li><a href="http://flask.pocoo.org/">Flask</a></li>
<li><a href="https://github.com/sproutcore/sproutcore20">Sproutcore 2</a></li>
<li><a href="http://jplayer.org/">jPlayer</a></li>
<li><a href="https://github.com/balupton/History.js/">History.js</a></li>
</ul>
Just Launched: Metalab Design v4/2011/09/11/just-launched-metalab-v4.html2011-09-11T00:00:00ZT00:00:00-08:002011-09-11T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I'm happy to announce the latest version of the Metalab Design website is live! I worked on the initial development, interaction and code. Then <a href="http://twitter.com/#!/alibosworth">Ali Bosworth</a> and <a href="http://twitter.com/#!/jasonswebster">Jason Webster</a>, of <a href="http://www.getflow.com/">Flow</a> fame, did the hard work of polishing the animations and getting things looking great cross-browser.</p>
<p>Check it out!</p>
<p><a href="http://metalabdesign.com"><img src="/images/metalab.jpg"></a></p>
<p></p><p>I'm happy to announce the latest version of the Metalab Design website is live! I worked on the initial development, interaction and code. Then <a href="http://twitter.com/#!/alibosworth">Ali Bosworth</a> and <a href="http://twitter.com/#!/jasonswebster">Jason Webster</a>, of <a href="http://www.getflow.com/">Flow</a> fame, did the hard work of polishing the animations and getting things looking great cross-browser.</p>
<p>Check it out!</p>
<p><a href="http://metalabdesign.com"><img src="/images/metalab.jpg"></a></p>
<p></p>
<h2 id="colophon">Colophon</h2>
<p>A lot of technology went into building this site. Here's a quick rundown:</p>
<ul>
<li><a href="http://middlemanapp.com">Middleman</a> - Static development framework</li>
<li><a href="http://slim-lang.com/">Slim</a> - Whitespace-aware templating language</li>
<li><a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> - Whitespace-aware Javascript</li>
<li><a href="http://compass-style.org/">Sass and Compass</a> - Whitespace-aware CSS preprocessor</li>
<li><a href="http://transformjs.strobeapp.com/">TransformJS</a> - jQuery CSS3 Transforms</li>
</ul>
Middleman 2.0/2011/08/08/middleman-2-0.html2011-08-08T00:00:00ZT00:00:00-08:002011-08-08T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Middleman 2.0 is a huge release featuring a refactored core, a unified source folder, a unified command line, tons of new features and a <a href="http://middlemanapp.com">full documentation website</a>.</p>
<p>As always, install via RubyGems:</p>
<div class="highlight"><pre class="highlight plaintext"><code>gem install middleman
</code></pre></div>
<p>For more information, read the <a href="http://middlemanapp.com/guides/getting-started">Getting Started</a> guide.</p>
<p>Here's an overview of everything that's changed.</p>
<p></p><p>Middleman 2.0 is a huge release featuring a refactored core, a unified source folder, a unified command line, tons of new features and a <a href="http://middlemanapp.com">full documentation website</a>.</p>
<p>As always, install via RubyGems:</p>
<div class="highlight"><pre class="highlight plaintext"><code>gem install middleman
</code></pre></div>
<p>For more information, read the <a href="http://middlemanapp.com/guides/getting-started">Getting Started</a> guide.</p>
<p>Here's an overview of everything that's changed.</p>
<p></p>
<h2 id="unified-source-folder">Unified Source Folder</h2>
<p>The <code>public</code> and <code>views</code> folders have been combined into a single <code>source</code> folder which contains all of your files. Use the <a href="http://middlemanapp.com/guides/migrating">migration tool</a> to quickly update your folder structure, or manually combine the folders.</p>
<h2 id="unified-command">Unified Command</h2>
<p>The old commands, <code>mm-init</code>, <code>mm-server</code> and <code>mm-build</code>, have been combined into a single <code>middleman</code> command with the following subcommands:</p>
<ul>
<li><code>middleman init</code></li>
<li><code>middleman server</code></li>
<li><code>middleman build</code></li>
</ul>
<h2 id="new-features">New Features</h2>
<p>Here are the most interesting new features of Middleman 2.0.</p>
<h3 id="sprockets">Sprockets</h3>
<p>Sprockets is a tool for Javascript dependency management. Using Sprockets you can include other Javascript and CoffeeScript files into your scripts. </p>
<div class="highlight"><pre class="highlight plaintext"><code>//= require "another_file"
function my_javascript() {
}
</code></pre></div>
<p>Read more in the <a href="http://middlemanapp.com/guides/coffeescript-sprockets">Javascript, CoffeeScript and Sprockets</a> guide.</p>
<h3 id="dynamic-pages">Dynamic Pages</h3>
<p>Dynamic pages allow you to generate HTML for files which share a single template. </p>
<div class="highlight"><pre class="highlight plaintext"><code>["tom", "dick", "harry"].each do |name|
page "/about/#{name}.html", :proxy => "/about/template.html" do
@person_name = name
end
end
</code></pre></div>
<p>Read more in the <a href="http://middlemanapp.com/guides/dynamic-pages">Dynamic Pages</a> guide.</p>
<h3 id="pretty-urls">Pretty URLs</h3>
<p>Pretty URLs (aka Directory Indexes) let you generate folders for each HTML file in your project which results in a pretty, extension-less URL in common web-servers.</p>
<div class="highlight"><pre class="highlight plaintext"><code>activate :directory_indexes
</code></pre></div>
<p>Now <code>source/my-page.html</code> will generate <code>build/my-page/index.html</code>.</p>
<p>Read more in the <a href="http://middlemanapp.com/guides/pretty-urls">Pretty URLs</a> guide.</p>
<h3 id="yaml-frontmatter">YAML Frontmatter</h3>
<p>YAML Frontmatter lets you add in-template variables at the top of a page, which are also available in the layout, and to configure which layout the page uses.</p>
<div class="highlight"><pre class="highlight plaintext"><code>---
layout: "login"
page_name: "Login"
---
<h1><%= data.page.page_name %></h1>
</code></pre></div>
<p>The above <code>login.html.erb</code> file will be rendered using the <code>login.erb</code> layout file.</p>
<p>Read more in the <a href="http://middlemanapp.com/guides/individual-page-configuration">Individual Page Configuration</a> guide.</p>
<h3 id="livereload">LiveReload</h3>
<p>By default, LiveReload will monitor your <code>config.rb</code> file and automatically restart the Middleman server if it changes. This means, activating new features no longer requires a server restart.</p>
<p>In addition, you can have LiveReload monitor your project files as well and instruct the web-browser to reload when they change using the <a href="https://github.com/mockko/livereload#readme">LiveReload Extension</a> and the <code>--livereload</code> flag.</p>
<div class="highlight"><pre class="highlight plaintext"><code>middleman server --livereload
</code></pre></div>
<h2 id="migrating-to-2-0">Migrating to 2.0</h2>
<p>Updating old projects to Middleman 2.0 is very easy. Simply use the new <code>migrate</code> command:</p>
<div class="highlight"><pre class="highlight plaintext"><code>middleman migrate
</code></pre></div>
<p>Read more about the migration edge cases in the <a href="http://middlemanapp.com/guides/migrating">Migrating to Middleman 2.0</a> guide.</p>
<h2 id="support">Support</h2>
<p>If there are any issues or regressions, please log bugs on the <a href="https://github.com/middleman/middleman/issues">Github Issue Tracker</a>.</p>
CoffeeScript-specific Style Guide/2011/05/13/coffeescript-specific-style-guide.html2011-05-13T00:00:00ZT00:00:00-08:002011-05-13T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>First, go buy <a href="http://twitter.com/topfunky">@topfunky</a>'s new <a href="https://peepcode.com/products/coffeescript">CoffeeScript PeepCode screencast</a>. It's wonderful. All done? Okay.</p>
<p>One of the most interesting pieces of information to me, as someone who's been writing a lot of CoffeeScript and has written a ton of Javascript in the past, is the subtle tweaks to style in CoffeeScript. Here are some quick preferred styles.</p>
<p></p><p>First, go buy <a href="http://twitter.com/topfunky">@topfunky</a>'s new <a href="https://peepcode.com/products/coffeescript">CoffeeScript PeepCode screencast</a>. It's wonderful. All done? Okay.</p>
<p>One of the most interesting pieces of information to me, as someone who's been writing a lot of CoffeeScript and has written a ton of Javascript in the past, is the subtle tweaks to style in CoffeeScript. Here are some quick preferred styles.</p>
<p></p>
<p>Here's a simple piece of jQuery and a test case in plain Javascript.</p>
<div class="highlight"><pre class="highlight plaintext"><code>var elem = $("#myselector").addClass("testing");
expect(elem.id).toEqual("myselector");
</code></pre></div>
<h2 id="naive-conversion-to-coffeescript">Naive Conversion to CoffeeScript:</h2>
<p>Simply removing semi-colons and the <tt>var</tt> keyword isn't really enough.</p>
<div class="highlight"><pre class="highlight plaintext"><code>elem = $("#myselector").addClass("testing")
expect(elem.id).toEqual("myselector")
</code></pre></div>
<h2 id="lisp-y-function-grouping-calling-omitting-final-parentheses">Lisp-y Function Grouping/Calling & Omitting Final parentheses</h2>
<p>First, remember that CoffeeScript doesn't require parentheses when calling functions. These two lines are rendered identically:</p>
<div class="highlight"><pre class="highlight plaintext"><code>myfunc("string")
myfunc "string"
</code></pre></div>
<p>The second version, without parentheses, is the preferred style. The general rule is: <strong>the final method call in a chain should omit the parentheses</strong>. The original, naive conversion can become:</p>
<div class="highlight"><pre class="highlight plaintext"><code>elem = $("#myselector").addClass "testing"
expect(elem.id).toEqual "myselector"
</code></pre></div>
<p>Finally, CoffeeScript prefers to use parentheses to group methods, rather than group method parameters. This subtle difference is best illustrated by the final code. I think seeing the jQuery <tt>$</tt> without a parenthesis was off-putting at first, but I'm slowly learning to like it. The resulting code feels more math-y (or Lisp-y).</p>
<h2 id="preferred-style">Preferred Style</h2>
<div class="highlight"><pre class="highlight plaintext"><code>elem = ($ "#myselector").addClass "testing"
(expect elem.id).toEqual "myselector"
</code></pre></div>Javascript Microframeworks and The Future/2011/05/09/javascript-microframeworks-and-the-future.html2011-05-09T00:00:00ZT00:00:00-08:002011-05-09T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Last week at <a href="http://2011.jsconf.us/">jsconf</a>, <a href="http://mir.aculo.us/">Thomas Fuchs</a> continued his argument for small frameworks with the release of <a href="http://microjs.com/">MicroJS</a> which acts as a listing of tiny, single-purpose libraries. The idea being that freedom and choice, combined with optimizing for size will result in a better product than using a larger, monolithic "framework."</p>
<p>But what are we talking about when we say "framework" and what kind of applications can be built with microframeworks? </p>
<p></p><p>Last week at <a href="http://2011.jsconf.us/">jsconf</a>, <a href="http://mir.aculo.us/">Thomas Fuchs</a> continued his argument for small frameworks with the release of <a href="http://microjs.com/">MicroJS</a> which acts as a listing of tiny, single-purpose libraries. The idea being that freedom and choice, combined with optimizing for size will result in a better product than using a larger, monolithic "framework."</p>
<p>But what are we talking about when we say "framework" and what kind of applications can be built with microframeworks? </p>
<p></p>
<h2 id="the-two-types-of-html-applications">The Two Types of HTML Applications</h2>
<p>It is useful to denominate the two kinds of web applications that exist on the web. First, there is the traditional "Progressive Enhancement" apps. These use Javascript to bring additional interaction, animation and life to static HTML/CSS. The benefit is that even if the client has problems with Javascript due to some esoteric IE bug, or their phone doesn't support Javascript, that they can still interact with the site normally. The majority of large sites using jQuery act in this way. They output HTML from the backend and then jQuery adds interaction.</p>
<p>The second type is the MVC application. These frameworks start from a blank slate and use their own Views (templates) to build up the components of an app. This view layer certainly adds complexity (and lines of code) to the framework, but the result is usually a more Desktop-like user experience. The big frameworks of this type are <a href="http://blog.sproutcore.com/">Sproutcore</a>, <a href="http://cappuccino.org/">Cappuccino</a> and to a lesser degree, <a href="http://documentcloud.github.com/backbone/">Backbone.js</a>. <a href="http://skilldrick.co.uk/2011/05/javascript-and-the-end-of-progressive-enhancement/comment-page-1/">Nick Morgan argues that these types of app are the future</a>.</p>
<p>We'll need to keep in mind both types of applications as we think about optimization. What benefits one might not benefit the other and it's important to figure out the kind of app a person is talking about when they are discussing "microframeworks."</p>
<h2 id="the-problem">The Problem</h2>
<p>On the web, speed is king. Yahoo and Amazon have shown that every additional millisecond it takes to load your page has a direct result in decreasing sales. Right now, the biggest bottleneck is the way javascript loading blocks rendering in the browser. The modern web craves javascript. The browser is just an empty shell until it is scripted to life. This means the entire stack of web interactivity has to be written in Javascript and it has to be transferred to every single client who views the site. There are 3 solutions to this problem:</p>
<h3 id="the-great-cache-in-the-sky">The Great Cache in the Sky</h3>
<p>jQuery is now present on about 44% of websites. jQuery also weighs about 130k (before minification and gzipping). Which means after just a little casual browsing, you've probably downloaded jQuery several times. Browsers cache Javascript based on which domain it was downloaded from, which means your browser is actually storing 1 copy of jQuery for every site you visited that used it. And, even though you have a dozen copies already, it's going to download it again when you change to a new site.</p>
<p>The jQuery project and Google both offer to serve jQuery from their respective CDNs. These CDNs are heavily optimized to get clients a copy of jQuery as quickly as possible and they have the added bonus of using a consistent URL. That means if domaina.com and domainb.com both point to Google's copy of jQuery, then they will share the same file in the cache. This means domainb.com and all subsequent domains you visit using the Google CDN copy of jQuery won't have to be delayed waiting for jQuery to download, it will already be in the cache.</p>
<p>This is a great idea. With jQuery on 44% of the web, it's time to admit that it is the "standard library" of the web. Personally, I think Google Chrome should ship with the last dozen versions of jQuery embedded and have an option to prefer the local copies over downloading a new one. The standard library should ship with the language (in the browser). I think this will happen some day, but until then...</p>
<h3 id="load-asynchronously">Load Asynchronously</h3>
<p>There are a handful of popular new tools for loading your Javascript without blocking such as LABjs, RequireJS, StealJS, yepnope and script.js. Of course, these tools are themselves written in Javascript and must be first loaded in a blocking fashion. However, they are usually small enough that this isn't a real issue. Once the script loader is ready, it will begin pulling in your other Javascript files.</p>
<p>Asynchronous script loading works great for apps using "progressive enhancement", you can off-load almost all the Javascript, including jQuery, until later and when it finally loads the page simply gets a little nicer and interactive. However, to the user it looks like the page is loaded and they can begin interacting immediately.</p>
<p>"MVC Applications" require more complicated organization and packaging to work asynchronously. They need to know which parts of the app can be loaded later and which are needed immediately. The larger frameworks, like <a href="http://blog.sproutcore.com/">Sproutcore</a> and <a href="http://javascriptmvc.com/">JavascriptMVC</a>, have already solved this problem, but it does add some conceptual overhead.</p>
<h3 id="use-less-code">Use Less Code</h3>
<p>Simply put: send less data to the client. Sounds easy? Remember that jQuery is 130k before you even start writing your own code. This is where Thomas Fuchs (and <a href="http://microjs.com/">MicroJS</a>) come in. He argues that "frameworks" are too big and include stuff that you probably don't need. He, and others, seem purposefully vague about which framework they are rebelling against, but let's be honest: it's jQuery.</p>
<p>I've built some large applications of both the Progressive Enhancement and MVC varieties and initially I couldn't understand how a seasoned developer could possibly argue that glueing a dozen plugins together is better than a consistent application framework. Tom Dale, of the Sproutcore team, <a href="http://tomdale.net/2011/04/imagine-a-beowulf-cluster-of-javascript-frameworks/">was similarly flabbergasted</a>. While I agree with everything Tom writes in that article, I think he got hung up on terminology. Thomas Fuchs isn't arguing against Sproutcore, he is covertly arguing against jQuery. I, Thomas Reynolds (let's call this the Mexican Standoff of Javacript Toms), personally love Sproutcore and so I'll spend the rest of this article talking about replacing jQuery for Progressively Enhanced apps.</p>
<h2 id="replacing-jquery-piece-by-piece">Replacing jQuery Piece by Piece</h2>
<p>What is jQuery? Do most developers use everything available? Here are the core functions and their current file sizes:</p>
<ul>
<li>Selector Engine (33k)</li>
<li>DOM Manipulation (21k)</li>
<li>DOM Attributes (16k)</li>
<li>DOM Data Storage (9k)</li>
<li>Core Helpers and Plugin Framework: $.each, $.extend, etc (23k)</li>
<li>CSS reading/writing/animating (26k)</li>
<li>AJAX (26k)</li>
<li>Events (32k)</li>
<li>Deferreds (5k)</li>
</ul>
<p>Take a look at that list and then take a look at <a href="http://microjs.com/">MicroJS</a>. Look familiar? The majority of these micro libraries take aim at a specific portion of jQuery and attempt to do it in a smaller file size. Sound great? If you're optimizing for size it does, but let me issue a word of warning.</p>
<p>jQuery is used on 44% of the web. It is better tested, has more users and has better browser support than any other framework. It is a very well organized project which is continuing to improve and increase performance on every release. I agree with Yehuda Katz, the most important piece of any framework is the size, age and knowledge of its community. Therefore, I believe these new micro libraries will be forced to re-learn the same lessons (whether it be browser support or speed optimization) that jQuery has already solved.</p>
<h2 id="enter-ender-js">Enter Ender.js</h2>
<p><a href="http://ender.no.de/">Ender.js</a> is a framework framework. It attempts to provide a scaffold roughly shaped like jQuery with places to plugin micro libraries of your choice to fill in the features. Then Ender.js will glue those parts together and produce either a single output file or a file which loads each component asynchronously.</p>
<p>The default jQuery-like bundle is called "jeesh" and includes:</p>
<ul>
<li>Selector Engine (Qwery)</li>
<li>DOM Manipulation (Bonzo)</li>
<li>DOM Attributes (Bonzo)</li>
<li>DOM Data Storage (Bonzo)</li>
<li>Core Helpers and Plugin Framework: $.each, $.extend, etc (Underscore & Klass)</li>
<li>CSS reading/writing/animating (Émile)</li>
<li>AJAX (Reqwest)</li>
<li>Events (Bean)</li>
</ul>
<p>These pieces fit together nicely and create an almost drop-in replacement for jQuery. The edges are a little rough and you will have to rewrite some code to use it. <a href="http://www.dustindiaz.com/">Dustin Diaz</a> wrote almost all of theses default libraries, so atleast there is some consistency. As Ender.js gets more popular and more libraries are integrated which weren't written by Dustin, I expect the API will get more and more awkward. As I said above, while Dustin is a very smart person (and he's had help from Thomas Fuchs as well), neither can match jQuery's maturity, test suite and institutional knowledge.</p>
<p>Still, if you're optimizing for size on a Progressively Enhanced app, Ender.js is a nice fit. If you're optimizing for consistency and the ability to hire and bring new developers up-to-speed quickly, then you should probably stick with jQuery. </p>
<h3 id="anecdotal-evidence">Anecdotal "Evidence"</h3>
<p>I'm working on a small Progressively Enhanced portfolio site. I've completed the homepage, which uses 2 "plugins" for some slideshows and some helper functions. The initial build was with jQuery and the jQueryUI widget factory. Minified: <u>109k</u>, the majority of that being jQuery which I wasn't really using that many features of.</p>
<p>Next, I ported the site to JavascriptMVC which has a very nice dependency management system and only pulls in the pieces you need (and jQuery). The coding-style was nicer, the code modularized and the minified output was: <u>110k</u>. Makes sense, it has all of jQuery plus a 1k of glue code (Class system + Controllers). I'd really like to see JavascriptMVC (and Sproutcore too), break up jQuery into it's components and rely on those directly. Their dependency management systems can handle this and it should reduce the file system for relatively simple apps.</p>
<p>Finally, I used Ender with Bonzo, Émile, Bean, Qwery and <a href="http://extralogical.net/projects/firmin/">Firmin</a>. I had to change some stuff around and basically invent a micro controller system, but the minified output was only: <u>38k</u>.</p>
<p>So, not a surprise, when competing purely on size, microframeworks and Ender.js win. I didn't really love the code I had to write for the Ender.js version and I don't appreciate opening 4 different documentation pages to figure out the methods. Still, I'll probably stick with it because the project has only a single developer, doesn't require great IE compatibility and my primary goal is speed.</p>
<h2 id="conclusion">Conclusion</h2>
<p>People are going to keep talking about microframeworks, but I don't see jQuery's usage decreasing at all. Developer Happiness should be the primary goal, but we can't work on that until these technical issues of memory, cpu usage, gpu usage and blocking scripts are solved. They will be solved and looking back, these will feel like the dark ages.</p>
<p>Here's what I'm looking forward to in the "future." I'd like to see an end-to-end framework written in CoffeeScript. Models, Views and Controllers are the same code and the decision whether to execute code on the client or the server can be optimized. Doing the same database requests? Optimize and cache it on the backend. Rendering the same views? Do it on the backend. I'd like to see the client open a connection to the node.js backend and pipeline scripts and data as needed. If something would be faster on the client side, build it into a module and pipe it to the client on demand.</p>
<p>Honestly, I don't think we'll be waiting too much longer for such a system. A first step can be seen in Shopify's <a href="http://batmanjs.org/">batman.js</a> which made a huge splash at jsconf. Property binding is huge (also at the heart of Sproutcore) and reduces the need for jQuery's DOM manipulation hammer. Can't wait to play with it!</p>
Trigger CSS3 Animations with jQuery/2011/05/06/trigger-css3-animations-with-jquery.html2011-05-06T00:00:00ZT00:00:00-08:002011-05-06T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Did you know that jQuery 1.4.3 added a system for adding custom css attributes? For example, any normal style can be applied like so:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$(elem).css({ background: 'red' })
</code></pre></div>
<p>But what about more complicated styles? Complicated polyfills and vendor-prefixed styles? What if you could add a custom handler for <tt>border-radius</tt>? It's pretty simple and I'll show you a strawman example.</p>
<p></p><p>Did you know that jQuery 1.4.3 added a system for adding custom css attributes? For example, any normal style can be applied like so:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$(elem).css({ background: 'red' })
</code></pre></div>
<p>But what about more complicated styles? Complicated polyfills and vendor-prefixed styles? What if you could add a custom handler for <tt>border-radius</tt>? It's pretty simple and I'll show you a strawman example.</p>
<p></p>
<div class="highlight"><pre class="highlight plaintext"><code>$.cssHooks['pirateBackground'] = {
get: function(elem, computed, extra) {
return "yaarrr";
},
set: function(elem, value) {
elem.style.background = value + " url(pirates.png)";
}
};
$(elem).css({ pirateBackground: 'red' });
// elem now has a red background and the pirates.png pattern
$(elem).css('pirateBackground') == "yaarrr"
</code></pre></div>
<p>Included in David DeSandro's excellent <a href="http://isotope.metafizzy.co/">Isotope</a> library are <a href="https://github.com/desandro/isotope/blob/a2a238968347199842dd7e2d552741d5a63c90b9/jquery.isotope.js">csshooks for CSS3 scale and translate</a>. These hooks correctly use the fast 3d-transforms if available. I've included the full implementation below, but the important part is that you can include the following gist and use it like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>// Double the size using CSS3 transform scale
$(elem).css({ scale: [2] })
// Move the element 100px right and 200px down
$(elem).css({ translate: [ 100, 200 ] })
</code></pre></div>
<h2 id="demo">Demo</h2>
<div class="highlight"><pre class="highlight plaintext"><code>$('.2x').click(function() {
$('.square').css({ scale: [2] })
});
$('.1x').click(function() {
$('.square').css({ scale: [1] })
});
$('.right').click(function() {
$('.square').css({ translate: [150, 0] })
});
$('.left').click(function() {
$('.square').css({ translate: [25, 0] })
});
</code></pre></div>
<iframe width="300" height="450" src="/images/iso/demo.html"></iframe>
<h2 id="full-implementation">Full Implementation</h2>
<p>Download: <a href="https://gist.github.com/959860">https://gist.github.com/959860</a></p>
<script src="https://gist.github.com/959860.js?file=isoTransform.js"></script>
jQuery.Deferred Image Preloader/2011/05/03/jquerydeferred-image-preloader.html2011-05-03T00:00:00ZT00:00:00-08:002011-05-03T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>A little wrapper around <tt><a href="http://api.jquery.com/category/deferred-object/">jQuery.Deferred</a></tt> for an image preloader.</p>
<p></p><p>A little wrapper around <tt><a href="http://api.jquery.com/category/deferred-object/">jQuery.Deferred</a></tt> for an image preloader.</p>
<p></p>
<div class="highlight"><pre class="highlight plaintext"><code>var loadImageCache = {}
var loadImage = function(imageSrc) {
if (typeof loadImageCache[imageSrc] === "undefined") {
deferred = $.Deferred();
preloader = new Image();
preloader.onload = function() { deferred.resolve(this.src) };
preloader.onerror = function() { deferred.reject(this.src) };
preloader.src = imageSrc;
loadImageCache[imageSrc] = deferred;
}
return loadImageCache[imageSrc];
}
</code></pre></div>
<p>Requires jQuery 1.5 or newer:</p>
<div class="highlight"><pre class="highlight plaintext"><code>loadImage("http://my/image.jpg").then(function(url) {
alert(url + ' is preloaded');
});
</code></pre></div>
<p>The code will only preload each url once, you can reuse the deferred object and add additional <tt>then</tt> callbacks to that object anywhere in your code.</p>
Just Launched: PixelUnion v2/2011/04/26/just-launched-pixelunion-v2.html2011-04-26T00:00:00ZT00:00:00-08:002011-04-26T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>A project I've been working on has just launched. Check out the release post from the Metalab blog below:</p>
<blockquote>
<p><iframe src="http://player.vimeo.com/video/22873653" width="500" height="281" frameborder="0"></iframe><br><br>
About a year ago, we teamed up with <a href="http://www.45royale.com/">45royale</a> to create <a href="http://pixelunion.net">Pixel Union</a>, a premium Tumblr theme marketplace showcasing designs by some of the world...</p>
</blockquote><p>A project I've been working on has just launched. Check out the release post from the Metalab blog below:</p>
<blockquote>
<p><iframe src="http://player.vimeo.com/video/22873653" width="500" height="281" frameborder="0"></iframe><br /><br />
About a year ago, we teamed up with <a href="http://www.45royale.com/">45royale</a> to create <a href="http://pixelunion.net">Pixel Union</a>, a premium Tumblr theme marketplace showcasing designs by some of the world’s best designers. It’s been immensely successful. What began as four themes dedicated to better showcasing photographs and videos has rapidly turned into a library of nearly twenty, multipurpose themes. <br /><br />
It’s with a whole lot of pride that we announce today the launch of Pixel Union 2.0. We’ve redesigned the site, we’ve packed it full of new themes and, over the next two months, we’re going to be releasing one new theme each week. Check out <a href="http://pixelunion.net/">the new site</a> and stay tuned by following Pixel Union <a href="http://twitter.com/pixelunion">on Twitter</a><br /><br />
<strong>- <a href="http://blog.metalabdesign.com/post/4966260447/introducing-pixel-union-2-0-about-a-year-ago-we">Metalab Blog</a></strong></p>
</blockquote>
Just Give a Damn About Something/2011/04/26/just-give-a-damn-about-something.html2011-04-26T00:00:00ZT00:00:00-08:002011-04-26T00:00:00ZT00:00:00-08:00Thomas Reynolds<blockquote>
<p>I just want everyone to care about something. [...] I just think it's sad when people seem to have no passion in life.
<strong>- Marco Arment</strong></p>
</blockquote>
<blockquote>
<p>I just want everyone to care about something. [...] I just think it's sad when people seem to have no passion in life.
<strong>- Marco Arment</strong></p>
</blockquote>
CrossFit is for Nerds/2011/04/24/crossfit-is-for-nerds.html2011-04-24T00:00:00ZT00:00:00-08:002011-04-24T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Yesterday I competed in the CrossFit Games Open WOD 11.5 at CrossFit HEL (in Portland, Oregon). To the majority of my readers, those words mean absolutely nothing. So, let's start at the beginning.</p>
<h2 id="what-is-crossfit">What is CrossFit?</h2>
<p>CrossFit is an fitness program...</p><p>Yesterday I competed in the CrossFit Games Open WOD 11.5 at CrossFit HEL (in Portland, Oregon). To the majority of my readers, those words mean absolutely nothing. So, let's start at the beginning.</p>
<h2 id="what-is-crossfit">What is CrossFit?</h2>
<p>CrossFit is an fitness program that attempts to improve your skill in the broadest range of physical abilities possible. Here is a short list of activities a random CrossFit workout might contain:</p>
<ul>
<li>Bodyweight Exercises (Pullups, pushups, etc)</li>
<li>Olympic Weightlifting (Snatch, Clean & Jerk) </li>
<li>Cardio/Metabolic Conditioning (Rowing, sprinting, jump rope)</li>
<li>Gymnastic Movements (Handstands, gymnastics rings)</li>
<li>Strongman Lifting (Flipping tires, Atlas stones)</li>
<li>Strength Training (Heavy squats, benchpress)</li>
<li>Russian Kettlebell Training</li>
</ul>
<p>Here's the catch. A typical CrossFit workout (or WOD) is very short (10-15 minutes on average) and combines the above in the most devious ways possible. For example, try running as hard as you can until you're mind is fatigued, and THEN attempt a complex and technical movement like the Olympic Snatch.</p>
<h2 id="where-do-i-crossfit">Where do I CrossFit?</h2>
<p>CrossFit is essentially a start-up incubator for Gyms. The main website posts a new workout every day. If you workout from home, you can do it in your garage and share your score in the comments. Over the past 5 years, thousands of small CrossFit gyms have popped up around the world. Most of these were founded by people who were working out in their garage and then decided to quit their boring job and run their own business. Initially, they and their new clients can follow the CrossFit.com workouts, but eventually they will start creating their own.</p>
<p>Most of these gyms are run in small, garage-like buildings filled with barbells and weights. The limited space encourages small communities and direct interaction between the clients and the owners. They are the ultimate startup. Small, focused, unable to afford fancy offices, but dedicated to their small (but growing) group of users. It's hard to describe the incredibly tight sense of community at every CrossFit gym (or "box") I've visited. </p>
<p>Interestingly, these gyms/communities follow <a href="http://en.wikipedia.org/wiki/Dunbar's_number">Dunbar's number</a> pretty closely. About the time a gym nears 150 members, usually some segment will break off and start another gym to return the community to a smaller, more focused state.</p>
<h2 id="stats-charts-data-points">Stats, Charts & Data-points</h2>
<p>Finally, here is the reason why CrossFit is for Nerds. Every workout has a score and participants are encouraged to track every possible metric. And because there are so many possible workouts and combinations of exercises, there are a dizzying number of data-points. It also provides a sense of progress. If you're trying to diet or hitting the treadmill at the gym, how do you know it's working? Does anyone try to speed-up their running or do they just set the timer for 1 hour and wait it out? With CrossFit you can say "this week I lifted 110 pounds and last week it was only 100 pounds." That's a 10% increase in a week! And I personally love looking at all the little improvements.</p>
<p>Which brings me to the CrossFit Games and the Open WODs. Every year, CrossFitters around the world compete to discover who is the "fittest." Usually, there are formalized competitions in each region and eventually these boil down to a single multi-day competition in California somewhere. I highly suggest <a href="http://games2010.crossfit.com/blog/videos/2010/">taking a look at the videos from last year</a>, which were recorded in HD and streamed live over the 3-day competition (CrossFit has a very solid IT team).</p>
<p>This year, there were nearly 30,000 registered athletes, so HQ (the folks who run CrossFit) decided that the first round of competition would take place were CrossFit is strongest: in the garage, in the box, and in the gyms. This year, there are 6 WODs (1 per week) and competitors can either complete them in a CrossFit gym (any CrossFit gym in the world) or anywhere they have access to a video camera. Athletes can record their workout and upload to the site for judging (I told you their IT team was badass).</p>
<p>First, this further enhances the community by creating thousands of mini-competitions. Second, this is all happening live on the <a href="http://games.crossfit.com/">CrossFit Games website</a>, which means there is a metric fuckton of data. Check it out:</p>
<p><a href="http://games.crossfit.com/content/scoreboard-men"><img src="/images/scoreboard.jpg"></a></p>
<p>Now, I'm not a statistician, but <a href="http://xfit2011.blogspot.com/">this guy is</a>. Drink in the data:</p>
<ul>
<li><a href="http://xfit2011.blogspot.com/2011/04/womens-body-weight-performances-wk1-and.html">Women's body weight and it's effect on rank</a></li>
<li><a href="http://xfit2011.blogspot.com/2011/04/ideal-crossfit-weight-for-men.html">Ideal men's weight</a></li>
<li><a href="http://xfit2011.blogspot.com/2011/04/age-and-crossfit-open-performance.html">Age vs Performance</a></li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>In my opinion, working out isn't about being some roided-out Jersey Shore reject. It's about improving yourself one little data-point at a time. It can <a href="http://www.uclahealth.org/body.cfm?id=502&action=detail&ref=134">increase productivity, while decreasing stress</a>. It provides a sense of community and it will slowly give you more and more "dumb human tricks" like handstands.</p>
<h2 id="footnotes">Footnotes</h2>
<ul>
<li>Speaking of fitness nerds, I highly recommend Tim Ferriss' <a href="http://www.fourhourbody.com/">The 4-Hour Body</a>.</li>
<li>I'm currently one of the 15 worst CrossFitters in the Northwest, according to my current place in the competition. No worries, it's not about winning. I'm getting higher scores of workouts and exercises than I ever had before!</li>
<li>I ran into <a href="https://twitter.com/#!/justin_lewis">Justin Lewis</a>, a principle at <a href="http://www.weareinstrument.com/">Instrument</a>, at my last WOD. He remarked on how badass it was that I was competing in my jQuery Conference shirt :)</li>
<li>Here are some other nerds I CrossFit with:
<ul>
<li><a href="Designer/Dev">@pixelmatrix</a></li>
<li><a href="Flash%20Guru">@heavilyinvolved</a></li>
<li><a href="iOS%20Master">@matt_tuzzolo</a></li>
<li><a href="iOS%20dude,%20Clean%20&%20Jerk%20monster">@cschep</a></li>
</ul></li>
</ul>
Branching Out, Opening Up and Publishing More/2011/04/23/branching-out-opening-up-and-publishing-more.html2011-04-23T00:00:00ZT00:00:00-08:002011-04-23T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>It's been 2 years and 1 month since I started writing seriously here. I've enjoyed it very much, but I've also focused almost exclusively on technical articles and the promotion of my own open source software. While I am proud of these articles, it...</p><p>It's been 2 years and 1 month since I started writing seriously here. I've enjoyed it very much, but I've also focused almost exclusively on technical articles and the promotion of my own open source software. While I am proud of these articles, it can get a bit dry, can't it?</p>
<p>Over the same time span, I've watched <a href="http://marco.org">Marco Arment</a> slowly branch out from a similarly technical (or Apple news focused) blog. These days his blog has a few personal stories, lots of quick links & quotes, his thoughts on the current news articles and longer researched posts.</p>
<p>That has inspired me a lot. I often get discouraged when I discover I am not the first person to do or write about something. If a topic or thought is in Google, why should I repeat the common opinion? But you know what? This is my site. It is (and will be) a catalog of my opinions, work and thoughts. So from now on, this blog becomes personal. Expect a lot more one-line posts linking to other sites. Expect some off-topic posts about things I love, like mixing cocktails or Crossfit. Expect my, probably redundant, voice echoing the thoughts of the day. Don't expect comments, I'll probably turn those off on everything expect open source projects I need to do support for. Expect a more personal voice.</p>
<p>See you soon,</p>
<p>-Thomas Reynolds</p>
Middleman v1.1/2011/04/15/middleman-v11.html2011-04-15T00:00:00ZT00:00:00-08:002011-04-15T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><strong>Update: <a href="/2011/08/08/middleman-2-0.html">Middleman version 2.0 has been released</a></strong></p>
<p>It's been a long time since <a href="/2009/10/22/middleman">I introduced Middleman on this blog</a> in 2009. Since then, RubyGems reports that there have been 27,518 downloads, <a href="https://github.com/middleman/middleman/contributors">several great contributors</a> to the source code and even a mention in a printed book.</p>
<p>I've been working hard on documentation as it was the most requested feature from the <a href="/2011/02/06/future-of-middleman-survey">"Future of Middleman Survey"</a>. I'm a developer and I'm sorry to admit that my first documentation target is the code and generated documentation. Available at: <a href="http://middlemanapp.com/"></a><a href="http://middlemanapp.com/">http://middlemanapp.com/</a></p>
<p>I know, I need better, more tutorial-style written documentation for actual people. I'll be working on it as time permits, but I'd also love any assistance.</p>
<p>So, let's talk about the version 1.1. Originally, I planned to make 1.1 a simple update to use the latest features from Sass 3.1. However, as Sass took forever to actually ship, I tweaked, massaged and added a lot more stuff to the platform. Now, I'm releasing even though Sass 3.1 isn't out. <i>C'est la vie</i>. So, here's what's new:</p>
<ul>
<li>Now running on Sinatra 1.2</li>
<li>Sass 3.1 beta & Compass 0.11 beta</li>
<li>Feature/Extension API (<a href="#features">see below</a>)</li>
<li>Simple YAML-based data for reusable content (<a href="#yaml">see below</a>)</li>
<li>mm-build & mm-init now use Thor for templating</li>
<li>Lorem Ipsum & placehold.it helpers (<a href="#lorem">see below</a>)</li>
<li>mm-init templates, including HTML5 Boilerplate (<a href="#boilerplate">see below</a>)</li>
<li>Built-in Rack config.ru for easy running on Heroku or under Pow (see below)</li>
<li>Experimental JRuby support</li>
<li>RubyGems-test support</li>
<li>Using Bundler for packaging</li>
</ul>
<p></p><p><strong>Update: <a href="/2011/08/08/middleman-2-0.html">Middleman version 2.0 has been released</a></strong></p>
<p>It's been a long time since <a href="/2009/10/22/middleman">I introduced Middleman on this blog</a> in 2009. Since then, RubyGems reports that there have been 27,518 downloads, <a href="https://github.com/middleman/middleman/contributors">several great contributors</a> to the source code and even a mention in a printed book.</p>
<p>I've been working hard on documentation as it was the most requested feature from the <a href="/2011/02/06/future-of-middleman-survey">"Future of Middleman Survey"</a>. I'm a developer and I'm sorry to admit that my first documentation target is the code and generated documentation. Available at: <a href="http://middlemanapp.com/"><a href="http://middlemanapp.com/">http://middlemanapp.com/</a></a></p>
<p>I know, I need better, more tutorial-style written documentation for actual people. I'll be working on it as time permits, but I'd also love any assistance.</p>
<p>So, let's talk about the version 1.1. Originally, I planned to make 1.1 a simple update to use the latest features from Sass 3.1. However, as Sass took forever to actually ship, I tweaked, massaged and added a lot more stuff to the platform. Now, I'm releasing even though Sass 3.1 isn't out. <i>C'est la vie</i>. So, here's what's new:</p>
<ul>
<li>Now running on Sinatra 1.2</li>
<li>Sass 3.1 beta & Compass 0.11 beta</li>
<li>Feature/Extension API (<a href="#features">see below</a>)</li>
<li>Simple YAML-based data for reusable content (<a href="#yaml">see below</a>)</li>
<li>mm-build & mm-init now use Thor for templating</li>
<li>Lorem Ipsum & placehold.it helpers (<a href="#lorem">see below</a>)</li>
<li>mm-init templates, including HTML5 Boilerplate (<a href="#boilerplate">see below</a>)</li>
<li>Built-in Rack config.ru for easy running on Heroku or under Pow (see below)</li>
<li>Experimental JRuby support</li>
<li>RubyGems-test support</li>
<li>Using Bundler for packaging</li>
</ul>
<p></p>
<p>Let's take a look at some of these in depth.</p>
<p><a name="features"></a></p>
<h2 id="feature-extension-api">Feature/Extension API</h2>
<p>All the "features" of Middleman can be enabled or disabled from your <tt>config.rb</tt> file. These features are now all using the Sinatra extension API which means it is very easy to add your own features or include features from other RubyGems. Here is an example Feature:</p>
<div class="highlight"><pre class="highlight plaintext"><code># In your config.rb or an external file/gem required in config.rb
module MyMiddlemanFeature
class << self
def registered(app)
app.helpers MyMiddlemanFeature::Helpers
end
alias :included :registered
end
module Helpers
def my_custom_helper
"Hello World"
end
end
end
# In config.rb
activate MyMiddlemanFeature
</code></pre></div>
<p>The above extension will add some helpers to your project. Of course, there is already the shortcut <tt>helpers</tt> block available in <tt>config.rb</tt>, but this extension could live anywhere. If you have some reusable components or business logic, you can place those in a gem, share it within your company and include it in <tt>config.rb</tt>. I use this for a custom grid-system I reuse on a lot of projects.</p>
<p>Of course, existing Sinatra extensions should work too. <a href="http://www.sinatrarb.com/extensions-wild.html">See more here</a>.</p>
<p><a name="yaml"></a></p>
<h2 id="yaml-data-api">YAML Data API</h2>
<p>Heavier static systems like Nanoc have a robust system for separating data from your HTML. This is great for sharing content across pages or having simpler files which content-focused co-workers can update without touching HTML. It's not documented, but because Middleman runs on Sinatra, it's possible to open database connections and pull data in that way already, but that's a bit must. Middleman 1.1 comes with a simple data API. Here's how it works:</p>
<ol>
<li>Create a folder in the root of your project named <tt>data</tt></li>
<li>Create as many <tt>.yml</tt> YAML files as you want</li>
<li>Their contents will be made available in your templates as <tt>data["filename"]</tt></li>
</ol>
<p>For example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>// In PROJECT_ROOT/data/people.yml
friends:
- tom
- dick
- harry
// In my template
%h1 Friends
%ul
- data.people.friends.each do |f|
%li= f
</code></pre></div>
<p><a name="lorem"></a></p>
<h2 id="lorem-ipsum-placehold-it-helpers">Lorem Ipsum & Placehold.it helpers</h2>
<p>The <a href="https://github.com/blahed/frank">Frank project</a>, a static tool also inspired by Sinatra, has a wonderful set of helpers for generating random text content and placeholder images. I'm adapted this code for Middleman (god bless the MIT license). The API is as follows:</p>
<div class="highlight"><pre class="highlight plaintext"><code>lorem.sentence # returns a single sentence
lorem.words 5 # returns 5 individual words
lorem.word
lorem.paragraphs 10 # returns 10 paragraphs
lorem.paragraph
lorem.date # accepts a strftime format argument
lorem.name
lorem.first_name
lorem.last_name
lorem.email
</code></pre></div>
<p>And to use placeholder images:</p>
<div class="highlight"><pre class="highlight plaintext"><code>lorem.image('300x400')
#=> http://placehold.it/300x400
lorem.image('300x400', :background_color => '333', :color => 'fff')
#=> http://placehold.it/300x400/333/fff
lorem.image('300x400', :random_color => true)
#=> http://placehold.it/300x400/f47av7/9fbc34d
lorem.image('300x400', :text => 'blah')
#=> http://placehold.it/300x400&text=blah
</code></pre></div>
<p><a name="boilerplate"></a></p>
<h2 id="new-project-templates-html5-boilerplate">New Project Templates (HTML5 Boilerplate)</h2>
<p>I've abstracted the templates used in <tt>mm-init</tt> so that it is easy to add new ones, but right now those templates have to live in the Middleman gem to work. In the future, I'll add support for extra templates in external gems or somewhere on the local machine like <tt>~/.middleman</tt>. For now, enjoy the new template option, the wonderful <a href="http://html5boilerplate.com/">HTML5 Boilerplate</a>. It is used like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$ mm-init my_boilerplate_project --template=html5
create my_boilerplate_project/config.rb
create my_boilerplate_project/public
create my_boilerplate_project/public/404.html
create my_boilerplate_project/public/apple-touch-icon.png
create my_boilerplate_project/public/crossdomain.xml
create my_boilerplate_project/public/css/handheld.css
create my_boilerplate_project/public/css/style.css
create my_boilerplate_project/public/favicon.ico
create my_boilerplate_project/public/humans.txt
create my_boilerplate_project/public/images/.gitignore
create my_boilerplate_project/public/index.html
create my_boilerplate_project/public/js/libs/dd_belatedpng.js
create my_boilerplate_project/public/js/libs/jquery-1.5.0.js
create my_boilerplate_project/public/js/libs/jquery-1.5.0.min.js
create my_boilerplate_project/public/js/libs/modernizr-1.6.min.js
create my_boilerplate_project/public/js/mylibs/.gitignore
create my_boilerplate_project/public/js/plugins.js
create my_boilerplate_project/public/js/script.js
create my_boilerplate_project/public/robots.txt
create my_boilerplate_project/views
</code></pre></div>
<h2 id="rack-support-by-default">Rack-support by Default</h2>
<p>Finally, a very simple Rack <tt>config.ru</tt> file is included in the default template. It's contents are:</p>
<div class="highlight"><pre class="highlight plaintext"><code>require 'rubygems'
require 'middleman'
run Middleman::Server
</code></pre></div>
<p>This allows Middleman to easily run on a Heroku instance or under 37Signal's new <a href="http://pow.cx/">Pow webserver</a>.</p>
<h2 id="installation">Installation</h2>
<p>As easy as ever:</p>
<div class="highlight"><pre class="highlight plaintext"><code>gem install middleman
</code></pre></div>
<p>Please direct all questions and bugs to Github:
<a href="https://github.com/middleman/middleman"><a href="https://github.com/middleman/middleman">https://github.com/middleman/middleman</a></a></p>
Adjustable Animations with Sliders/2011/04/13/adjustable-animations-with-sliders.html2011-04-13T00:00:00ZT00:00:00-08:002011-04-13T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Quick question? What is the perfect amount of time to animate an element on a page? jQuery defaults to 400ms, which sounds short, but ends up being pretty perfect for most occasions. It gets the job done and then it gets out of the way. </p>
<p>However, it shouldn't surprise you that designers have opinions on motion and we're just now reaching the point where motion is becoming important on the web. </p><p>Quick question? What is the perfect amount of time to animate an element on a page? jQuery defaults to 400ms, which sounds short, but ends up being pretty perfect for most occasions. It gets the job done and then it gets out of the way. </p>
<p>However, it shouldn't surprise you that designers have opinions on motion and we're just now reaching the point where motion is becoming important on the web. Back in the day, 37Signals would just set the background of an element to yellow and call it a day. If you take a look at <a href="http://getflow.com">Flow</a>, you'll see some very designed motion. Closing a task results in the checkbox animating to a state, then it picks up and animates along an arc to drop into the "completed" box in your sidebar.</p>
<p>Okay, so, what's the perfect timing for that animation? There are tools for prototyping motion, most notably Adobe Flash, but usually you're designer is going to want to look over your shoulder and tweak the animation until it "feels right."</p>
<p>The solution is something I've seen friends in the old-school OpenGL motion build into their dev workflow. Every time they've got a motion variable (duration, size, color, wobble, randomness, etc), they setup a control to adjust the variable. Who wants to change integers in OpenGL and recompile? Like so many things, it's time to re-learn tricks from the desktop world if we're going to move forward.</p>
<p>Here, below is the most basic example. I have a square that is animating back and forth and changing width and height. In a more complicated example, it might arc or have several animations queued up. I've used a shiny new HTML5 <tt>range</tt> element and each time the animation loops, it checks the value to define it's duration.</p>
<div class="highlight"><pre class="highlight plaintext"><code><!-- Ranges from 0-4000, with integer steps. Defaults to 400 -->
<input type="range" min="0" max="4000" step="1" value="400">
</code></pre></div>
<p>The animation looks like:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$elem.animate({ left: 480, width: 100, height: 100 }, {
duration: $("input[type=range]").val()
});
</code></pre></div>
<p>Simple enough. If I were implementing an animation, vaguely defined in a PSD, I'd setup something like this and then let the designer have a field day. Developers love round numbers and math, but the "best" timing may actually be the combination of an esoteric easing function and a duration of 962.</p>
<p>This gets even more interesting if you're using something like WebGL, Three.js or Box2d.js. Adjust physics engines on the fly makes finding the perfect balance a cinch.</p>
<h1 id="demo">Demo</h1>
<p>Here we have a little animating square, a slider to control the duration and a bunch of easing options. Go ahead, play around and find the "sweet spot."</p>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script>
$.getScript("/javascripts/jquery.easing.1.3.js", function() {
$(function($) {
$(".range").change(function() {
$(".speed").text($(this).val());
}).change();
function getEasing() {
return $(".easing").val();
}
function getSliderValue() {
return parseInt($(".range").val(), 10);
}
function animateRight() {
$(".box").stop().animate({ left: 380, width: 100, height: 100 }, {
duration: getSliderValue(),
easing: getEasing(),
complete: function() {
setTimeout(animateLeft, 750);
}
});
}
function animateLeft() {
$(".box").stop().animate({ left: 0, width: 50, height: 50 }, {
duration: getSliderValue(),
easing: getEasing(),
complete: function() {
setTimeout(animateRight, 750);
}
});
}
animateRight();
});
});
</script>
<div class="demo" style="width: 600px; height: 300px; position: relative; overflow: hidden;">
Duration: <span class="speed"></span><br />
<input class="range" type="range" min="0" max="4000" step="1" value="1400" style="width: 300;" /><br />
Easing: <select class="easing">
<option>swing</option>
<option>easeInQuad</option>
<option>easeOutQuad</option>
<option>easeInOutQuad</option>
<option>easeInCubic</option>
<option>easeOutCubic</option>
<option>easeInOutCubic</option>
<option>easeInQuart</option>
<option>easeOutQuart</option>
<option>easeInOutQuart</option>
<option>easeInQuint</option>
<option>easeOutQuint</option>
<option>easeInOutQuint</option>
<option>easeInSine</option>
<option>easeOutSine</option>
<option>easeInOutSine</option>
<option>easeInExpo</option>
<option>easeOutExpo</option>
<option>easeInOutExpo</option>
<option>easeInCirc</option>
<option>easeOutCirc</option>
<option>easeInOutCirc</option>
<option>easeInElastic</option>
<option>easeOutElastic</option>
<option>easeInOutElastic</option>
<option>easeInBack</option>
<option>easeOutBack</option>
<option>easeInOutBack</option>
<option>easeInBounce</option>
<option selected>easeOutBounce</option>
<option>easeInOutBounce</option>
</select><br />
<div class="box" style="width: 50px; height: 50px; background: red; position: absolute; top: 75px; left: 10px;"></div>
</div>
Announcing: WouldHire.com/2011/04/08/announcing-wouldhirecom.html2011-04-08T00:00:00ZT00:00:00-08:002011-04-08T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>This year at SXSW I was either involved in or overheard the same conversation several times. </p>
<div class="highlight"><pre class="highlight plaintext"><code>Person A: So where do you work now?
Person B: Just started a new job at Company X.
Person A: Ah, man, you should have told me you were looking.
I'd love to work with you.
</code></pre></div>
<p>Somehow, despite all of our constant communication and over-sharing on Twitter, we still like to avoid "serious" conversations about jobs, salaries and what it would take to get your friend/buddy/idol to work with you. So, to scratch this itch, <a href="http://pixelmatrixdesign.com/">Josh Pyles</a> and I spent the last weekend putting together <a href="http://wouldhire.com">WouldHire.com</a>.</p>
<p></p><p>This year at SXSW I was either involved in or overheard the same conversation several times. </p>
<div class="highlight"><pre class="highlight plaintext"><code>Person A: So where do you work now?
Person B: Just started a new job at Company X.
Person A: Ah, man, you should have told me you were looking.
I'd love to work with you.
</code></pre></div>
<p>Somehow, despite all of our constant communication and over-sharing on Twitter, we still like to avoid "serious" conversations about jobs, salaries and what it would take to get your friend/buddy/idol to work with you. So, to scratch this itch, <a href="http://pixelmatrixdesign.com/">Josh Pyles</a> and I spent the last weekend putting together <a href="http://wouldhire.com">WouldHire.com</a>.</p>
<p></p>
<p>The site is very simple. Go to the homepage, enter your twitter username and see if anyone has expressed interest in working with you. If they have and you're looking for a new gig, it's up to you two to figure it out.</p>
<p><a href="http://wouldhire.com"><img src="/images/WouldHire-homepage.png" alt="Homepage"></a></p>
<p><a href="http://who.wouldhire.com/pixelmatrix"><img src="/images/WouldHire-who.png" alt="Who WouldHire @pixelmatrix"></a></p>
<p>Finally, if you're looking to let someone know that you're interested, simply login (using Twitter) and add some Twitter usernames to your "dream team."</p>
<p><img src="/images/WouldHire-admin.png" alt="WouldHire Admin"></p>
<p>Pretty cool, eh? Please check it out, email me your ideas/comments and hopefully this will help someone, somewhere end up with their dream job.</p>
Model and Data Store: JavascriptMVC/2011/02/18/model-and-data-store-javascriptmvc.html2011-02-18T00:00:00ZT00:00:00-08:002011-02-18T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Last time, <a href="/2011/01/25/client-side-mvcs-part-1-the-model-and-data-store.html">I wrote about client-side models</a> in an abstract way using plain Javascript. Understanding the purpose of models and encapulating model-specific functionality is important for code organization, but you will end up having to write a bunch...</p><p>Last time, <a href="/2011/01/25/client-side-mvcs-part-1-the-model-and-data-store.html">I wrote about client-side models</a> in an abstract way using plain Javascript. Understanding the purpose of models and encapulating model-specific functionality is important for code organization, but you will end up having to write a bunch of code to support your models. For example, converting and parsing JSON values, figuring out how and when to push changes to the server and client-side validations.</p>
<p>Now, you might think you are a very smart developer and you could write Twitter in a weekend and that frameworks and libraries are bloat that you—oh perfect developer—don't need. Well, you're wrong.</p>
<p>There is serious value in frameworks which have been around and in use for several years. The accumulated knowledge of hundreds of esoteric browser bugs and issues will save your ass when it's down to the wire and suddenly your site isn't working in IE8 on Windows XP with Cleartype disabled.</p>
<h2 id="javascriptmvc-model">JavascriptMVC $.Model</h2>
<p>Compared to the Sencha and Sproutcore's robust data packages, JavascriptMVC's is somewhat simple. It embraces jQuery's AJAX methods and even places its classes on the jQuery "$" object. First, let's take a look at a model who's only goal is to represent a client-side object. We'll use it for organizing data and generating DOM elements, but save backend connectivity for later.</p>
<div class="highlight"><pre class="highlight plaintext"><code>// Setup the model definition
$.Model.extend("Project",
{
// Static methods.
// The following will appear as Project.fooBar()
fooBar: function() {
// Do something;
}
},
{
// Instance methods
// The following will appear as myProject.similarProjects()
similarProjects: function() {
// Loop over all projects and find similar ones
}
});
// Create an instance
var myProject = new Project({
name: "Project 1",
owner: "me"
});
// Get some values
console.debug("My name is: " + myProject.name);
</code></pre></div>
<p>As you can see, the attributes defined on the model are relatively free-form. Simply pass them into the constructor and they'll be accessible in the model instance and to your instance methods. However, if you want to use some additional magic such an custom getters, setters and attribute conversions, you're going to need to use a jQuery-style proxy method to get and set attributes. Unsurprisingly, that method is called <tt>attr</tt>. Let's look at the same model, but with a helper method added.</p>
<div class="highlight"><pre class="highlight plaintext"><code>$.Model.extend("Project",
{
},
{
setTitle: function(newTitle) {
// Optionally set some other attribute at the same time,
// like a subtitle.
// Makes sure the title is always uppercase.
return newTitle.toUpperCase();
}
});
var myProject = new Project();
myProject.attr("title", "my title");
console.debug("My title is: " + myProject.attr("title")); // MY TITLE
</code></pre></div>
<p>Now, whenever you use the <tt>attr</tt> helper to get or set the title, it will run through the <tt>setTitle</tt> method first. Alternatively, you could setup this conversion at the class level.</p>
<div class="highlight"><pre class="highlight plaintext"><code>$.Model.extend("Project",
{
attributes: {
title: 'uppercase'
},
convert: function(original) {
return original.toUpperCase();
}
},
{
});
</code></pre></div>
<p>In JavascriptMVC, you can bind models to DOM nodes. What this let's us do is to accept a click on a button, find the model it corresponds to and perform an action easily. I'll go into this more when talking about the JavascriptMVC view layer.</p>
<h2 id="model-with-json-apis">$.Model with JSON APIs</h2>
<p>Unless you're app uses something like LocalStorage to keep all the client data in the visitor's browser, you'll probably want to pull model data from a backend server. $.Model makes this shockingly easy in the basic case. Behold:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$.Model.extend('Project',
{
findAll: "projects",
findOne: "projects/{id}",
create: "projects",
destroy: "projects/{id}",
update: "projects/{id}"
},
{
});
</code></pre></div>
<p>Now you can interact with your server-side models very easily. For example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>// Let's assume this returns the following JSON from "/projects":
// [{ id: 1, name: "My Project" }]
Project.findAll({ }, function(allProjects) {
// An array of Project models
allProjects;
});
// Let's assume this returns the following JSON from "/projects/1":
// { id: 1, name: "My Project" }
Project.findOne({ id: 1 }, function(myProject) {
// Returns "My Project
myProject.attr('name');
// Triggers HTTP PUT to "projects/1"
myProject.update('name', 'New name');
// Triggers HTTP DELETE to "projects/1"
myProject.destroy();
});
// Create new instance
var newProject = new Project({ name: "New Project" });
// Triggers HTTP POST to "/projects"
newProject.save();
</code></pre></div>
<p>Awesomely simple. Keep in mind that the <tt>findAll</tt>, <tt>findOne</tt>, <tt>create</tt>, <tt>destroy</tt> and <tt>update</tt> class methods can be defined by you to handle any kind of backend service. If you need to parse XML or work with a bizarre API you don't control, this is where you'd do it.</p>
Aaron Quint on Javascript Hash URLs/2011/02/11/aaron-quint-on-javascript-hash-urls.html2011-02-11T00:00:00ZT00:00:00-08:002011-02-11T00:00:00ZT00:00:00-08:00Thomas Reynolds<blockquote>
<p>Sammy and the ‘#’ are for applications. It provides a way to maintain state in a world where you can require JavaScript and even require the presence of certain browsers. If you’re an application, that requires login/signup you can make a number of...</p>
</blockquote><blockquote>
<p>Sammy and the ‘#’ are for applications. It provides a way to maintain state in a world where you can require JavaScript and even require the presence of certain browsers. If you’re an application, that requires login/signup you can make a number of demands of your users. You also probably dont even want the crawlability. You’re using ‘#’ to maintain state for a specific user in a specific session.</p>
<p>Outside of the world of the ‘application’ you really, really shouldn’t rely on JavaScript being there for your site to work (at least at a basic level).<br />
<strong>- Aaron Quint</strong></p>
</blockquote>
<p>Checkout the <a href="http://www.quirkey.com/blog/2011/02/10/ish/">full article</a> on <a href="http://twitter.com/aq">@aq</a>'s blog.</p>
<p>I'm definitely a fan of dynamic javascript applications which utilize the #! method to support the back-button and deep linking. I wrote a <a href="http://secondstory.github.com/secondstoryjs-router/">Sammy-inspired Javascript URL router for JavascriptMVC</a> and I agree with Aaron. Dynamic URLs for applications, static sites for traditional content. Where Gawker went wrong with their redesign is by confusing the two.</p>
Andy Rutledge on Kickstarter/2011/02/08/andy-rutledge-on-kickstarter.html2011-02-08T00:00:00ZT00:00:00-08:002011-02-08T00:00:00ZT00:00:00-08:00Thomas Reynolds<blockquote>
<p>By taking the professional-to-client approach for what should be a merchant-to-customer context, Mr. Chimero has abdicated ownership of his idea/genius and the results that will come of it. Having bought and paid for it, the collective investors now...</p>
</blockquote><blockquote>
<p>By taking the professional-to-client approach for what should be a merchant-to-customer context, Mr. Chimero has abdicated ownership of his idea/genius and the results that will come of it. Having bought and paid for it, the collective investors now own his genius in this project. By selling out first before he created the product he promises, he’s now working for the investors instead of working for himself.<br />
<strong>- Andy Rutledge</strong></p>
</blockquote>
<p><a href="http://www.andyrutledge.com/profit-lies-theft-and-idiocy.php">Read the full article</a>, it's great. I agree with Andy, but let me say that I'm a huge fan of Frank's. I love his writing and am very happy he'll have the opportunity to focus on a project he loves. My opinions about Kickstarter revolve around it's model, not the artists who are able to follow their dreams because of it.</p>
Future of Middleman Survey/2011/02/06/future-of-middleman-survey.html2011-02-06T00:00:00ZT00:00:00-08:002011-02-06T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I've created a brief survey about <a href="http://middlemanapp.com">Middleman</a>. If you've used the project, I would love your input. Thanks!</p>
<p><a href="http://www.surveymonkey.com/s/5P9B92Q"><a href="http://www.surveymonkey.com/s/5P9B92Q">http://www.surveymonkey.com/s/5P9B92Q</a></a></p>
<p>I've created a brief survey about <a href="http://middlemanapp.com">Middleman</a>. If you've used the project, I would love your input. Thanks!</p>
<p><a href="http://www.surveymonkey.com/s/5P9B92Q"><a href="http://www.surveymonkey.com/s/5P9B92Q">http://www.surveymonkey.com/s/5P9B92Q</a></a></p>
Model and Data Store: Sencha/2011/01/28/model-and-data-store-sencha.html2011-01-28T00:00:00ZT00:00:00-08:002011-01-28T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I'm in the process of writing up how the Model and Data Store works in JavascriptMVC and Sproutcore. In the mean-time, check out Ed Spencer's fantastic article about the ExtJS/Sencha Data Package on the official Sencha blog.</p>
<p><a href="http://www.sencha.com/blog/ext-js-4-anatomy-of-a-model/">http://www.sencha.com...</a></p><p>I'm in the process of writing up how the Model and Data Store works in JavascriptMVC and Sproutcore. In the mean-time, check out Ed Spencer's fantastic article about the ExtJS/Sencha Data Package on the official Sencha blog.</p>
<p><a href="http://www.sencha.com/blog/ext-js-4-anatomy-of-a-model/">http://www.sencha.com/blog/ext-js-4-anatomy-of-a-model/</a></p>
<p><img src="http://www.sencha.com/assets/images/20110126-model.png" style="padding: 0; border: 0; box-shadow: white 0 0 0; -webkit-box-shadow: white 0 0 0; -moz-box-shadow: white 0 0 0; -o-box-shadow: white 0 0 0;" width=580 /></p>
Client-side MVC+S Part 1: The Model and Data Store/2011/01/25/client-side-mvcs-part-1-the-model-and-data-store.html2011-01-25T00:00:00ZT00:00:00-08:002011-01-25T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Like it or not, the Apple iPhone and iPad have changed people’s expectations for how apps and even websites should behave. As designers begin porting native application concepts to the web, we front-end developers have got to become more organized...</p><p>Like it or not, the Apple iPhone and iPad have changed people’s expectations for how apps and even websites should behave. As designers begin porting native application concepts to the web, we front-end developers have got to become more organized and application-oriented to survive. More and more, websites should be categorized as "simple applications." Building sites as a collection of jQuery plugins is a bad idea in this new, complex web-application world.</p>
<p>Maybe you’ve heard about <a href="http://www.sproutcore.com/">Sproutcore</a>, <a href="http://cappuccino.org/">Capuccino</a>, <a href="http://www.sencha.com/products/touch/">Sencha Touch</a>, <a href="http://javascriptmvc.com/">JavascriptMVC</a> or <a href="http://documentcloud.github.com/backbone/">Backbone</a>. These frameworks provide a full application stack for the web and they are all based on the Model-View-Controller pattern. Please note, if you are familiar with server-side MVC, you should be aware that client-side MVC is slightly different. Even if you aren’t interested in learning a whole new framework, you will definitely need the MVC pattern to build modern web sites so I’m going to talk about what each piece of the pattern looks like on the client-side.</p>
<h2 id="model">Model</h2>
<p>Client-side models have two important pieces. First is the traditional model which has some attributes (like name, date updated, etc) and allows you to update those attributes. The generic Javascript object handles this role perfectly. If you’re getting data from JSON, you’re getting a JavaScript Object Model (JSOM?) of the data. For example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>{ name: "Object 1", updated_at: "2011/01/25" }
</code></pre></div>
<p>At some point you will want to have some helper functions that are related to each model. Maybe you want to get the name in all caps. A simple Javascript Class for this model would look like:</p>
<div class="highlight"><pre class="highlight plaintext"><code>var Project = function(attrs) {
this.name = attrs.name;
}
Project.prototype.allCapsName = function() {
return this.name.toUpperCase();
}
var myProject = new Project("mine");
myProject.allCapsName() => "MINE"
</code></pre></div>
<p>So far, so good and we’re still entirely in the realm of plain old Javascript. Each of the popular frameworks mentioned above take the approach of wrapping a data object in a class to allow custom methods, but if all you need is a way of organizing your code without a library, this should be good enough.</p>
<h2 id="data-store">Data Store</h2>
<p>The second part of the Model is the Data Store/Source. At some point, you will need a way of getting models from a server, working with a list of models and sending updates to the server. If you have each model handle communication with the server itself, you will end up with a lot of duplication. So let’s make a data store that gets a list of project using a plain javascript model from above. I’m going to use jQuery for the AJAX portion because </p>
<div class="highlight"><pre class="highlight plaintext"><code>var ProjectList = {
all: [],
fetch: function(myCallback) {
var self = this;
$.get("/projects.json", function(data) {
for (var i = 0; i < data.length; i++) {
var model = new Project(data[i]);
self.all.push(model);
}
myCallback && myCallback(self.all);
});
}
};
ProjectList.all => []
ProjectList.fetch(function(data) {
console.debug("Got a list of Project models");
});
</code></pre></div>
<p>Basically, we have a Javascript object which stores a list of our models. When we call <tt>ProjectList.fetch</tt>, jQuery gets JSON representing a bunch of projects which we iterate over and add to <tt>ProjectList.all</tt> which is an array. If you wanted, you could also write some kind of <tt>ProjectList.sync</tt> function which would push data to the backend.</p>
<p><a href="http://www.sproutcore.com/">Sproutcore</a> and <a href="http://www.sencha.com/products/touch/">Sencha Touch</a> provide robust data source libraries for interacting with a wide variety of backends such as REST, XML, JSON or YQL. Their model systems also track which attributes have changed on each object and can intelligently sync with the backend. Still, even without using a framework, this abstraction is very useful.</p>
<p>Ed Spencer has <a href="http://www.sencha.com/blog/2011/01/21/countdown-to-ext-js-4-data-package/">a great write-up of the Sencha/ExtJS Data Package</a>. I highly suggest reading it if only to get a grasp on the importance of having solid client-side models.</p>
SecondStoryJS State Machine now has a documentation website/2010/12/31/secondstoryjs-state-machine-now-has-a-documentation-website.html2010-12-31T00:00:00ZT00:00:00-08:002010-12-31T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>You can now learn everything you wanted to know about the JavascriptMVC3 state machine on the project website at:</p>
<p><a href="http://secondstory.github.com/secondstoryjs-router/"><a href="http://secondstory.github.com/secondstoryjs-statemachine/">http://secondstory.github.com/secondstoryjs-statemachine/</a></a></p>
<p><img src="/images/SecondStoryJS-StateMachine.png" alt="SecondStoryJS State Machine" /></p>
<p>You can now learn everything you wanted to know about the JavascriptMVC3 state machine on the project website at:</p>
<p><a href="http://secondstory.github.com/secondstoryjs-router/"><a href="http://secondstory.github.com/secondstoryjs-statemachine/">http://secondstory.github.com/secondstoryjs-statemachine/</a></a></p>
<p><img src="/images/SecondStoryJS-StateMachine.png" alt="SecondStoryJS State Machine" /></p>
Best Albums of the Year: 2010/2010/12/09/best-albums-of-the-year-2010.html2010-12-09T00:00:00ZT00:00:00-08:002010-12-09T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>It's that time of year again! I don't want a personal live journal all year, but damnit this is the one exception. I document my opinions because I think it will be really fun to look back and see what I was listening to in Ye Olde 2010. I suppose...</p><p>It's that time of year again! I don't want a personal live journal all year, but damnit this is the one exception. I document my opinions because I think it will be really fun to look back and see what I was listening to in Ye Olde 2010. I suppose this should be a "Top 14" list, but instead it's "Top 10" and some honorable mentions. Let's get started.</p>
<h2 id="top-10">Top 10:</h2>
<ul class="albums">
<li>
<div class='cover'>
<img src='/albums/2010/10.jpg' /><div></div>
</div>
<div class='content'>
<h6>United Nations</h6>
<h4>Nevermind The Bombings, Here's Your Six Figures</h4>
<p>This hardcore supergroup creates loud, in-your-face music that you survive until the album is over. This EP is short, but it's a great palette cleanser after hearing some bullshit Glee single.</p>
</div>
<div class='player'>
<h6>#10</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2010/9.jpg' /><div></div>
</div>
<div class='content'>
<h6>Envy</h6>
<h4>Recitation</h4>
<p>This classic Japanese hardcore band has slowly become more melodic, trading in hardcore-riffs for post-rock landscapes. The one thing that hasn't changed are the vocals. The interaction between the absolutely beatiful music and the tortured vocals works amazingly. The vocals don't grate because the music is inspiring, but the post-rock doesn't get slow, boring and repetitive because at any moment the peace could be broken by screams.</p>
</div>
<div class='player'>
<h6>#9</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2010/8.jpg' /><div></div>
</div>
<div class='content'>
<h6>Portugal. The Man</h6>
<h4>American Ghetto</h4>
<p>Another year, another great Portugal. The Man album. The psychadelic sounds of last year's album are still present, but the edges are rougher. More guitars, more big rock moments and yet another perfectly sized record. The album is exactly as long as it should be, no filler.</p>
</div>
<div class='player'>
<h6>#8</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2010/7.jpg' /><div></div>
</div>
<div class='content'>
<h6>B.o.B</h6>
<h4>B.o.B Presents: The Adventures of Bobby Ray </h4>
<p>Lots of hip hop on my list this year. B.o.B came out of nowhere and released a very radio-friendly album with some great guest appearances, a glimpse of his skills as an MC and a lot of really clever lyrics. I put B.o.B in the same bucket as Lupe Fiasco. These guys are smart, eloquent and know what they want to say. There isn't any fake drug game bravado or wasted breaths. The songs have a purpose and it is focused rather than the scattershot someone like Lil Wayne excretes.</p>
</div>
<div class='player'>
<h6>#7</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2010/6.jpg' /><div></div>
</div>
<div class='content'>
<h6>Cee Lo Green</h6>
<h4>The Lady Killer</h4>
<p>Cee Lo finally let loose, brought the energy over from the first Gnarls Barkley album and created an incredibly fun, modern soul record. Thankfully the huge single "Fuck You" isn't the only highlight. You can tell Cee Lo wanted to have fun, croon his heart out and just do what he wants, even if the result is a heavily censored music video (and appearance on Glee).</p>
</div>
<div class='player'>
<h6>#6</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2010/5.jpg' /><div></div>
</div>
<div class='content'>
<h6>Big Boi</h6>
<h4>Sir Lucious Left Foot: The Son of Chico Dusty</h4>
<p>This is the best hip hop album in a long while. Kanye doesn't count, he did something entirely different. No, this is a classic hip hop album. Lots of range in both the production and Big Boi's styles, but obviously the product of the Dirty South and one of the most talented rappers alive. Too bad the label removed the songs featuring Andre 3000 due to the boys of Outkast being signed to separate labels.</p>
</div>
<div class='player'>
<h6>#5</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2010/4.jpg' /><div></div>
</div>
<div class='content'>
<h6>Girl Talk</h6>
<h4>All Day</h4>
<p>Did anyone even know this album was coming out this year? It took me all of 2 days to fall in love with the most recent "best mashup album ever." Of course, it took the title again. Check out <a href="http://mashupbreakdown.com/">this visual player</a> and it's easy to be amazed by the complexity of the album.</p>
</div>
<div class='player'>
<h6>#4</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2010/3.jpg' /><div></div>
</div>
<div class='content'>
<h6>Fang Island</h6>
<h4>Fang Island</h4>
<p>Last year I listened to a lot of Post Rock and eventually I hit the end of my interest in the same atmosphere of dread. Fang Island flips is all around and has created a fantastically fun instrumental album which a suprising amount of complexity for something you can nod-along to. I saw the band live and the 5! guitars were pretty impressive.</p>
</div>
<div class='player'>
<h6>#3</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/2010/2.jpg' /><div></div>
</div>
<div class='content'>
<h6>Kanye West</h6>
<h4>My Beautiful Dark Twisted Fantasy </h4>
<p>This album is the culmination of everything Kanye is, everything he has been through and everything he has been working on. Who is Kanye? He's a super popular rapper, he changing the speed and pitch of female vocalists to sounds somewhat whiny, he produced songs for Jay Z, he has had public women problems, his mother passed away, he played with drum machines and auto-tune, he loves fashion and has a flair for the ornate. Take all that, mix it up and you get a perfect album.</p>
<p>Emotional, bragging, massive strings, Jay Z twice, 30-minute music videos, still got that pitch shifting, artistic use of auto-tune, cohesive mood and a supreme feeling of confidence. This is not a hip hop album, it's a statement of art. Any portion which works differently than the rest of the album, such as Monster, just shows Kanye's balls in that experimentation. Finally, I love the way Kanye retreats on many songs, letting his music and his guests handle the rest of the song after his initial verse.</p>
</div>
<div class='player'>
<h6>#2</h6>
</div>
</li>
<li class="last">
<div class='cover'>
<img src='/albums/2010/1.jpg' /><div></div>
</div>
<div class='content'>
<h6>Gorillaz</h6>
<h4>Plastic Beach</h4>
<p>If you had asked me when I began writing this article if Plastic Beach was my favorite album of the year, I would have said no. But during the process of organizing these albums and looking at my Last.fm stats for the past year, it's clear that I listened to this album more often by any other. In fact, I listened to it 200% more than the second most-listened-to album. I love everything on this list, but Plastic Beach definitely has staying power.</p>
<p>Also surprising is the fact that I felt the album was a sad departure from the Danger Mouse produced Demon Days, which I loved. Plastic Beach had less interesting songs, a more deliberate pace, weird-ass songs like Superfast Jellyfish and a bit too much electronic influence for me. But you know the way it is, the difficult albums become your favorites. The impenetrable surface gives way to reveal depth. I now consider this album nearly perfect. The primary sign of that is when my iPhone loops back to the beginning of the album after it finishes and I neither notice or become bored by the repetition.</p>
</div>
<div class='player'>
<h6>#1</h6>
</div>
</li>
</ul>
<h2 id="honorable-mentions">Honorable Mentions:</h2>
<ul>
<li>
<div class='cover_small'>
<img src='/albums/2010/15.jpg' /><div></div>
</div>
<div class='content_small'>
<h6>Amia Venera Landscape</h6>
<h4>The Long Procession</h4>
<p>Absolutely huge metal album. If it'd been released earlier in the year, it would probably be in my top 10.</p>
</div>
</li>
<li>
<div class='cover_small'>
<img src='/albums/2010/14.jpg' /><div></div>
</div>
<div class='content_small'>
<h6>Gogol Bordello</h6>
<h4>Trans-Continental Hustle</h4>
<p>Most accessible Gogol Bordello album yet.</p>
</div>
</li>
<li>
<div class='cover_small'>
<img src='/albums/2010/13.jpg' /><div></div>
</div>
<div class='content_small'>
<h6>Janelle Monáe</h6>
<h4>The ArchAndroid</h4>
<p>Fantastically inventive hip hop album. It's all over the place and most of it works. Janelle is destined to be a superstar.</p>
</div>
</li>
<li>
<div class='cover_small'>
<img src='/albums/2010/12.jpg' /><div></div>
</div>
<div class='content_small'>
<h6>The Black Keys</h6>
<h4>Brothers</h4>
<p>Another departure from a Danger Mouse produced album I loved, also great.</p>
</div>
</li>
<li class="last">
<div class='cover_small'>
<img src='/albums/2010/11.jpg' /><div></div>
</div>
<div class='content_small'>
<h6>Broken Bells</h6>
<h4>Broken Bells</h4>
<p>Danger Mouse gets his due. Abandonded by two of my favorites, but still able to turn out a fantastic album with the help of The Shins' James Mercer.</p>
</div>
</li>
</ul>
PubSub, Evented Programming and Javascript/2010/10/27/pubsub-evented-programming-and-javascript.html2010-10-27T00:00:00ZT00:00:00-08:002010-10-27T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>One of the buzzwords at jQuery Conference 2010 Boston (that mouthful makes Microsoft product names sound elegant), was "PubSub." At least three speakers referenced the concept in different contexts and I overheard quite a bit of chatter about it in...</p><p>One of the buzzwords at jQuery Conference 2010 Boston (that mouthful makes Microsoft product names sound elegant), was "PubSub." At least three speakers referenced the concept in different contexts and I overheard quite a bit of chatter about it in the hallways. I was surprised to see so many people getting their first introduction to the concept, especially given how event-oriented jQuery is. So, let's take a look at what PubSub means, how you can use it in jQuery and some very naive example code.</p>
<h2 id="what-is-pubsub">What is PubSub?</h2>
<p>PubSub is short for "Publish and Subscribe." Any piece of code can publish an event, or message, and any other piece of code can listen for that event. This allows code that responds to events to be easily decoupled from the code that creates an event. Here's an example using jQuery's <tt>$.ajax</tt> functionality. Without PubSub you might write an AJAX request like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$.ajax({
url: "/api/login.json",
success: function(data) {
// Update some HTML classes
// Show the person who logged in
// Refresh some lists of data
// etc.
}
});
</code></pre></div>
<p>Basically, anything that needs to happen when a user logs in must be written in that nested anonymous "success" function. The best solution for maintaining code, writing test cases and avoiding heavily-nested anonymous functions would be to make a function that handles each step of the login success separately.</p>
<h2 id="pubsub-enabled-ajax-success">PubSub-enabled AJAX success</h2>
<p>For this example, we'll use a very naive version of PubSub. We'll use <tt>$.fn.trigger</tt> and <tt>$.fn.bind</tt> on the root document object. jQuery's event api already handles the nuts and bolts of allowing multiple anonymous functions to respond to a single event, like "click" or "hover." Using this technique, we can organize the AJAX success code like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>// Update some HTML classes
$(document).bind("userDidLogin", function(event, data) {
$("#loginButton").hide();
$("#logoutButton").show();
});
// Show the person who logged in
$(document).bind("userDidLogin", function(event, data) {
$("#header #user").html(data.username);
});
// Refresh some lists of data
$(document).bind("userDidLogin", function(event, data) {
$.each(data.items, function() {
$("#items").append(this);
});
});
$.ajax({
url: "/api/login.json",
success: function(data) {
// Publish the event with the data
$(document).trigger("userDidLogin", data);
}
});
</code></pre></div>
<p>Now, it may look like we've created a lot more code, but now each of those subscribing functions can be placed anywhere. Say, for example, that we have a <tt>header.js</tt> which handles changes to the header of the page. We could put only the subscribes that relate to the header in there, thus making our code much more organized. We can also being writing test cases for each of the subscribers now that they are decoupled and simplified.</p>
<h2 id="pubsub-libraries">PubSub Libraries</h2>
<p>There are several available libraries for handling PubSub in javascript. The simplest jQuery form is what I've used here. <a href="http://weblog.bocoup.com/publishsubscribe-with-jquery-custom-events">This article on the Bocoup blog</a> compares the speed of the approach I've used above with a dedicated jq.pubsup library. Not surprisingly, anything dealing with the DOM is going to be slower than handling the events in memory.</p>
<p>I personally use the <a href="http://www.openajax.org/member/wiki/OpenAjax_Hub_1.0_Specification">OpenAjax Hub implementation</a> in conjunction with the <a href="http://v3.javascriptmvc.com/index.html#&who=jQuery.Controller">JavascriptMVC Controller</a>.</p>
Slides from my jQuery Conference Presentation/2010/10/18/slides-from-my-jquery-conference-presentation.html2010-10-18T00:00:00ZT00:00:00-08:002010-10-18T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Here are the slides which went along with my JavascriptMVC presentation at jQuery Conference Boston. You can avoid the nasty flash widget and <a href="http://dl.dropbox.com/u/102356/organizing-code-with-javascriptmvc.pdf">download the PDF directly</a> if you prefer.</p>
<p id="__ss_5467723"><object id="__sse5467723" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=jqconf-101017163158-phpapp01&stripped_title=jqconf&userName=tdreyno" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse5467723" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=jqconf-101017163158-phpapp01&stripped_title=jqconf&userName=tdreyno" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></p>
<p>Here are the slides which went along with my JavascriptMVC presentation at jQuery Conference Boston. You can avoid the nasty flash widget and <a href="http://dl.dropbox.com/u/102356/organizing-code-with-javascriptmvc.pdf">download the PDF directly</a> if you prefer.</p>
<p id="__ss_5467723"><object id="__sse5467723" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=jqconf-101017163158-phpapp01&stripped_title=jqconf&userName=tdreyno" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse5467723" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=jqconf-101017163158-phpapp01&stripped_title=jqconf&userName=tdreyno" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></p>
SecondStoryJS Router now has a documentation website/2010/10/11/secondstoryjs-router-now-has-a-documentation-website.html2010-10-11T00:00:00ZT00:00:00-08:002010-10-11T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Like the title says, you can now learn everything you wanted to know about the JavascriptMVC3 router on the project website at:</p>
<p><a href="http://secondstory.github.com/secondstoryjs-router/"><a href="http://secondstory.github.com/secondstoryjs-router/">http://secondstory.github.com/secondstoryjs-router/</a></a></p>
<p><img src="/images/SecondStoryJS-Router.png" alt="SecondStoryJS Router" /></p>
<p>Like the title says, you can now learn everything you wanted to know about the JavascriptMVC3 router on the project website at:</p>
<p><a href="http://secondstory.github.com/secondstoryjs-router/"><a href="http://secondstory.github.com/secondstoryjs-router/">http://secondstory.github.com/secondstoryjs-router/</a></a></p>
<p><img src="/images/SecondStoryJS-Router.png" alt="SecondStoryJS Router" /></p>
Middleman Feature: Config.rb can setup Rack middleware/2010/10/11/middleman-feature-configrb-can-setup-rack-middleware.html2010-10-11T00:00:00ZT00:00:00-08:002010-10-11T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Did you know that since <a href="http://middlemanapp.com">Middleman</a>'s <tt>config.rb</tt> is evaluated by Sinatra that it can initialize Rack middleware?</p>
<p>In the code sample below, I use the <a href="http://github.com/wbzyl/rack-codehighlighter">rack-codehighlighter</a> middleware to add syntax highlighting to a Middleman project.</p>
<script src="http://gist.github.com/621390.js?file=config.rb"></script>
<p>Did you know that since <a href="http://middlemanapp.com">Middleman</a>'s <tt>config.rb</tt> is evaluated by Sinatra that it can initialize Rack middleware?</p>
<p>In the code sample below, I use the <a href="http://github.com/wbzyl/rack-codehighlighter">rack-codehighlighter</a> middleware to add syntax highlighting to a Middleman project.</p>
<script src="http://gist.github.com/621390.js?file=config.rb"></script>
Handling Touch Events in jQuery Tools Scrollable/2010/09/22/handling-touch-events-in-jquery-tools-scrollable.html2010-09-22T00:00:00ZT00:00:00-08:002010-09-22T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><strong>[EDIT]: Looks like jQuery Tools Scrollable will support touch natively in their next release <a href="http://github.com/jquerytools/jquerytools/commit/d63892b54a85e00bb73ce248f8db29acf327d293">according to this commit</a>.</strong></p>
<p>Today I was trying to optimize the experience of a website for the Apple iPad. One quick win is to respond to touch events on the...</p><p><strong>[EDIT]: Looks like jQuery Tools Scrollable will support touch natively in their next release <a href="http://github.com/jquerytools/jquerytools/commit/d63892b54a85e00bb73ce248f8db29acf327d293">according to this commit</a>.</strong></p>
<p>Today I was trying to optimize the experience of a website for the Apple iPad. One quick win is to respond to touch events on the device which will make your site feel much smoother and avoid the double tapping which Mobile Safari sometimes requires to activate javascript links. Additionally, your very nice paging controls may not be large enough to comfortably tap on the device (the common wisdom is touch targets need to be at least 40px square). A simple swipe can go a long way towards addressing these issues.</p>
<p>So, how can we get the Scrollable widget to handle touch events?</p>
<p>First, you'll obviously need the <a href="http://flowplayer.org/tools/scrollable/index.html">jQuery Tools Scrollable</a> widget.</p>
<p>Next, you'll need Rick Olson's excellent <a href="http://github.com/technoweenie/jquery.doubletap">DoubleTap for jQuery</a> which adds touch events to jQuery's event system.</p>
<p>Finally, you'll need to write the glue:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$.fn.handleSwipes = function() {
return this.each(function() {
var api = $(this).data("scrollable");
api.getRoot().addSwipeEvents()
.bind('swipeleft', function() {
api.next();
})
.bind('swiperight', function() {
api.prev();
});
});
};
</code></pre></div>
<p>Once you have all three of these components on a page, initialize them like so:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$(".scrollable").scrollable().handleSwipes();
</code></pre></div>
<p>Now touch swipes will trigger the next and previous behavious built into the widget. Enjoy.</p>
Speaking at jQuery Conference: Boston 2010/2010/09/08/speaking-at-jquery-conference-boston-2010.html2010-09-08T00:00:00ZT00:00:00-08:002010-09-08T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Two big announcements today.</p>
<p>First, I'll be speaking at <a href="http://events.jquery.org/2010/boston/">jQuery Conference: Boston 2010</a> which is taking place October 16-17. My talk will be on code organization and dependency management with <a href="http://v3.javascriptmvc.com/index.html">JavascriptMVC 3</a> and <a href="http://github.com/jupiterjs/steal">steal</a> being the two solutions that...</p><p>Two big announcements today.</p>
<p>First, I'll be speaking at <a href="http://events.jquery.org/2010/boston/">jQuery Conference: Boston 2010</a> which is taking place October 16-17. My talk will be on code organization and dependency management with <a href="http://v3.javascriptmvc.com/index.html">JavascriptMVC 3</a> and <a href="http://github.com/jupiterjs/steal">steal</a> being the two solutions that I'm most fond of.</p>
<p>Second, I've joined the JavascriptMVC Core Team, so I can actually appear to be an authority on the subject I'm presenting :)</p>
<p>Thanks to the jQuery Conference organizers for accepting my talk and thanks to <a href="http://jupiterjs.com/pages/justin-meyer">Justin Meyer</a> and the rest of the JavascriptMVC Core Team for having me. See you all in Boston!</p>
Mustache for JavascriptMVC 3/2010/08/09/mustache-for-javascriptmvc-3.html2010-08-09T00:00:00ZT00:00:00-08:002010-08-09T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>If you're a fan of the Mustache templating language, here's a plugin to integrate it with JavascriptMVC 3.</p>
<p>There are two ways of grabbing the code. If you have a very recent version of JavascriptMVC 3 you can use the new <tt>getjs</tt> method of installing...</p><p>If you're a fan of the Mustache templating language, here's a plugin to integrate it with JavascriptMVC 3.</p>
<p>There are two ways of grabbing the code. If you have a very recent version of JavascriptMVC 3 you can use the new <tt>getjs</tt> method of installing plugins. The command, from your project folder, looks like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>./steal/js steal/getjs mustache
</code></pre></div>
<p>Alternatively, you can grab the code from <a href="http://github.com/tdreyno/mustache-javascriptmvc">the Github repository</a>:</p>
<div class="highlight"><pre class="highlight plaintext"><code>git clone git://github.com/tdreyno/mustache-javascriptmvc.git mustache
</code></pre></div>
<p>Include it in your app:</p>
<div class="highlight"><pre class="highlight plaintext"><code>steal.plugins("mustache")
</code></pre></div>
<p>Create some <tt>.mustache</tt> files and use them normally:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$("#elem").html("//views/template.mustache", { variable: "Value" })
</code></pre></div>The jQuery Tools API Pattern/2010/08/06/the-jquery-tools-api-pattern.html2010-08-06T00:00:00ZT00:00:00-08:002010-08-06T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>A common pattern for initializing jQuery plugins is by selecting all the instances of the target in the DOM and running the plugin once. For example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$(":input").myPlugin();
</code></pre></div>
<p>But what if you need to inspect the plugin later or are only interested in...</p><p>A common pattern for initializing jQuery plugins is by selecting all the instances of the target in the DOM and running the plugin once. For example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$(":input").myPlugin();
</code></pre></div>
<p>But what if you need to inspect the plugin later or are only interested in one instance of the plugin. A friend of mine <a href="http://forum.jquery.com/topic/return-customized-default-values-for-each-in-a-plugin">recently asked this question</a> and my suggestion was to look at the way the <a href="http://flowplayer.org/tools/">jQuery Tools</a> project does it. For each of their plugins, they build an API object which only interacts with one specific element and they attach it to the element once the plugin has been initialized using the jQuery.data method. This also provides a clean way of checking if the plugin has already been initialized on a specific element.</p>
<p>Here's how they run their scrollable plugin when called by jQuery:</p>
<div class="highlight"><pre class="highlight plaintext"><code>// jQuery plugin implementation
$.fn.scrollable = function(conf) {
// already constructed --> return API
var el = this.data("scrollable");
if (el) { return el; }
conf = $.extend({}, $.tools.scrollable.conf, conf);
this.each(function() {
el = new Scrollable($(this), conf);
$(this).data("scrollable", el);
});
return conf.api ? el: this;
};
</code></pre></div>
<p>The <tt>Scrollable</tt> function handles plugin initialization on a per-element basis and returns scoped methods for interacting with that object. Its implementation looks like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function Scrollable(root, conf) {
// Setup variables
// methods
$.extend(self, {
getConf: function() {
return conf;
},
// et cetera
});
// callbacks
$.each(['onBeforeSeek', 'onSeek', 'onAddItem'], function(i, name) {
// configuration
if ($.isFunction(conf[name])) {
$(self).bind(name, conf[name]);
}
self[name] = function(fn) {
$(self).bind(name, fn);
return self;
};
});
// run methods
}
</code></pre></div>
<p>Now, let's assume we have applied this pattern to our <tt>myPlugin</tt> plugin. The interaction would look like this.</p>
<div class="highlight"><pre class="highlight plaintext"><code>$(":input").myPlugin();
var specificInput = $("#myinput");
var api = specificInput.data("myPlugin");
api.getConf() // See the original config variables
api.doSomething() // run some code
api.destroy() // remove the plugin
// Run a callback on this specific instance
api.onClick(function() {
// Click handler
});
</code></pre></div>
<p>The pattern would also handle accidently running the plugin twice on a single element. For example, in the following script the plugin would only initialize the <tt>#myinput</tt> element once:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$("#myinput").myPlugin();
$(":input").myPlugin();
</code></pre></div>
<p>The <a href="http://flowplayer.org/tools/documentation/scripting.html#api">full jQuery Tools API documentation</a> is available on their website.</p>
Style Guides Using Sass @extend/2010/07/30/style-guides-using-sass-extend.html2010-07-30T00:00:00ZT00:00:00-08:002010-07-30T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>There are some very common front-end development patterns that drive me crazy. CSS with every style related to a specific selector on one line and IE-only stylesheets with conditional comments are both common place and even encouraged by some. But...</p><p>There are some very common front-end development patterns that drive me crazy. CSS with every style related to a specific selector on one line and IE-only stylesheets with conditional comments are both common place and even encouraged by some. But the worst, in my opinion, is breaking our CSS into multiple files in an attempt to make them "themable." Usually this results in something like a <tt>main.css</tt> and a <tt>fonts.css</tt> or <tt>colors.css</tt>. Having a go-to file for designers to manipulate fonts and colors is very useful, but usually the structure of this secondary file mirrors the primary file and you end up with a lot of repetition. Furthermore, if your DOM structure changes, then you will need to update multiple files (<tt>ie.css</tt> results in a similar problem).</p>
<p>Sass' @extend feature allows us to have a <tt>style-guide.sass</tt> in which designers can run free, but is not dependent on DOM structure. Let's take a look at how I setup my style guides.</p>
<h2 id="the-style-guide">The Style Guide</h2>
<p>The designer on the project has put together a wonderful style guide PDF which I will be implementing in Sass. Here is what it looks like:</p>
<p><img src="/images/style-guide-full.png" /></p>
<p>As you can see, each style has a title and some specifics for the text treatment.</p>
<p>First I setup variables for our color palatte.</p>
<div class="highlight"><pre class="highlight plaintext"><code>$primary-orange: #fe8a16
$hover-orange: #f67502
$steel-blue: #303b41
$bright-blue: #4892bc
$dark-grey: #4b4b48
</code></pre></div>
<p>Next I create some simple mixins to handle usage of custom fonts.</p>
<div class="highlight"><pre class="highlight plaintext"><code>=custom-font
font-family: "Droid Sans"
font-weight: normal
=bold-custom-font
font-family: "Droid Sans Bold"
font-weight: bold
</code></pre></div>
<p>Finally, I start defining the styles as classes. As you can see, I am using @extend to avoid repeating myself. I'm going to omit some of the styles in the guide for the sake of brevity.</p>
<div class="highlight"><pre class="highlight plaintext"><code>.sg-heading-1
+custom-font
font-size: 32px
line-height: 36px
color: $steel-blue
.sg-heading-2
@extend .sg-heading-1
font-size: 20px
line-height: 28px
.sg-heading-3
@extend .sg-heading-2
color: $bright-blue
.sg-main-body
font-size: 14px
line-height: 24px
font-weight: normal
color: $dark-grey
.sg-secondary-body
@extend .sg-main-body
font-size: 12px
line-height: 18px
.sg-text-link-1
font-weight: normal
color: $primary-orange
text-decoration: none
&:hover
color: $hover-orange
</code></pre></div>
<h2 id="referencing-the-style-guide">Referencing the Style Guide</h2>
<p>Now, when I go to implement a specific portion of the site, I can be concise by referencing the style guide. </p>
<div class="highlight"><pre class="highlight plaintext"><code>.info-box
h2
@extend .sg-heading-2
ul li
@extend .sg-text-link-1
p
@extend .sg-main-body
dl
@extend .sg-secondary-body
</code></pre></div>
<p>Here's the resulting CSS output:</p>
<div class="highlight"><pre class="highlight plaintext"><code>.sg-heading-1, .sg-heading-2, .sg-heading-3, .info-box h2 {
font-family: "Droid Sans";
font-weight: normal;
font-size: 32px;
line-height: 36px;
color: #303b41; }
.sg-heading-2, .sg-heading-3, .info-box h2 {
font-size: 20px;
line-height: 28px; }
.sg-heading-3 {
color: #4892bc; }
.sg-main-body, .sg-secondary-body, .info-box dl, .info-box p {
font-size: 14px;
line-height: 24px;
font-weight: normal;
color: #4b4b48; }
.sg-secondary-body, .info-box dl {
font-size: 12px;
line-height: 18px; }
.sg-text-link-1, .info-box ul li {
font-weight: normal;
color: #fe8a16;
text-decoration: none; }
.sg-text-link-1:hover, .info-box ul li:hover {
color: #f67502; }
</code></pre></div>
<h2 id="conclusion">Conclusion</h2>
<p>I have been incredibly happy with this approach. It has all the independence of the external <tt>fonts-and-colors.css</tt> method, but is more flexible, uses less code and is more readable in both the Sass and CSS forms.</p>
<p>I highly suggest getting your designer to build a style guide. It enforces consistency and keeps the randomness out of coding. Why should a site use every font size between 12px and 22px? Just pick a few sizes and standardize on them.</p>
Sass @extend Introduction/2010/07/27/sass-extend-introduction.html2010-07-27T00:00:00ZT00:00:00-08:002010-07-27T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Sass (and SCSS) version 3 added support for the @extend directive which provides a means of class inheritance and combats the duplication of CSS which Sass mixins create. The earlier features of Sass were basically macros. They grabbed a piece of CSS...</p><p>Sass (and SCSS) version 3 added support for the @extend directive which provides a means of class inheritance and combats the duplication of CSS which Sass mixins create. The earlier features of Sass were basically macros. They grabbed a piece of CSS from either a mixin definition or an external file and inserted that CSS into the output. @extend actually manipulates the selectors and uses CSS's own cascading inheritance system simplify code and avoid duplication. Let's look at some simple examples.</p>
<h2 id="multiple-sidebars-and-fighting-class-itis">Multiple Sidebars and Fighting Class-itis</h2>
<p>Imagine you have a sidebar with 3 boxes. The first box is logging in, the second box is for an already logged in user and the third box is simply a series of links (a tag cloud, maybe). All three boxes should be styled similarly so let's start with the basics:</p>
<div class="highlight"><pre class="highlight plaintext"><code>.sidebar-box
+clearfix
margin: 0 0 10px 0
background: #eee
+border-radius
padding: 10px
</code></pre></div>
<p>Now, any <tt>div</tt> element we assign a class of <tt>sidebar-box</tt> will be cleared, have a bottom margin, a background color, rounded-corners and an internal padding. Now let's develop a login/logout box which has some specifics for form controls.</p>
<div class="highlight"><pre class="highlight plaintext"><code>.sidebar-auth-box
@extend .sidebar-box
input[type=text]
padding: 10px
border: 1px solid #ccc
</code></pre></div>
<p>Now, any <tt>div</tt> element we assign a class of <tt>sidebar-auth-box</tt> will behave identically to the standard <tt>sidebar-box</tt>, but will also have custom styling for form inputs. Finally, the logout box will be a darker color to help it stand out. Before @extend, we might have ended up with a tag like this: </p>
<div class="highlight"><pre class="highlight plaintext"><code><div id="logout-box" class="sidebar-box sidebar-auth-box">
</code></pre></div>
<p>Now, we can keep our HTML simple and continue with another @extend:</p>
<div class="highlight"><pre class="highlight plaintext"><code>#login-box
@extend .sidebar-auth-box
#logout-box
@extend .sidebar-auth-box
background: #bbb
#links-box
@extend .sidebar-box
</code></pre></div>
<p>This requires only an <tt>id</tt> on the three boxes, but we don't repeat ourselves. You'll also notice that the plain CSS classes are still available to place on <tt>div</tt> elements for rapid development or if custom id attributes are not needed. For those who are curious what the output looks like, here it is: </p>
<div class="highlight"><pre class="highlight plaintext"><code>.sidebar-box,
.sidebar-auth-box,
#login-box,
#logout-box,
#links-box {
overflow: hidden;
display: inline-block;
margin: 0 0 10px 0;
background: #eeeeee;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
-o-border-radius: 5px;
-ms-border-radius: 5px;
-khtml-border-radius: 5px;
border-radius: 5px;
padding: 10px; }
.sidebar-box,
.sidebar-auth-box,
#login-box,
#logout-box,
#links-box {
display: block; }
.sidebar-auth-box input[type=text],
#login-box input[type=text],
#logout-box input[type=text] {
padding: 10px;
border: 1px solid #cccccc; }
#logout-box {
background: #bbbbbb; }
</code></pre></div>JavascriptMVC Router/2010/07/23/javascriptmvc-router.html2010-07-23T00:00:00ZT00:00:00-08:002010-07-23T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><strong>[Edit]: The SecondStoryJS Router now has a documentation website at <a href="http://secondstory.github.com/secondstoryjs-router/"></a><a href="http://secondstory.github.com/secondstoryjs-router/">http://secondstory.github.com/secondstoryjs-router/</a></strong></p>
<p>Modern web applications should function as naturally as their static page-based predecessors. As developers, we may need to store...</p><p><strong>[Edit]: The SecondStoryJS Router now has a documentation website at <a href="http://secondstory.github.com/secondstoryjs-router/"><a href="http://secondstory.github.com/secondstoryjs-router/">http://secondstory.github.com/secondstoryjs-router/</a></a></strong></p>
<p>Modern web applications should function as naturally as their static page-based predecessors. As developers, we may need to store state in the location bar, but the user shouldn't be able to tell the difference, except, hopefully, the Ajaxified version should be faster and smoother.</p>
<p>To accomplish this, we need to move a lot of the libraries we've used on the backend into the world of Javascript. JavascriptMVC handles models, views and controllers, but it doesn't provide a router. A router takes a string which contains state, such as <tt>/articles/my-first-article</tt> and activates a specific piece of code which can respond to the request.</p>
<p>At <a href="http://secondstory.com/">Secondstory</a>, we've been building upon JavascriptMVC and <a href="http://github.com/joshbuddy/sherpa">Joshua Hull's wonderful Sherpa route recognizer</a>. Originally intended for usage in a NodeJS environment, Sherpa can take complex route definitions (as seen in Ruby on Rails) and map them to a destination while extracting variables from the route.</p>
<p>Here's a matching example from the Sherpa docs:</p>
<div class="highlight"><pre class="highlight plaintext"><code>Router.add('/test/:variable').to('testing')
Router.recognize('/test/iloveyou') ->
{
"destination": "testing",
"params": {
"variable": "iloveyou"
}
}
</code></pre></div>
<p>You can also generate routes from parameters if you give the route a name:</p>
<div class="highlight"><pre class="highlight plaintext"><code>Router.add('/test/:variable').to('testing').name('testRoute')
Router.generate('testRoute', { "variable": "iloveyou" }) ->
"/test/iloveyou"
</code></pre></div>
<h2 id="using-in-javascriptmvc">Using in JavascriptMVC</h2>
<p>First, grab a copy of the Sherpa library and put it in your resources directory. Then, in your JavascriptMVC project file you intialize Sherpa:</p>
<div class="highlight"><pre class="highlight plaintext"><code>steal.resources("sherpa")
.then(function($) {
var Router = new Sherpa.Router();
});
</code></pre></div>
<p>Now you have to choose how tightly you want to couple routes and controllers. I've approached this in a two different ways.</p>
<p>First, you can initialize a new controller on the document element when the route is matched:</p>
<div class="highlight"><pre class="highlight plaintext"><code>Router.add("/articles/:article_name").to("project_article");
var key = window.location.pathname,
foundRoute = Router.recognize(key);
if (foundRoute && $(document)[foundRoute.destination]) {
$(document)[foundRoute.destination](foundRoute.params);
}
</code></pre></div>
<p>Alternatively, you could fire an OpenAjax event instead:</p>
<div class="highlight"><pre class="highlight plaintext"><code>Router.add("/articles/:article_name").to("project_article");
var key = window.location.pathname,
foundRoute = Router.recognize(key);
if (foundRoute) {
OpenAjax.hub.publish(foundRoute.destination, foundRoute.params);
}
</code></pre></div>
<p>Unfortunately, this will only run once, during the inital load of your project. In reality, you will want to watch the location bar throughout the usage of your application and either run controllers or publish events for each location change. JavascriptMVC provides the <tt>jquery/controller/history</tt> which publishes <tt>history./current/url</tt> OpenAjax events when the location changes. You could wire this up on your own, or you could use the class we've developed and written tests for.</p>
<h2 id="ss-router">SS.Router</h2>
<p>The Secondstory router class uses <tt>jquery/controller/history</tt> to listen to the location change events, then it matches against the Routes you have setup and finally sends a new OpenAjax event containing the value of the <tt>.to()</tt> method you setup when definition the route. It also contains logic for making sure multiple events aren't published for the same location if a user clicks the same link twice, for example.</p>
<p>First, grab the code using JavascriptMVC's built-in <tt>getjs</tt> command:</p>
<div class="highlight"><pre class="highlight plaintext"><code>./steal/js steal/getjs ss/router
</code></pre></div>
<p>So let's go back to our project configuration file:</p>
<div class="highlight"><pre class="highlight plaintext"><code>steal.plugins("ss/router")
.then(function($) {
Router.add("/articles/:article_name").to("project_article");
});
</code></pre></div>
<p>That's it! When <tt>#/articles/my-first-article</tt> is accessed, OpenAjax will publish a <tt>project<em>article</tt> event with "my-first-article" as the "article</em>name" parameter.</p>
UINavigationController implementation for SenchaTouch/2010/07/02/uinavigationcontroller-implementation-for-senchatouch.html2010-07-02T00:00:00ZT00:00:00-08:002010-07-02T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><a href="http://www.sencha.com/products/touch/">SenchaTouch</a> is web development framework for building native-looking mobile apps (iOS & Android) using standards-based web technologies such as HTML5 & CSS3. The Sencha website features <a href="http://www.sencha.com/products/touch/demos.php">several very impressive demos</a>. However, the framework is still...</p><p><a href="http://www.sencha.com/products/touch/">SenchaTouch</a> is web development framework for building native-looking mobile apps (iOS & Android) using standards-based web technologies such as HTML5 & CSS3. The Sencha website features <a href="http://www.sencha.com/products/touch/demos.php">several very impressive demos</a>. However, the framework is still in beta and many useful features are either incomplete or missing entirely.</p>
<p>One common interaction in iPhone applications is multi-level navigation which places a back button in the toolbar and allows the user to drill down into the data. In a native app, the <tt>UINavigationController</tt> class manages this hierarchy of views and asks the currently selected view information about itself for display. For example, the current view may have a <tt>navigationTitle</tt> of "Tier 1" and its child view may have a <tt>navigationTitle</tt> of "Tier 2." UINavigationViewController will inspect these views and make sure the correct title is visible in the navigation bar according to the currently selected view. See the diagram below:</p>
<p><img src="http://files.posterous.com/temp-2010-07-02/bwAhfIJeckcGGuGdeEtylgJJanitascAdxyEdziptsBpmmaDGschrlzbyrIx/navigation_interface.jpg?AWSAccessKeyId=1C9REJR1EMRZ83Q7QRG2&Expires=1280251911&Signature=6PnQ/gmFo0jFitRh9D2S3Y2BOZc%3D" /></p>
<p>SenchaTouch has something similar with the NestedList class which shows a hierarchy of <tt>Ext.List</tt> panels. However, it would be nice to have something much more generic that allows any type of panel to be placed in the hierarchy. Below this post is the source code for <tt>PanelStack</tt> which functions much like <tt>UINavigationController</tt>. Each panel in the stack can push more panels beneath it or pop itself off the stack (identical to pressing the back button). Additionally, each panel is has an animation property which is run on push and reversed on pop making interactions such as flipping a card over to see its back and then returning to the front very easy to accomplish.</p>
<h2 id="how-to-use-panelstack">How to use PanelStack</h2>
<div class="highlight"><pre class="highlight plaintext"><code>var bottomLevel = new Ext.Panel({ title: "Start page" });
var firstLevel = new Ext.Panel({ title: "Tier 1" });
var secondLevel = new Ext.Panel({ title: "Tier 2" });
var controller = new PanelStack({ items: [bottomLevel] });
// Showing the bottomLevel, a title of "Start page" and no back button
controller.pushPanel(firstLevel);
// Showing the firstLevel, a title of "Tier 1" and a "back" button
controller.pushPanel(secondLevel);
// Showing the secondLevel, a title of "Tier 2" and a "back" button
controller.popPanel();
// Showing the firstLevel, a title of "Tier 1" and a "back" button
// Manually tapping the "back" button
// Showing the bottomLevel, a title of "Start page" and no back button
</code></pre></div>
<h2 id="the-current-code-for-the-class-is-below">The current code for the class is below.</h2>
<script src="http://gist.github.com/461744.js"></script>
State Machine Controller for JavascriptMVC/2010/05/27/state-machine-controller-for-javascriptmvc.html2010-05-27T00:00:00ZT00:00:00-08:002010-05-27T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><strong>[Updated]: The repository has moved to <a href="http://github.com/secondstory/secondstoryjs-statemachine">http://github.com/secondstory/secondstoryjs-statemachine</a>. The main class has been renamed to SS.Controller.StateMachine</strong></p>
<p><strong>[Edit]: The SecondStoryJS State Machine now has a documentation website at <a href="http://secondstory.github.com/secondstoryjs-statemachine/"></a><a href="http://secondstory.github.com/secondstoryjs-statemachine/">http://secondstory...</a></strong></p><p><strong>[Updated]: The repository has moved to <a href="http://github.com/secondstory/secondstoryjs-statemachine">http://github.com/secondstory/secondstoryjs-statemachine</a>. The main class has been renamed to SS.Controller.StateMachine</strong></p>
<p><strong>[Edit]: The SecondStoryJS State Machine now has a documentation website at <a href="http://secondstory.github.com/secondstoryjs-statemachine/"><a href="http://secondstory.github.com/secondstoryjs-statemachine/">http://secondstory.github.com/secondstoryjs-statemachine/</a></a></strong></p>
<p>I've been attempting to write this article for a week, but I've been unable to justify the usefulness of Finite State Machines in words. I tried written up some typical examples, such as the classic vending machine, but it kept getting very obtuse very quickly. Instead, let me just say, that I love Finite State Machines. I think they are the only technique I learned at school and when I am able to replace dozens of <tt>if</tt> statements with a Finite State Machine, it makes me very happy and feel secure. Being able to monitor an object's state, rather than just querying its instance variables, makes testing simpler and helps me find bugs.</p>
<p>If you need a Finite State Machine for JavascriptMVC, I've got one for you. In fact, every controller in my application uses it. The most common use-case is asyncronous loading, rendering and eventually interaction. Here's an example:</p>
<h2 id="finite-state-machine-implementation">Finite State Machine Implementation</h2>
<p>The goal of the following controller is to have widgets or panels which are made visible by clicking a link. Only one of the widgets may be visible at the same time and if you click the link for the currently open widget, it should toggle off. Each widget also contains a link for closing itself (<tt>a.close</tt>).</p>
<p>A state machine can respond to jQuery events, global OpenAjax messages and internal "publishState" commands. The destination states define which state we are moved into on an event. Finally, "onEnter" and "onExit" can point to either instance methods or global OpenAjax messages.</p>
<div class="highlight"><pre class="highlight plaintext"><code>SS.Controller.StateMachine.extend("MyNavigation", {}, {
states: {
// Any click of the a.close element will close everything
global: { "a.close click": "initial" },
// Initial is the default state.
// It will also represent "all closed"
initial: { onEnter: "closeDrawers",
"#header-thread a click": "threadIsOpen",
"#header-timeline a click": "timelineIsOpen" },
threadIsOpen: { onEnter: "drawers.toggle.thread",
"#header-thread a click": "initial",
"#header-timeline a click": "timelineIsOpen" },
timelineIsOpen: { onEnter: "drawers.toggle.timeline",
"#header-timeline a click": "initial",
"#header-thread a click": "threadIsOpen" }
},
"drawers.toggle.* subscribe": function(event_name) {
this.closeDrawers();
var elem_name = "#" + event_name.split(".").pop();
$(elem_name).show();
},
closeDrawers: function() {
$("#thread, #timeline").hide();
}
});
</code></pre></div>
<p>Clicking on #header-thread, #header-timeline and then #header-timeline again will print the following debug output:</p>
<div class="highlight"><pre class="highlight plaintext"><code>steal.js INFO: FSM (MyNavigation.instance0): initial -> threadsOpen
steal.js INFO: FSM (MyNavigation.instance0): threadsOpen -> timelineOpen
steal.js INFO: FSM (MyNavigation.instance0): timelineOpen -> initial
</code></pre></div>
<h2 id="how-do-i-get-it">How Do I Get It?</h2>
<p>First, get the <a href="http://v3.javascriptmvc.com/index.html">current version of JavascriptMVC 3 from their site</a>.</p>
<p>Second, grab the code using JavascriptMVC's built-in <tt>getjs</tt> command:</p>
<div class="highlight"><pre class="highlight plaintext"><code>./steal/js steal/getjs ss/state_machine
</code></pre></div>
<p>Next, create a Site and a Controller (see the <a href="http://v3.javascriptmvc.com/index.html#&who=getstarted">JavascriptMVC Getting Started Guide</a>).</p>
<p>We need to add our new plugin to the site. In appname.js, add the following to your <tt>steal</tt> command:</p>
<div class="highlight"><pre class="highlight plaintext"><code>.plugins("ss/controller/state_machine")
</code></pre></div>
<p>Now you can extend your Controllers from <tt>SS.Controller.StateMachine</tt>.</p>
<h2 id="other-better-examples">Other/Better Examples?</h2>
<p>I would love a chance to show how this works will a less contrived example. If you've a complex controller and think something like this would be useful, then please email me and I'll port your code to using a state machine.</p>
HTML5 localStorage for JavascriptMVC/2010/05/21/html5-localstorage-for-javascriptmvc.html2010-05-21T00:00:00ZT00:00:00-08:002010-05-21T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><strong>[Updated]: The new Github repository location is: <a href="http://github.com/secondstory/secondstoryjs-html5storage">http://github.com/secondstory/secondstoryjs-html5storage</a>. The new class names are SS.Model.HTML5Store.Local and SS.Model.HTML5Store.Session</strong></p>
<p>For those who don't know, JavascriptMVC 3 is a framework...</p><p><strong>[Updated]: The new Github repository location is: <a href="http://github.com/secondstory/secondstoryjs-html5storage">http://github.com/secondstory/secondstoryjs-html5storage</a>. The new class names are SS.Model.HTML5Store.Local and SS.Model.HTML5Store.Session</strong></p>
<p>For those who don't know, JavascriptMVC 3 is a framework for building complex web applications based on jQuery. jQuery is a wonderful tool for manipulating the DOM, but it doesn't provide any system for dependency resolution, file organization or a separation of concerns. JavascriptMVC 3, which is currently in a very solid alpha form, provides a strong MVC foundation for oragnizing your code.</p>
<p>The View component supports Ejs (a javascript variant of Erb), Jaml (a javascript templating system inspired by Haml) and a basic template implementation based on <a href="http://ejohn.org/blog/javascript-micro-templating/">John Resig's blog post</a> called Micro.</p>
<p>The Controller layer is based on responding to events, both normal jQuery DOM events (and special events) as well as OpenAjax events.</p>
<p>Finally, the Model component is basically just a Class which you can wire into your existing REST API with the help of some plugins and a little code. The Model component comes with a backing data store that can be swapped out. The default is an in-memory object that's provided as a placeholder for future data stores.</p>
<p>I suggest reading this <a href="http://jupiterjs.com/pages/javascriptmvc#news/too-enterprisey">blog post on JavascriptMVC's impressed unit/functional testing system</a>.</p>
<p>HTML5 is the new hotness and so I've implemented <tt>localStorage</tt> and <tt>sessionStorage</tt> backends for the JavascriptMVC 3 Model system. This means that once data is loaded into your model (via Ajax) it can be cached on the local machine until the end of the session or "forever" (until the localStorage cache is cleared). The difference between <tt>sessionStorage</tt> and browser cookies is that cookies are sent on every request so they are not well suited for storing lots of data. </p>
<h2 id="how-do-i-use-it">How Do I Use It?</h2>
<p>First, get the <a href="http://v3.javascriptmvc.com/index.html">current version of JavascriptMVC 3 from their site</a>.</p>
<p>Second, grab the code using JavascriptMVC's built-in <tt>getjs</tt> command:</p>
<div class="highlight"><pre class="highlight plaintext"><code>./steal/js steal/getjs ss/model/html5store
</code></pre></div>
<p>Next, create a Site and a Model (see the <a href="http://v3.javascriptmvc.com/index.html#&who=getstarted">JavascriptMVC Getting Started Guide</a>).</p>
<p>We need to add our new plugin to the site. In appname.js, add the following to your <tt>steal</tt> command:</p>
<div class="highlight"><pre class="highlight plaintext"><code>.plugins("ss/model/html5store")
</code></pre></div>
<p>Okay, so we have a model and now we need to add the new store system:</p>
<div class="highlight"><pre class="highlight plaintext"><code>jQuery.Model.extend("MyModel",
{
setup: function(){
// Alternatively, use SS.Model.HTML5Store.Local
this.storeType = SS.Model.HTML5Store.Session;
this._super.apply(this, arguments);
}
},
{
}
);
</code></pre></div>
<p>Now, whenever you create a MyModel with a unique id, it will be added to the HTML5 sessionStorage. You're responsible for updating the store if the model changes and for querying the store to see if it has a copy of the model we're looking for. Here's some boilerplate code to do that:</p>
<div class="highlight"><pre class="highlight plaintext"><code>function updateModel(params) {
MyModel.store.destroy(params.id);
MyModel.store.create(params);
}
function isInStore(id) {
return MyModel.store.findOne(id);
}
</code></pre></div>
<p>Using this plugin, I've been able to decrease the number of Ajax requests in my data-heavy webapp to 0 after the initial load. You could also preload data in the background using this technique to vastly improve the speed of your site.</p>
<h2 id="browser-support">Browser Support</h2>
<p>HTML5 localStorage is supported in IE8, Firefox 3.5+, Safari 4+, Chrome 4+ and Opera 10.50+. If localStorage is unavailable, the plugin will degrade to the default in-memory store.</p>
<h2 id="jquery-offline">jQuery-offline</h2>
<p>For a framework-agnostic version of this plugin, please take a look at <a href="http://github.com/wycats/jquery-offline">Yahuda Katz' jquery-offline</a>.</p>
Apple-style Gradient Text Headlines in SCSS/SASS/2010/04/13/apple-style-gradient-text-headlines-in-scsssass.html2010-04-13T00:00:00ZT00:00:00-08:002010-04-13T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Apple's effect looks like this:</p>
<p><img src="http://dl.dropbox.com/u/102356/Screenshot.png"></p>
<p>This effect only works in Webkit-based browsers like Safari and Chrome at this time and requires Sass 3 and the most recent version of Compass:</p>
<div class="highlight"><pre class="highlight plaintext"><code>h1 {
@include linear-gradient(color-stops(#999, black));
-webkit...</code></pre></div><p>Apple's effect looks like this:</p>
<p><img src="http://dl.dropbox.com/u/102356/Screenshot.png" /></p>
<p>This effect only works in Webkit-based browsers like Safari and Chrome at this time and requires Sass 3 and the most recent version of Compass:</p>
<div class="highlight"><pre class="highlight plaintext"><code>h1 {
@include linear-gradient(color-stops(#999, black));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</code></pre></div>
<p>Or, if you prefer plain CSS:</p>
<div class="highlight"><pre class="highlight plaintext"><code>h1 {
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%,
color-stop(0%, #999999),
color-stop(100%, #000000));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</code></pre></div>
<p>Which renders as:</p>
<p><img src="http://dl.dropbox.com/u/102356/Screenshot-1.png" /></p>
Sass 3 Color Manipulation/2010/04/12/sass-3-color-manipulation.html2010-04-12T00:00:00ZT00:00:00-08:002010-04-12T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I was going to write about the Compass Colors plugin merging into Sass 3, but it looks like Sass-maintainer Nathan Weizenbaum has already written a great article about it.</p>
<p>Read about <a href="http://nex-3.com/posts/89-powerful-color-manipulation-with-sass">Powerful Color Manipulation with Sass</a> on his blog.</p>
<p>Just for kicks...</p><p>I was going to write about the Compass Colors plugin merging into Sass 3, but it looks like Sass-maintainer Nathan Weizenbaum has already written a great article about it.</p>
<p>Read about <a href="http://nex-3.com/posts/89-powerful-color-manipulation-with-sass">Powerful Color Manipulation with Sass</a> on his blog.</p>
<p>Just for kicks, here is a relavant portion of Sass colors that I use on this blog:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$font-color: darken(#4e4c49, 5)
$darker-font-color: #4e4c49
$header-color: darken($font-color, 10)
$border-color: #d0d0d0
$link-color: #af512c
#social
color: lighten($font-color, 40)
#footer
background: darken(#603d17, 5)
</code></pre></div>
<p>These functions are also used in <a href="http://brandonmathis.com/projects/fancy-buttons/demo/">Brandon Mathis' fantastic Fancy Button library</a>. Brandon and <a href="http://www.oddbird.net/susy/">Susy's</a> Eric Meyer are both <a href="http://chriseppstein.github.com/blog/2010/04/11/compass-core-team/">Compass core contributors</a> now. Congratulations to both and thanks for all the fantastic code.</p>
Example SCSS (Sassy CSS) File/2010/04/09/example-scss-sassy-css-file.html2010-04-09T00:00:00ZT00:00:00-08:002010-04-09T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I'm working on a new site which will eventually run on PHP5. Going back to raw CSS isn't really an option because I value my time and sanity. Thankfully there may be a way to run Sass' new format, <a href="http://nex-3.com/posts/96-scss-sass-is-a-css-extension">SCSS</a>, under PHP using <a href="http://github.com/anthonyshort/csscaffold">Anthony Short's CSScaffold project</a></p><p>I'm working on a new site which will eventually run on PHP5. Going back to raw CSS isn't really an option because I value my time and sanity. Thankfully there may be a way to run Sass' new format, <a href="http://nex-3.com/posts/96-scss-sass-is-a-css-extension">SCSS</a>, under PHP using <a href="http://github.com/anthonyshort/csscaffold">Anthony Short's CSScaffold project</a>. The project provides a CSS preprocessor, like Sass, which runs on PHP. Currently, the project's syntax is similar, but different, than either Less or SCSS. Thankfully, Anthony has said he is working on bringing CSScaffold in-line with the SCSS syntax.</p>
<p>Happy days! I can do the early development in Sass or SCSS using their normal Ruby library and plan for a perfect future where that same stylesheet can run unmodified on the PHP-only server. If I were a Sass diehard, I could write it all in Sass and then use the new <tt>sass-convert</tt> tool to migrate to SCSS before deployment. However, I'd actually like to give SCSS a spin so I've built out the styles in plain old SCSS. The result is include below.</p>
<p>If anyone has questions or would like some more clarification on the following, <a href="mailto:me@tdreyno.com">shoot me an email</a>.</p>
<h2 id="an-example-scss-file">An Example SCSS File</h2>
<div class="highlight"><pre class="highlight plaintext"><code>@import "compass";
@import "blueprint";
@import "blueprint/fancy_type";
$blueprint-grid-columns: 5;
$blueprint-grid-width: 150px;
$blueprint-grid-margin: 20px;
$blueprint-font-family: Helvetica Neue, Arial, Helvetica, sans-serif;
$blueprint-fixed-font-family:'andale mono', 'lucida console', monospace;
$blueprint-font-size: 12px;
$text-color: #555555;
$light-text-color: #a0a0a0;
$quote-text-color: #f27a00;
$disclosure-text-color: #ed7c06;
$thick-border: 8px solid black;
$dotted-border: 1px dotted #999999;
$header-background-color: #f07c05;
$paging-background-color: black;
$unfocused-background-color: #f1f0ec;
$quote-background-color: #f1f0ec;
$story-title-color: #f07c05;
@include global-reset;
@include blueprint-typography;
body {
background: $unfocused-background-color image_url("white-bg.jpg") repeat-y 50% 0;
color: $text-color;
}
.content_wrapper {
@include container;
width: 910px;
}
#header {
height: 72px;
background: $header-background-color;
@include clearfix;
h1 {
color: white;
@include float-left;
a {
@include replace-text("logo.jpg");
width: 116px;
height: 72px;
display: block;
text-decoration: none;
}
}
ul {
@include horizontal-list;
padding: 0 0 0 25px;
li {
@include incr(18px);
padding: 0 20px 0 0;
text-transform: uppercase;
a {
color: #febf0f;
text-decoration: none;
width: 100px;
height: 72px;
display: block;
}
&#header-threads a {
@include replace-text("header-threads-text.jpg");
}
&#header-timeline a {
@include replace-text("header-timeline-text.jpg");
}
}
}
}
#paging {
background: $paging-background-color;
height: 33px;
padding: 15px 0 0 0;
h6 {
@include float-left;
color: #908f8b;
padding-right: 20px;
text-transform: uppercase;
a {
color: #f07b07;
text-decoration: none;
}
}
ul {
@include horizontal-list;
li {
padding: 3px 4px;
a {
color: #4c4c4c;
@include replace-text("thread-paging-inactive-bullet.jpg");
width: 10px;
height: 10px;
display: block;
}
&.active a {
color: #f17d06;
background-image: image_@import "compass";
}
}
}
}
#content {
position: relative;
#previous {
position: absolute;
top: 0;
left: 0;
text-align: right;
}
#next {
position: absolute;
top: 0;
right: 0;
text-align: left;
}
}
#thread {
@include container;
width: 910px;
top: 0px;
left: 0px;
@include transition-property(left);
@include transition-duration(0.5s);
@include transition-timing-function(ease-in-out);
@for $i from 0 through 30 {
&.position#{$i} {
left: ($i * -910px);
}
}
}
.js {
#content {
overflow: hidden;
width: 100%;
}
#thread {
padding: 0;
width: 5000px;
position: absolute;
}
}
.story {
@include float-left;
width: 810px;
padding: 0 50px;
h4.date {
@include float-right;
@include span(1);
background: $unfocused-background-color;
padding: 10px 20px;
@include border-radius(3px);
}
h1 {
padding: 40px 0 20px 0;
border-bottom: $thick-border;
color: $story-title-color;
@include incr(30px);
}
.artifacts {
@include column(3);
.row {
@include clearfix;
border-bottom: $dotted-border;
margin-bottom: $blueprint-grid-margin;
}
.artifact {
color: $light-text-color;
img {
margin-bottom: 0.5em;
}
a {
font-weight: bold;
text-decoration: none;
color: #0a83e0;
}
}
.threecol { @include column(3); }
.twocol { @include column(2); }
.onecol { @include column(1); }
.last { @include last; }
}
.information {
@include column(1.6, true);
border-bottom: $dotted-border;
margin-left: 40px;
h2 {
@include incr(20px, $blueprint-font-size, 35px);
}
.textblock p {
@include incr(13px, $blueprint-font-size, 26px);
}
.quote {
color: $quote-text-color;
blockquote {
@include incr(18px, $blueprint-font-size, 30px);
color: $quote-text-color;
margin: 0;
padding: 12px 18px;
background: $quote-background-color;
@include border-radius(5px);
}
cite {
display: block;
padding: 0.5em 18px 1.5em 18px;
}
}
.disclosure {
border-top: $dotted-border;
h5 {
padding: 10px 0;
margin: 0;
color: $disclosure-text-color;
}
p {
color: #a8a8a8;
}
}
}
}
#footer {
@include container;
background: white;
width: 810px;
padding: $blueprint-grid-margin 0;
.inner {
border-top: $thick-border;
padding: 30px 0;
}
p {
@include float-right;
@include incr(10px);
color: #b3b3b3;
}
ul {
@include horizontal-list;
li {
padding: 0 30px 0 0;
a {
text-decoration: none;
color: #ef7a06;
}
}
}
}
</code></pre></div>Sass 3 Syntax/2010/03/31/sass-3-syntax.html2010-03-31T00:00:00ZT00:00:00-08:002010-03-31T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><strong>Edit: Added section on hyphens and underscores as requested by <a href="http://twitter.com/chriseppstein">Chris Eppstein</a></strong></p>
<p>Today a beta for Sass 3 was released. It comes with some interesting new syntax options so let's get it installed and dive into the new syntax and directives.</p>
<h2 id="installation">Installation</h2><p><strong>Edit: Added section on hyphens and underscores as requested by <a href="http://twitter.com/chriseppstein">Chris Eppstein</a></strong></p>
<p>Today a beta for Sass 3 was released. It comes with some interesting new syntax options so let's get it installed and dive into the new syntax and directives.</p>
<h2 id="installation">Installation</h2>
<p>Go ahead and grab the Sass 3 prerelease by running:</p>
<div class="highlight"><pre class="highlight plaintext"><code>gem install haml --pre
</code></pre></div>
<h2 id="converting-old-sass-files-to-new-syntax">Converting Old Sass Files to New Syntax</h2>
<p>The old <tt>css2sass</tt> command line tool has been replaced with <tt>sass-convert</tt>. Like the old tool, <tt>sass-convert</tt> can change css files into sass files. It can also convert css files to the new, optional, scss format. Finally, it can convert between scss and sass as well as upgrading old sass files to the new syntax.</p>
<p>Converting from Sass 2 to Sass 3 is as easy as:</p>
<div class="highlight"><pre class="highlight plaintext"><code>sass-convert --in-place --from sass2 style.sass
</code></pre></div>
<p>There is also a <tt>--to</tt> flag which Sass 3 is the default. You could also convert <tt>--to scss</tt> if you wanted to experiment with that format.</p>
<h2 id="new-syntax-1-no-more-equals-signs">New Syntax #1: No more equals signs</h2>
<p>In Sass 2, lines which required parsing, contained functions or math had to begin with an equals sign instead of the normal CSS colon. Sass 3 has removed this requirement and we can all go back to using a colon for separating a style directive and it's value in CSS, Sass 3 or SCSS.</p>
<p>Before:</p>
<div class="highlight"><pre class="highlight plaintext"><code>body
background= image_url("background.png")
</code></pre></div>
<p>After:</p>
<div class="highlight"><pre class="highlight plaintext"><code>body
background: image_url("background.png")
</code></pre></div>
<h2 id="new-syntax-2-variable-prefix">New Syntax #2: Variable prefix</h2>
<p>Formerly, the way Sass defined variables was using the exclamation point prefix. However, since the exclamation point is already used in CSS (with the !important directive) it always felt a little strange to use the same symbol in two different contexts. In Sass 3, variables are now defined with the dollar sign prefix similar to PHP.</p>
<p>Before:</p>
<div class="highlight"><pre class="highlight plaintext"><code>!background_color= #ffffff
</code></pre></div>
<p>After:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$background_color: #ffffff
</code></pre></div>
<p>One nice side effect of this change is the ability to mix quoted and unquoted strings on the same line. Something I do often for font declarations and now I no longer need to wrap the whole section in an additional level of quotes.</p>
<p>Before:</p>
<div class="highlight"><pre class="highlight plaintext"><code>!font_family= "'Lucida Sans', 'Lucida Grande', arial, sans-serif"
</code></pre></div>
<p>After:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$font_family: 'Lucida Sans', 'Lucida Grande', arial, sans-serif
</code></pre></div>
<h2 id="new-syntax-3-default-variable-values">New Syntax #3: Default variable values</h2>
<p>Variable assignment used to use the ||= syntax from Ruby to only update a variable when it did not already exist. However, since the equals sign is no longer used in Sass 3, there is now a new, more CSS-like syntax for conditionally assigning a variable. Sass 3 uses a directive similar to !important, called !default, which is placed at the end of the assignment.</p>
<p>Before:</p>
<div class="highlight"><pre class="highlight plaintext"><code>!font_size ||= 12px
</code></pre></div>
<p>After:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$font_size: 12px !default
</code></pre></div>
<h2 id="new-syntax-4-interchangeable-underscores-and-hyphens">New Syntax #4: Interchangeable underscores and hyphens</h2>
<p>In the past, variables in Sass would only work with underscores used to separate the different "parts" of the variable name. This format is very Ruby-like, but I personally prefer to use hyphens in my CSS. Sass 3 allows both underscores and hyphens to be used, but there is an interesting twist. Sass 3 will allow their use interchangeably. If the variable is defined with underscores, it can still be called with hyphens. This should save some frustration for those using a Sass framework like <a href="http://compass-style.org/">Compass</a> or <a href="http://www.oddbird.net/susy/">Susy</a>. You can use whichever form you want and Sass will find the correct variable.</p>
<p>Before:</p>
<div class="highlight"><pre class="highlight plaintext"><code>!body_background_color= #000000
body
background= !body_background_color
</code></pre></div>
<p>After (either will work):</p>
<div class="highlight"><pre class="highlight plaintext"><code>$body_background_color: #000000
$text-color: #ffffff
body
background: $body-background-color
background: $body_background_color
color: $text-color
color: $text_color
</code></pre></div>
<h2 id="conclusion">Conclusion</h2>
<p>That's all for now. There are several other nice features in Sass 3 such as the integration of compass-colors, a new mixin definition and inclusion syntax and the SCSS syntax. You can read about these in the <a href="http://beta.sass-lang.com/docs/yardoc/file.SASS_CHANGELOG.html#3-0-0-syntax-changes">Sass 3 Changelog</a>. I may write about SCSS later, but I'm not a huge fan and will probably wait and let someone who has a bigger stake in the issue (those using LESS or those who adore single-line CSS) address it. </p>
A Learning Experience. iPhone-style checkboxes in Coffee-Script/2010/03/01/a-learning-experience-iphone-style-checkboxes-in-coffee-script.html2010-03-01T00:00:00ZT00:00:00-08:002010-03-01T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>According to the <a href="http://jashkenas.github.com/coffee-script/">Coffee Script website</a>, "CoffeeScript is a little language that compiles into JavaScript. Think of it as JavaScript's less ostentatious kid brother — the same genes, roughly the same height, but a different sense of style. Apart from...</p><p>According to the <a href="http://jashkenas.github.com/coffee-script/">Coffee Script website</a>, "CoffeeScript is a little language that compiles into JavaScript. Think of it as JavaScript's less ostentatious kid brother — the same genes, roughly the same height, but a different sense of style. Apart from a handful of bonus goodies, statements in CoffeeScript correspond one-to-one with their equivalent in JavaScript, it's just another way of saying it."</p>
<p>Basically, Coffee Script is compiled into Javascript and attempts to make basic operations simpler and safe. For example, in Ruby you can add a conditional to the end of the current line as a short-hand for a full <tt>if</tt> statement. In Coffee Script this looks like:</p>
<div class="highlight"><pre class="highlight plaintext"><code>number = -42 if opposite_day
</code></pre></div>
<p>Which compiles to:</p>
<div class="highlight"><pre class="highlight plaintext"><code>if (opposite_day) {
number = -42;
}
</code></pre></div>
<p>Pretty simple, right? If you're familiar with Javascript, you'll recognize Coffee Script's attempt to fix little annoyances. I dove right in and ported my iPhone-style Checkboxes for jQuery to Coffee Script. <a href="http://github.com/tdreyno/iphone-style-checkboxes/blob/master/coffee/iphone-style-checkboxes.coffee">The code can be found on GitHub</a>. Here are a few thoughts and examples I discovered. </p>
<h2 id="basic-features">Basic Features</h2>
<p>A lot of the convenience of Coffee Script is only really apparent if you're quite familiar with Javascript. The following three features are fairly common and useful in Ruby, but trying something similar in Javascript requires a bit more error-checking and code. Coffee Script hides this.</p>
<div class="highlight"><pre class="highlight plaintext"><code># Conditional assignments
expensive ||= do_the_math()
# Treating function arguments as a real array
backwards = ->
alert arguments.reverse()
# Existence conditions
solipsism = true if mind? and not world?
</code></pre></div>
<p>These are compiled to their Javascript representations.</p>
<div class="highlight"><pre class="highlight plaintext"><code># Conditional assignments
expensive = expensive || do_the_math();
# Treating function arguments as a real array
var backwards;
backwards = function backwards() {
arguments = Array.prototype.slice.call(arguments, 0);
return alert(arguments.reverse());
};
# Existence conditions
var solipsism;
if ( (typeof mind !== "undefined" && mind !== null) &&
!(typeof world !== "undefined" && world !== null)) {
solipsism = true;
}
</code></pre></div>
<h2 id="features-i-love-1-simpler-functions-this-attribute-function-binding">Features I Love #1: Simpler functions, this.attribute & function binding</h2>
<p>From here on out, I'll omit the Javascript version. Let's just look at some cool features and trust they will work when compiled. To begin, function definitions, and anonymous functions, are even simpler in Coffee Script. It's as simple as:</p>
<div class="highlight"><pre class="highlight plaintext"><code>method_name: (parameter1, parameter1, other_params...) ->
"Thanks for coming"
</code></pre></div>
<p>The method is defined by a series of parameters, a -> symbol and an indented method body. Unless you specific a return value, the last statement of the method is automatically returned, as in Ruby. The ellipsis parameter is called a Splat, this sucks up the remaining parameters that may have been passed in a groups them into an array.</p>
<p>A class is just a variation of a function in Javascript. Usually capitalized, it looks like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>Account = (customer, cart) ->
@customer = customer
@cart = cart
</code></pre></div>
<p>The Account class takes two parameters on it's constructor. The @ sign is used for accessing instance variables. In raw Javascript, this is usually handled by the <tt>this</tt> value. Maybe Javascript event libraries allow anonymous functions as callbacks, but the value of <tt>this</tt> inside these callbacks can be hard to ensure. In Coffee Script, we can force the value of <tt>this</tt>, called binding, to the current object by using a => symbol instead of -></p>
<div class="highlight"><pre class="highlight plaintext"><code> $('.shopping_cart').bind 'click', (event) =>
@customer.purchase @cart
</code></pre></div>
<p>The above code, when indented inside the Account class, will make sure the callback method has access to the instance @customer and @cart variables. <a href="http://jashkenas.github.com/coffee-script/#fat_arrow">Look on the Coffee Script site if you want to see the Javascript version of this code</a>. It's a bit rough.</p>
<h2 id="features-i-love-2-pattern-matching">Features I Love #2: Pattern Matching</h2>
<p>Next up is Pattern Matching, also known as Destructuring Assignment in the ECMAScript 4 syntax. Basically, we have an object or array and we want to pull some pieces out and into variables to work with. The simplest example is having a method that returns an array of three items.</p>
<div class="highlight"><pre class="highlight plaintext"><code>weather_report: (location) ->
# Make an Ajax request to fetch the weather...
[location, 72, "Mostly Sunny"]
[city, temp, forecast] = weather_report "Berkeley, CA"
</code></pre></div>
<p>In the above example, the weather_report function returns 3 variables which we then assign to three local variables. The structure of the template on the left-hand side mirrors the value on the right-hand side. So in the example above, we have an array of local variables on the left and an array of results from the function on the right.</p>
<p>Now lets get very complicated. Let's destructure nested objects. This can be very powerful. Here's an example nested object:</p>
<div class="highlight"><pre class="highlight plaintext"><code>futurists: {
sculptor: "Umberto Boccioni"
painter: "Vladimir Burliuk"
poet: {
name: "F.T. Marinetti"
address: [
"Via Roma 42R"
"Bellagio, Italy 22021"
]
}
}
</code></pre></div>
<p>Now, we'll pull out the pieces we want into local variables:</p>
<div class="highlight"><pre class="highlight plaintext"><code>{poet: {name: poet_name, address: [street, city]}} = futurists
</code></pre></div>
<p>This results in poet_name="F.T. Marinetti", street="Via Roma 42R" and city="Bellagio, Italy 22021"</p>
<p>I admit, I'm not used to thinking about data structures in this way, so there are probably some very cool applications which I haven't even thought of yet.</p>
<h2 id="features-i-love-3-indentation-aware-heredocs">Features I Love #3: Indentation-aware Heredocs</h2>
<p>The triple quote (from Python, I think?) starts a block of text which will be turned into a single string which has the indentation you'd expect rather than including all of the prefixed whitespace. </p>
<div class="highlight"><pre class="highlight plaintext"><code>html: '''
<strong>
cup of coffeescript
</strong>
'''
</code></pre></div>
<p>Compiles to:</p>
<div class="highlight"><pre class="highlight plaintext"><code>var html;
html = "<strong>\n cup of coffeescript\n</strong>";
</code></pre></div>
<h2 id="conclusion">Conclusion</h2>
<p>That's all I can think of right now. Make sure to check out the <a href="http://jashkenas.github.com/coffee-script/">Coffee Script docs</a>, look at <a href="http://github.com/tdreyno/iphone-style-checkboxes/blob/master/coffee/iphone-style-checkboxes.coffee">my port of iPhone-style Checkboxes</a> and invest a little time in this new language.</p>
<h2 id="welcome-to-the-year-2010-its-ascii-art-time">Welcome to the Year 2010, it's ASCII art time!</h2>
<div class="highlight"><pre class="highlight plaintext"><code> {
} } {
{ { } }
} }{ {
{ }{ } } _____ __ __
( }{ }{ { ) / ____| / _|/ _|
.- { { } { }} -. | | ___ | |_| |_ ___ ___
( ( } { } { } } ) | | / _ \| _| _/ _ \/ _ \
|`-..________ ..-'| | |___| (_) | | | || __/ __/
| | \_____\___/|_| |_| \___|\___|
| ;--.
| (__ \ _____ _ _
| | ) ) / ____| (_) | |
| |/ / | (___ ___ _ __ _ _ __ | |_
| ( / \___ \ / __| '__| | '_ \| __|
| |/ ____) | (__| | | | |_) | |_
| | |_____/ \___|_| |_| .__/ \__|
`-.._________..-' | |
|_|
</code></pre></div>Using RVM to Manage Multiple Ruby Interpreters/2010/02/17/using-rvm-to-manage-multiple-ruby-interpreters.html2010-02-17T00:00:00ZT00:00:00-08:002010-02-17T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I've been hearing a bit of buzz about the <a href="http://rvm.beginrescueend.com/rvm/install/">Ruby Version Manager</a> project on Twitter and from other Rubyists I know. Basically, the project provides a command-line tool which can download and compile a large number of Ruby implementations and swap between...</p><p>I've been hearing a bit of buzz about the <a href="http://rvm.beginrescueend.com/rvm/install/">Ruby Version Manager</a> project on Twitter and from other Rubyists I know. Basically, the project provides a command-line tool which can download and compile a large number of Ruby implementations and swap between the active implementation on a per-terminal basis.</p>
<p>This is especially useful for me as I have Ruby tools, like <a href="http://middlemanapp.com">Middleman</a>, which I need to maintain on multiple VMs. In the past, you'd have to install each VM to it's own namespace and be very careful when running them to make sure you were in the right VM. For example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>ruby: The default OSX ruby 1.8.7
ruby19: My custom-compiled ruby 1.9.1
jruby: My custom-compiled jRuby
macruby: My custom-compiled MacRuby
</code></pre></div>
<p>RVM makes managing these interpreters a snap. So here's how you get started.</p>
<h2 id="install-the-gem">Install the gem</h2>
<div class="highlight"><pre class="highlight plaintext"><code>gem install rvm
</code></pre></div>
<h2 id="run-the-installer">Run the installer</h2>
<div class="highlight"><pre class="highlight plaintext"><code>rvm-install
</code></pre></div>
<p>Follow instructions and append the output of the install to your terminal profile</p>
<div class="highlight"><pre class="highlight plaintext"><code>In ~/.profile
Add to the bottom:
if [[ -s /Users/tdreyno/.rvm/scripts/rvm ]] ; then source /Users/tdreyno/.rvm/scripts/rvm ; fi
</code></pre></div>
<p>Then, save and close ~/.profile and run:</p>
<div class="highlight"><pre class="highlight plaintext"><code>source ~/.profile
</code></pre></div>
<p>Now, you are ready to go.</p>
<h2 id="commands">Commands</h2>
<p>First, lets see which Ruby VMs the tool detected.</p>
<div class="highlight"><pre class="highlight plaintext"><code>rvm list
</code></pre></div>
<p>My output includes the built-in OSX VM.</p>
<div class="highlight"><pre class="highlight plaintext"><code>System Ruby
system [ x86_64 i386 ppc ]
</code></pre></div>
<p>Now, I want to install some more Rubies.</p>
<div class="highlight"><pre class="highlight plaintext"><code>rvm install 1.9.1,rbx,jruby,macruby
</code></pre></div>
<p>A couple of minutes later, you'll have 5 different Ruby VMs installed. RBX is Rubinius and the others should be self-explanatory.</p>
<h2 id="swapping-vms">Swapping VMs</h2>
<p>To change between the active VM, simply run:</p>
<div class="highlight"><pre class="highlight plaintext"><code>rvm use 1.9.1
</code></pre></div>
<p>And now <code>ruby -v</code> returns "ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-darwin10.2.0]"</p>
<p>In my case, I can now run my Cucumber tests against my library and verify that it's working with Ruby 1.9.1.</p>
<p>To return to your original VM, run:</p>
<div class="highlight"><pre class="highlight plaintext"><code>rvm use system
</code></pre></div>
<p>Be aware that each VM probably has it's own gems. So you'll need to be aware of that and try to keep each VM's gems in sync.</p>
Best Albums of the Decade. Top 25/2009/12/14/best-of-the-decade-pt2.html2009-12-14T00:00:00ZT00:00:00-08:002009-12-14T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>And now for the top 25.</p>
<ul class="albums">
<li>
<div class="cover">
<img src="/albums/25.jpg">
</div>
<div class="content">
<h6>2008</h6>
<h4>Of Montreal - Skeletal Lamping</h4>
<p>I flip-flopped on the position of the two Of Montreal albums several times. As bizarre and cross-genre as the band is, this album feels like "more of...</p>
</div>
</li>
</ul><p>And now for the top 25.</p>
<ul class="albums">
<li>
<div class='cover'>
<img src='/albums/25.jpg' />
</div>
<div class='content'>
<h6>2008</h6><h4>Of Montreal - Skeletal Lamping</h4>
<p>I flip-flopped on the position of the two Of Montreal albums several times. As bizarre and cross-genre as the band is, this album feels like "more of the same" from Hissing Fauna. However, it's also much better and maybe even easier to sing along to if you can parse the words.</p>
</div>
<div class='player'>
<h6>#25</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/24.jpg' />
</div>
<div class='content'>
<h6>2007</h6><h4>Menomena - Friend and Foe</h4>
<p>Local Portland three-piece who sound like a cross between a Jazz band and The Mars Volta. Given the amount of instruments on the album, I was blown away to see the three of them pull it off live. It's my understanding that they're working on a follow-up album. I can't wait.</p>
</div>
<div class='player'>
<h6>#24</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/23.jpg' />
</div>
<div class='content'>
<h6>2006</h6><h4>Gospel - The Moon is a Dead World</h4>
<p>I've fallen hard for post-hardcore and for some reason I really enjoy listening to it in unexpected locations. I feel asleep on the plane listening to Maths on repeat. I wandered around the beach in Hawaii listening to Gospel. Something about it feels so epic, even if it's just some guy screaming. Unfortunately the band is not longer together.</p>
</div>
<div class='player'>
<h6>#23</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/22.jpg' />
</div>
<div class='content'>
<h6>2006</h6><h4>Brand New - The Devil and God Are Raging Inside Me</h4>
<p>I'm not sure I actually like this band as I don't like their previous work and I don't like their follow-up album "Daisy." Still, I put this on when I'm in a bad mood. The title seems to fit perfectly.</p>
</div>
<div class='player'>
<h6>#22</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/21.jpg' />
</div>
<div class='content'>
<h6>2000</h6><h4>A.F.I. - The Art of Drowning</h4>
<p>
I've been listening to this album for 10 years. Unlike a lot of the stuff on this list which I discovered later, I think The Art of Drowning might have been my first real punk purchase. Blink 182 and Green Day don't count. The album further refines Black Sails in the Sunset and is the last decent AFI album until this year's Crash Love. Still, even the best parts of Crash Love make me want to put The Art of Drowning on instead.
</p>
</div>
<div class='player'>
<h6>#21</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/20.jpg' />
</div>
<div class='content'>
<h6>2005</h6><h4>Gorillaz - Demon Days</h4>
<p>How awesome is Danger Mouse? I liked the first Gorillaz album and I love Dan the Automator, but Demon Days is on a whole other level. The album alternates between poppy tracks with hip-hop guests and spacey electronic songs. If you hate diversity, Damon's The Good, the Bad & the Queen is basically an entire album of the spacey songs. Furthermore, Fire Coming Out of a Monkey's Head might be the most enjoyable spoken-word track of all time. It doesn't hurt that King Koopa is reading it.</p>
</div>
<div class='player'>
<h6>#20</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/19.jpg' />
</div>
<div class='content'>
<h6>2007</h6><h4>The World/Inferno Friendship Society - Addicted to Bad Ideas</h4>
<p>These gypsy punk-rockers from NY have always created enjoyable albums, but their energy and multitude of artists and instruments have always been a bit out of control. This concept album (and possible musical) about the life of Peter Lorre reins them in and gives the album an easy narrative to follow all the way up to the sad finale "Heart Attack '64."</p>
</div>
<div class='player'>
<h6>#19</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/18.jpg' />
</div>
<div class='content'>
<h6>2001</h6><h4>Rx Bandits - Progress</h4>
<p>My favorite band, probably one of my first concerts and definitely my driving soundtrack for 3-4 years. Progress began the transition from generic 3rd wave ska band to progressive rock gods. I don't think the Rx Bandits have rocked this hard until some of the guitar-driven stuff on 2009's Mandala. This is also Steve Choi's first with the band. Despite the fact that he didn't actually record on the album, it's nice to know he was around. His influence on the later albums completes the bands transition.</p>
</div>
<div class='player'>
<h6>#18</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/17.jpg' />
</div>
<div class='content'>
<h6>2005</h6><h4>Death Cab for Cutie - Plans</h4>
<p>For what sounds like an incredibly depressing album, I usually finish it feeling uplifted. The Postal Service wrenches my heart a little ever time, but Plans makes me smile. I can't really get into Transatlanticism and Narrow Stairs was a misfire in my opinion, but Plans is something I imagine I'll be listening to long into the next few decades.</p>
</div>
<div class='player'>
<h6>#17</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/16.jpg' />
</div>
<div class='content'>
<h6>2008</h6><h4>La Dispute - Somewhere at the Bottom of the River Between Vega and Altair</h4>
<p>Does anyone else know this band exists? The band fulfills all my 2000s requirements: post-hardcore, concept album and a cohesive listen all the way through. I don't think they've toured in Portland yet, but I'm still hopeful. I imagine the live show must be epic. This album is all about loss and anger. Here's hoping I'm never in a position where this becomes my soundtrack, but atleast it should be cathartic to scream along.</p>
</div>
<div class='player'>
<h6>#16</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/15.jpg' />
</div>
<div class='content'>
<h6>2008</h6><h4>Girl Talk - Feed the Animals</h4>
<p>A perfect, polished improvement over Night Ripper. This is the definitive mash-up album. Greg uses a lot more classic songs and rock samples while still maintaining the perfect balance and juxtaposition with various rappers on top. Lil Wayne's Lollipop over Red Hot Chili Peppers? Perfect.</p>
</div>
<div class='player'>
<h6>#15</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/14.jpg' />
</div>
<div class='content'>
<h6>2009</h6><h4>Rx Bandits - Mandala</h4>
<p>The climax to a decade of refinement and improvement. The band may have lost all of its horns, but that has unleashed the guitars. Like ...And the Battle Begun and The Resignation, this album was recorded "live" with the band rehearsing until they were confident enough to record it in one shot. The result, as before, is an incredibly organic album, complete with human flaws, missed notes and a perfect representation of their wonderful live show.</p>
</div>
<div class='player'>
<h6>#14</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/13.jpg' />
</div>
<div class='content'>
<h6>2003</h6><h4>The Postal Service - Give Up</h4>
<p>I've been to DC and I quite enjoyed it. If I were to attempt to wander the streets listening to this album, I may just end up in a corner hiding from people. This is the ultimate break-up album, but it's not encouraging in any way. I usually end up thinking "I am a fool and an asshole" at the end. Gibbard convinces you that it's all your fault and I'm not sure there is a rainbow at the end. I usually try to avoid listening to this when I'm sad, but I guess misery loves company.</p>
</div>
<div class='player'>
<h6>#13</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/12.jpg' />
</div>
<div class='content'>
<h6>2006</h6><h4>Head Automatica - Popaganda</h4>
<p>Another follow-up album that decided to dump Dan the Automator. And yet, like Demon Days, it's better for it. Popaganda does exactly what it claims to, takes Daryl Palumbo of Glassjaw's eccentricity and stuffs it into a pop-rock box.</p>
</div>
<div class='player'>
<h6>#12</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/11.jpg' />
</div>
<div class='content'>
<h6>2000</h6><h4>Deltron - Deltron 3030</h4>
<p>Hey look, more Dan the Automator! Del the Funkee Homosapien created the definitive hip hop concept album with this loose collection of songs about life in the year 3030, Del's life as a mech warrior and the oppressive regime that true artists must fight against. It's been 10 years and Del has been claiming Deltron Event II is mostly complete. I can't wait.</p>
</div>
<div class='player'>
<h6>#11</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/10.jpg' />
</div>
<div class='content'>
<h6>2004</h6><h4>mewithoutYou - Catch For Us the Foxes</h4>
<p>My first post-hardcore album. Basically, one brother asked his other brother to read his poetry (loudly) over his band's rock. The outcome is just pitch perfect.</p>
</div>
<div class='player'>
<h6>#10</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/09.jpg' />
</div>
<div class='content'>
<h6>2003</h6><h4>Rx Bandits - The Resignation</h4>
<p>I feel like I've already said enough about the Rx Bandits. This one was the first recorded "live" and ends with the massive build-up of Decrescendo. I'm also happy to see folks in 2003 complaining about America's wars.</p>
</div>
<div class='player'>
<h6>#9</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/08.jpg' />
</div>
<div class='content'>
<h6>2005</h6><h4>The Mars Volta - Frances the Mute</h4>
<p>I don't really know how to describe Mars Volta albums. Super-long songs. Unintelligible vocals. Epic.</p>
</div>
<div class='player'>
<h6>#8</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/07.jpg' />
</div>
<div class='content'>
<h6>2004</h6><h4>Leftover Crack - Fuck World Trade</h4>
<p>My favorite gutter-punks crafted a surprisingly coherent and beautiful album. There are piano interludes and songs about killing cops. Still waiting on a follow-up, but Star Fucking Hipsters are enough to hold me over.</p>
</div>
<div class='player'>
<h6>#7</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/06.jpg' />
</div>
<div class='content'>
<h6>2008</h6><h4>Why? - Alopecia</h4>
<p>Clever, hipster, jewish hip hop. What more do you need to know? Look at these lyrics:</p>
<pre>i know, i know
there's nothing more appealing
than the sound of high heels
down the marble tile hallways
of your distict's one allotted
city funded steiner school bilingual
or montessori followed by
a single high pitched scream
followed by breaking glass
but could your anger be mapped
into an interpretive dance
to a trip hop track
could it be bowed out on strings
or strung into a pattern
for a god's eye to bring to
your alma mater's holiday fundraiser boutique thing</pre>
</div>
<div class='player'>
<h6>#6</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/05.jpg' />
</div>
<div class='content'>
<h6>2006</h6><h4>Justin Timberlake - Futuresex/Lovesounds</h4>
<p>Pop music in the later-half of this decade was defined by Justin Timberlake. Yes, I'm counting Dick in a Box as well. Hip hop music in the same period was defined by Timbaland. This collaboration setup the new king of pop and fully erased his boy-band history. Will there be a follow-up? I hope so.</p>
</div>
<div class='player'>
<h6>#5</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/04.jpg' />
</div>
<div class='content'>
<h6>2007</h6><h4>Bloc Party - A Weekend in the City</h4>
<p>While Silent Alarm is a great album, A Weekend in the City is really an experience. The perfect rainy-day album, whether you're in London or not. I think I could leave this on repeat for an entire weekend. There is also an instrumental version which is wonderful in a completely different way.</p>
</div>
<div class='player'>
<h6>#4</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/03.jpg' />
</div>
<div class='content'>
<h6>2000</h6><h4>At the Drive-In - Relationship of Command</h4>
<p>ATDI's last album. After finally achieving mainstream success with "One Armed Scissor," they promptly imploded. There's never been anything like ATDI before or since. A different monster than Mars Volta, even if they share random, crazy-person lyrics.</p>
</div>
<div class='player'>
<h6>#3</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/02.jpg' />
</div>
<div class='content'>
<h6>2006</h6><h4>The Format - Dog Problems</h4>
<p>I've been listening to these guys since we were both in high school. We were even neighbors for a short time. Probably the only Phoenix, AZ band worth a damn. The band finally broke out with Interventions + Lullabies and nearly collapsed from the pressure. So they took a step back and decided to have fun. Dog Problems is the result, incorporating a ton of instruments, whimsical flourishes, a little bit of Beach Boys, a little Bowie and a lot of fun. Nate's new band, actually named "fun," follows the same formula, but probably needs a few more albums to mature.</p>
</div>
<div class='player'>
<h6>#2</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/01.jpg' />
</div>
<div class='content'>
<h6>2005</h6><h4>Say Anything - ...Is a Real Boy</h4>
<p>Who am I to argue with statistics. According to last.fm, I listened to this album way more than any other album. I love all the Say Anything albums, but this one is a little more rough and angry, which is a good thing. The new, married, happier Max Bemis is still great, but I enjoy his disgust.</p>
</div>
<div class='player'>
<h6>#1</h6>
</div>
</li>
</ul>
Best Albums of the Decade/2009/12/04/best-of-the-decade.html2009-12-04T00:00:00ZT00:00:00-08:002009-12-04T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>In 1990, I was 7 years old. Needless to say, by 17 I still didn't have the most refined musical tastes. I'm just now getting into Pavement, Jawbox and My Bloody Valentine. So, this past decade has been my first where I can remember listening to each...</p><p>In 1990, I was 7 years old. Needless to say, by 17 I still didn't have the most refined musical tastes. I'm just now getting into Pavement, Jawbox and My Bloody Valentine. So, this past decade has been my first where I can remember listening to each of the following albums when they were released. Most of the lists I've seen so far are exceptionally myopic, with albums mostly from the past 3-4 years and enjoy Radiohead to look cool. My list is hopefully more diverse. I've also used my actual listening habits (courtesy of last.fm) for ranking, rather than pretending I actually listened to The White Stripes ever single day like some lists.</p>
<p>Let's get started, with numbers 50-26:</p>
<ul class="albums">
<li>
<div class='cover'>
<img src='/albums/50.jpg' />
</div>
<div class='content'>
<h6>2005</h6><h4>Panic at the Disco - A Fever You Can't Sweat Out</h4>
<p>Listening to this recently, the autotune burned my ears, but I can't pretend I didn't have this on repeat when it came out. It's pretty cheesy, but the non-autotuned vocals are catchy and the songs varied. Their sophomore album tried to prove they had actual talent by simplifying their sound and foregoing the autotune, but it wasn't nearly as fun as this.</p>
</div>
<div class='player'>
<h6>#50</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/49.jpg' />
</div>
<div class='content'>
<h6>2006</h6><h4>Mogwai - Mr Beast</h4>
<p>One of my favorite post-rock albums and an album that sat in my record player for months on end. I'm not sure I could explain it if I wanted to. It's post rock, it climaxes and the timing is just about perfect on this album.</p>
</div>
<div class='player'>
<h6>#49</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/48.jpg' />
</div>
<div class='content'>
<h6>2002</h6><h4>Bad Religion - The Process of Belief</h4>
<p>The last half of the 90s were pretty hard on Bad Religion. Maybe they were just busy working on other things. The return of Brett Gurewitz on guitar helped propel their comeback. The first 3 songs work great together and are usually played in rapid succession live. I think this is their best work this decade, but The Empire Strikes First and New Maps of Hell are no slouches either.</p>
</div>
<div class='player'>
<h6>#48</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/47.jpg' />
</div>
<div class='content'>
<h6>2006</h6><h4>Scissor Sisters - Ta-Dah</h4>
<p>I once described this as the "gayest album I play loud and sing along to" and if you've scanned ahead, you'll know Justin Timberlake is on this list. So that's saying something. This disco-y album with Elton John on a lot of the tracks and featuring far too graphic sexual lyrics is just too much fun. Also, the "I Can't Decide" sing-along The Master had in that Dr. Who finale was just plain awesome.</p>
</div>
<div class='player'>
<h6>#47</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/46.jpg' />
</div>
<div class='content'>
<h6>2005</h6><h4>Transplants - Haunted Cities</h4>
<p>Both Transplants albums came out this decade. The self-titled is excellent, but despite their best efforts it's still a punk album. However, they hit the nail on the head in their second attempt. This is an Oakland hip hop album. Travis Barker on drums kicks the shit out of any studio drum machine.</p>
</div>
<div class='player'>
<h6>#46</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/45.jpg' />
</div>
<div class='content'>
<h6>2001</h6><h4>System of a Down - Toxicity</h4>
<p>System of a Down hit their stride on Toxicity after an excellent, manic self-titled album in the late 90s. How much strong material did they write? Well, they released a 16-song collection of B-sides called "Steal This Album!" a year later and it's almost good enough to be on this list as well. Their later double-albums Memorize & Hypnotize are excellent, but the band's dynamic was different. So I'm sticking with this classic SOAD.</p>
</div>
<div class='player'>
<h6>#45</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/44.jpg' />
</div>
<div class='content'>
<h6>2005</h6><h4>Mindless Self Indulgence - You'll Rebel To Anything</h4>
<p>Frankenstein Girls Will Seem Strangely Sexy should be on this list. It's awesome, but it came out in 2000 and I remember listening to it on Winamp so maybe it's just too 90s. Instead, I'm going with their follow-up. A band known for vile, 90 seconds songs of pure IDM madness decided to make 10, very polished, well-produced songs.</p>
</div>
<div class='player'>
<h6>#44</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/43.jpg' />
</div>
<div class='content'>
<h6>2004</h6><h4>My Chemical Romance - Three Cheers for Sweet Romance</h4>
<p>This album rips all the way through. It's speed and length matched perfectly up to my normal workout, so this was my default playlist for several years. It helps that I'm a sucker for comic books and concept albums and this album combines both.</p>
</div>
<div class='player'>
<h6>#43</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/42.jpg' />
</div>
<div class='content'>
<h6>2007</h6><h4>Of Montreal - Hissing Fauna, Are You the Destroyer?</h4>
<p>I'm not sure I could even describe this album or band. Dancey, poppy, random genres, disjointed, nonsense lyrics and pure awesome. This might be the most musically creative band on this list. It makes me feel boring.</p>
</div>
<div class='player'>
<h6>#42</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/41.jpg' />
</div>
<div class='content'>
<h6>2000</h6><h4>Deftones - White Pony</h4>
<p>Maybe this belongs in the 90s, but Deftones finally got it right in 2000 and I'm not going to take that away from them. This dark and violent album is all the more creepy thanks to Chino's soft voice and a guest spot from king of singing, Maynard James Keenan.</p>
</div>
<div class='player'>
<h6>#41</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/40.jpg' />
</div>
<div class='content'>
<h6>2008</h6><h4>The Mae Shi - Hlllyh</h4>
<p>I love punk rock, but there were only a couple options left to the genre this decade. Either it could follow Blink 182 into the realm of pop, put out retro albums like Bad Religion, NOFX and Propagandhi or cross-pollinate with the electronic scene like Panic! at the Disco. The Mae Shi chose the latter and create a manic, sometimes melodic, album that rocks all the way through.</p>
</div>
<div class='player'>
<h6>#40</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/39.jpg' />
</div>
<div class='content'>
<h6>2004</h6><h4>Sum 41 - Chuck</h4>
<p>Actually, there was one other option for punk bands, but I think Sum 41 was the only one that tried it. They decided to become a metal band. The vocals and melody remain true to the band's pop-punk style, but the guitars decided to imitate those of punk's former worst enemy. I'm a huge fan of this album, it's too bad it didn't go over well and the band has returned to their immature pop-punk style.</p>
</div>
<div class='player'>
<h6>#39</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/38.jpg' />
</div>
<div class='content'>
<h6>2007</h6><h4>Fall Out Boy - Infinity on High</h4>
<p>This decade's king of pop-punk decided to give up any illusion of punk and had hip-hop producer Babyface produce this album. The intro features Jay-Z and the guitars have mostly been muddled into an electronic sound or mixed out. The thing is, they made a perfect pop album and it's fun. Their follow-up, Folie á Deux is also excellent and even more polished, if not as cohesive.</p>
</div>
<div class='player'>
<h6>#38</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/37.jpg' />
</div>
<div class='content'>
<h6>2002</h6><h4>Queens of the Stone Age - Songs for the Deaf</h4>
<p>When people shit on "Rock music," I can't help but argue because this is the album I hear in my head. Needless to say, it rocks and Dave Grohl on drums pushes it up to 11.</p>
</div>
<div class='player'>
<h6>#37</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/36.jpg' />
</div>
<div class='content'>
<h6>2007</h6><h4>Big D and the Kids Table - Strictly Rude</h4>
<p>I should have put every Big D album on this list. Somehow they are all equally good and yet always different. Strictly Rude builds on How it Goes's departure from loud punk, but it also brings in a UK-ska feel. 15 great songs. 2009's Fluent in Stroll is excellent too, with it's surf-ska-rock feel, but it's a little too recent to be a classic already.</p>
</div>
<div class='player'>
<h6>#36</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/35.jpg' />
</div>
<div class='content'>
<h6>2001</h6><h4>Ozma - Rock and Rock Part 3</h4>
<p>Everyone knows the absolute failure Weezer has been this decade, but at the beginning we had Ozma to make up for it. This album isn't entirely cohesive, but there are so many gems, including the epic Baseball. You owe it to yourself to listen to it.</p>
</div>
<div class='player'>
<h6>#35</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/34.jpg' />
</div>
<div class='content'>
<h6>2003</h6><h4>The Mars Volta - De-Loused in the Comatorium</h4>
<p>Speaking of bands I failed to get into until it was too late, At the Drive-In broke up in 2001 after finally making it "big." Thankfully the core of the band continued as The Mars Volta. Swapping crazy punk-ish rock for progressive rock. The insane vocals remained. This is another concept album, so you know I can't help but love it.</p>
</div>
<div class='player'>
<h6>#34</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/33.jpg' />
</div>
<div class='content'>
<h6>2002</h6><h4>Common Rider - This is Unity Music</h4>
<p>I've already mentioned The Transplants, which featured former Operation Ive member Tim Armstrong. Thankfully, Jesse formed a new band as well. Common Rider is vaguely ska, but mostly held together by Jesse's vocals. Their debut, Last Wave Rockers, is excellent as well, but it came out in 1999.</p>
</div>
<div class='player'>
<h6>#33</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/32.jpg' />
</div>
<div class='content'>
<h6>2007</h6><h4>The National - Boxer</h4>
<p>Along with shoegaze, post-punk made a little comeback this decade. The National is doing it better than anyone else right now. Sorry Interpol, you got outdone.</p>
</div>
<div class='player'>
<h6>#32</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/31.jpg' />
</div>
<div class='content'>
<h6>2006</h6><h4>Clint Mansell (w/ Mogwai & Kronos Quartet) - The Fountain (Music from the Motion Picture)</h4>
<p>Holy crap! As if post-rock albums weren't epic enough, they had to write one about a century-spanning romantic, sci-fi beauty. The music perfectly matches the movie and the crescendo of the album (and film), "Death Is The Road To Awe" can't be beat.</p>
</div>
<div class='player'>
<h6>#31</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/30.jpg' />
</div>
<div class='content'>
<h6>2005</h6><h4>Kanye West - Late Registration</h4>
<p>Kanye's most consistent and best produced work. Featuring folks like Michel Gondry and Jon Brion ridding shotgun. 808s and Heartbreak is very interesting, but I'm going with "classic" Kanye.</p>
</div>
<div class='player'>
<h6>#30</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/29.jpg' />
</div>
<div class='content'>
<h6>2003</h6><h4>The Distillers - Coral Fang</h4>
<p>The definitive break-up album. The album was written during, and focusing on, the lead singer's divorce from Transplant's Tim Armstrong and new relationship with Queens of the Stone Age's Josh Homme. I seriously hope I never make a woman as angry as Brody is on this album.</p>
</div>
<div class='player'>
<h6>#29</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/28.jpg' />
</div>
<div class='content'>
<h6>2006</h6><h4>The Dresden Dolls - Yes Virginia</h4>
<p>The terrific twosome reigned in their self-title's burlesque punk sounds and creates this quirky masterpiece. The first half bounces around with great piano pieces and weird, chirping vocals. The second half slows down a little, but it's still great.</p>
</div>
<div class='player'>
<h6>#28</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/27.jpg' />
</div>
<div class='content'>
<h6>2001</h6><h4>Leftover Crack - Mediocre Generica</h4>
<p>The band's "tower-toppling release of 9/11/01" is one of the best punk albums of the decade and one of the best ska-punk albums of all time. Styz's anti-religion, anti-intolerance and pro-anarchy lyrics are top notch.</p>
</div>
<div class='player'>
<h6>#27</h6>
</div>
</li>
<li>
<div class='cover'>
<img src='/albums/26.jpg' />
</div>
<div class='content'>
<h6>2009</h6><h4>Portugal the Man - The Satanic Satanist</h4>
<p>One of those albums that you can leave on repeat for hours accidentally. Sublimely cohesive.</p>
</div>
<div class='player'>
<h6>#26</h6>
</div>
</li>
</ul>
The Middleman. A modular, feature-rich static site generator/2009/10/22/middleman.html2009-10-22T00:00:00ZT00:00:00-08:002009-10-22T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><strong>Update: <a href="/2011/08/08/middleman-2-0.html">Middleman version 2.0 has been released</a></strong><br>
<strong>Update: <a href="/2011/04/15/middleman-v11.html">Middleman version 1.1 has been released</a></strong><br>
<strong>Update: New <a href="https://convore.com/middleman/">Middleman Support Forum</a></strong></p>
<p>Developing large sites can be a tedious process. First of all, a large portion of each page will contain some amount...</p><p><strong>Update: <a href="/2011/08/08/middleman-2-0.html">Middleman version 2.0 has been released</a></strong><br />
<strong>Update: <a href="/2011/04/15/middleman-v11.html">Middleman version 1.1 has been released</a></strong><br />
<strong>Update: New <a href="https://convore.com/middleman/">Middleman Support Forum</a></strong></p>
<p>Developing large sites can be a tedious process. First of all, a large portion of each page will contain some amount of shared code. You have site-wide navigation, footers, javascript and CSS. Within those sections you may have other common data such as color schemes, asset paths and tracking codes. Experienced developers will see this problem coming from a mile away and start the project with site-wide constants and common components separated into their own reusable files. This works pretty well if you are developing in the same framework or language that the site will eventually operate under in production, but what if your job is strictly front-end and you have no advanced knowledge of the backend which will display your pages?</p>
<p>The two most common approaches I've encountered are to develop every page statically with shared components repeated in each and every file. Alternatively, many developers assume global familiarity with PHP or ASP and use some form of Server-Side Include for shared components. The situation gets a bit trickier for global constants and shared paths. I've seen PHP variables scattered throughout a site. I've also seen IDE-specific includes (like Textmate's) used for shared content and variables. </p>
<p>These approaches have a couple problems. First, they assume the client cares what technology you use. Second, they require you to deploy the site to a web-server before the client can preview the design. And finally, the backend team will probably be frustrated with your PHP unless they just so happen to use it as well.</p>
<p>The solution is to use strong backend tools and concepts like variables, helper functions, layouts (or MasterPages) and javascript/css minifiers while still delivering plain old, static HTML to the client.</p>
<h2 id="existing-solutions">Existing solutions</h2>
<p>The Ruby world already has a handful of tools which accomplish this. The two most common, in my opinion, are <a href="http://staticmatic.rubyforge.org/">StaticMatic</a> and <a href="http://nanoc.stoneship.org/">Nanoc</a>. I have far more experience with StaticMatic so I'll talk about that first.</p>
<p>StaticMatic is heavily inspired by Ruby on Rails and performs it's task in a similar, but still slightly different, way. I've used StaticMatic for years, contributed to it's codebase and converted anyone who would listen to using it. It allowed me to use Haml & Sass in static pages and I loved it. However, I have my own opinions and StaticMatic does a lot of little things differently than I'd like. Rather than fork that project or complain online, I wrote my own replacement which fits my style of development more closely. Apples and oranges in my opinion, but maybe other developers will be more at home with Middleman, like I am.</p>
<p>Nanoc, on the other hand, looks very, very powerful. Unfortunately, I've been frequently overwhelmed by the <a href="http://nanoc.stoneship.org/manual/">documentation</a> and feature set. Like I said above, I'm scratching my own itch and Nanoc provided a lot more than I needed while requiring a lot of Ruby-writing to work with. I see Middleman as the Sinatra of the static deployment world. There are bigger, and arguably better, systems out there, but my niche is small, easy to learn and fast.</p>
<h2 id="middleman">Middleman</h2>
<p>The best way to describe Middleman is to show you how I use it. I'll show you how to install it a little further down. The <tt>mm-init</tt> command takes a single argument, the directory which will contain your new project. If I run that command from the terminal, I will get the following:</p>
<div class="highlight"><pre class="highlight plaintext"><code># mm-init .
Generating with setup generator:
[ADDED] init.rb
[ADDED] views/index.html.haml
[ADDED] views/layout.haml
[ADDED] views/stylesheets/site.css.sass
[ADDED] public/stylesheets
[ADDED] public/javascripts
[ADDED] public/images
</code></pre></div>
<p>The initializer creates a homepage (index.html.haml), a layout to contain shared interface elements and a site-wide stylesheet. As you can see, Haml and Sass are the default templating languages. However, you're free to replace .haml with .erb and use Erb templates or enable additional renderers like Markdown (more on this later). The Sass support comes with Compass bundled to provide a large number of css frameworks such as YUI, Blueprint, 960.gs, Susy and more.</p>
<p>The init.rb file allows customization and enabling or disabling specific features. The default init.rb looks like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code># Helpers
helpers do
end
# Generic configuration
# enable :slickmap
# Build-specific configuration
configure :build do
# For example, change the Compass output style for deployment
# enable :minified_css
# Or use a different image path
# set :http_path, "/Content/images/"
# Disable cache buster
# disable :cache_buster
end
</code></pre></div>
<p>Helpers are functions which can be called from your templates and allow you to abstract frequently repeated code. Middleman comes with a handful, most for asset management, but you can write your own within the helpers block in the init.rb.</p>
<p>Next is the commented-out <a href="http://astuteo.com/slickmap/">Slickmap</a> feature. If you remove the comment, your structure will be parsed and a sitemap will automatically be generated for you. There are many other features you can enable or disable and this is the place to do it.</p>
<p>Finally, there is the configure block which allows variables, helpers and features to be modified only during the final static HTML build process. The example init.rb offers css minification, cache busting and changing the location of your assets in production (if you're using a CDN).</p>
<h2 id="configuration-an-example">Configuration & an Example</h2>
<p>The <tt>mm-init</tt> command creates an init.rb which will contain your customizations and configuration.</p>
<p>Below is an example init.rb that I am using on a live client site. First, I include a couple files with helper definitions. Next I enable php files to be previewed and choose the default template for directory requests. For this project, I have chosen to place all static files under the "assets" folder. The asset_url helper is overridden to ignore a couple cases specific to this site. Finally, I setup the directory under which the site will live in production. That's it! Nearly 200 pages with a shared layout, simple Haml templates, Blueprint-base CSS grids, minified CSS, Javascript dependency management and minification, CDN support and cache busting query strings.</p>
<div class="highlight"><pre class="highlight plaintext"><code>require 'config/path_helpers'
require 'config/haml_helpers'
mime :php, "text/html"
set :index_file, "index.php"
set :images_dir, "assets/images"
set :css_dir, "assets/stylesheets"
set :videos_dir, "assets/videos"
set :js_dir, "assets/javascripts"
configure :build do
set :http_prefix, "/sites/billboard"
enable :automatic_image_sizes
end
</code></pre></div>
<h2 id="features">Features</h2>
<p>As you can see, the basic project is quite sparse and you get to choose which features your project needs.
The current list of features is as follows:</p>
<div class="highlight"><pre class="highlight plaintext"><code># Features enabled by default
enable :compass
enable :sprockets
# Features disabled by default
disable :slickmap
disable :cache_buster
disable :minify_css
disable :minify_javascript
disable :relative_assets
disable :maruku
disable :automatic_image_sizes
disable :minify_css
disable :minify_javascript
disable :cache_buster
</code></pre></div>
<p>More documentation on these features and what they enable can be found <a href="http://middlemanapp.com">on the project website</a>.</p>
<h2 id="development-process">Development Process</h2>
<p>So, the quickest way to get started is to run <tt>mm-init</tt> and point it at a location for your new project. Then change directories into that project and run <tt>mm-server</tt>. Now you can develop your site and preview the results on localhost:4567. Finally, when you're ready to deliver raw HTML, run <tt>mm-build</tt> from the project folder. Here's an example.</p>
<div class="highlight"><pre class="highlight plaintext"><code>Gir:~ tdreyno$ mm-init new_project
Generating with setup generator:
[ADDED] init.rb
[ADDED] views/index.haml
[ADDED] views/layout.haml
[ADDED] views/stylesheets/site.sass
[ADDED] public/stylesheets
[ADDED] public/javascripts
[ADDED] public/images
Gir:~ tdreyno$ cd new_project/
Gir:new_project tdreyno$ mm-server
== Local config at: /Users/tdreyno/new_project/init.rb
== The Middleman is standing watch on port 4567
>> Thin web server (v1.2.4 codename Flaming Astroboy)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
Gir:new_project tdreyno$ mm-build
== Local config at: /Users/tdreyno/new_project/init.rb
Generating with build generator:
[ADDED] index.html
[ADDED] stylesheets/site.css
>> Thin web server (v1.2.4 codename Flaming Astroboy)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
</code></pre></div>
<h2 id="source-bug-reports">Source & bug reports</h2>
<p>The code, as always, is on GitHub at: <a href="http://github.com/middleman/middleman">http://github.com/middleman/middleman</a>.<br />
There is also a wiki at: <a href="http://wiki.github.com/middleman/middleman">http://wiki.github.com/middleman/middleman</a>.<br />
And finally, please report bugs to: <a href="http://github.com/middleman/middleman/issues">http://github.com/middleman/middleman/issues</a>.</p>
Tweetie-style paging with pageSlider/2009/08/31/pageslider-tweetie-style-pages.html2009-08-31T00:00:00ZT00:00:00-08:002009-08-31T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><a href="http://www.atebits.com/tweetie-mac/">Tweetie for Mac</a> is one of my favorite programs. However, it is also one of the least Mac-like applications I use. Instead of standard interactions, such as a tab control, for switching modes, Tweetie uses an iPhone-inspired
vertical slide. This is...</p><p><a href="http://www.atebits.com/tweetie-mac/">Tweetie for Mac</a> is one of my favorite programs. However, it is also one of the least Mac-like applications I use. Instead of standard interactions, such as a tab control, for switching modes, Tweetie uses an iPhone-inspired
vertical slide. This is similar to the various carousel scripts around the web, but vertical rather than horizontal.</p>
<p>I recently need a little bit of gloss on a rather plain website, so I borrowed the effect. You can see the code implemented on the <a href="http://www.jivesoftware.com/jiveworld/faqs">JiveWorld09</a> conference site. You can also see the effect in the screencast below:</p>
<div class='flash'>
<object height='404' width='400'>
<param name='allowfullscreen' value='true' />
<param name='allowscriptaccess' value='always' />
<param name='movie' value='http://vimeo.com/moogaloop.swf?clip_id=6371313&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1' />
<embed allowfullscreen='true' allowscriptaccess='always' height='404' src='http://vimeo.com/moogaloop.swf?clip_id=6371313&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1' type='application/x-shockwave-flash' width='400'></embed>
</object>
</div>
<h2 id="the-source">The Source</h2>
<p>You can grab the code on Github at<a href="http://github.com/tdreyno/pageSlider">http://github.com/tdreyno/pageSlider</a>
or in <a href="http://cloud.github.com/downloads/tdreyno/pageSlider/pageSlider.zip">this zip file</a>.</p>
<h2 id="how-to-use">How to Use</h2>
<p>First, and foremost, you will need jQuery and jQuery.history to provide the back-button support. These are included on GitHub and in the downloadable zip file.</p>
<p>The code is implemented as a jQuery plugin which is called on a collection of pages in the current html document. You must have a div which contains the pages (defaults to having an id of <tt>maincontent</tt>) and then you will select the pages and apply the plugin. In the example below, each page has a class of <tt>page</tt>. That same div must also have a <tt>title</tt> attribute declaring the unique name for referring to that page.</p>
<p>There are also some CSS caveats. The containing element must be set to <tt>overflow: hidden;</tt>. Additionally, calculating heights on the pages can be difficult. The best way is to set a padding on the <tt>.page</tt> so margins don't leak outside it's box.</p>
<div class="highlight"><pre class="highlight plaintext"><code><head>
<style type="text/css">
#maincontent {
overflow: hidden; }
.page {
padding: 5px; }
</style>
<script src="jquery-1.3.2.js" type="text/javascript"></script>
<script src="jquery.history.js" type="text/javascript"></script>
<script src="jquery.page-slider.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
$('.page').pageSlider();
});
</script>
</head>
<body>
<div id="maincontent">
<div title="home" class="page">
Home page
</div>
<div title="page2" class="page">
Page number two
</div>
</div>
</body>
</code></pre></div>
<p>Now, whenever the "history" hash (the #page location in the URL) is changed, the javascript will slide to the requested piece. Normal links such as <a href="#page2"> can be used to trigger the effect. The back-button will also change the history and thus trigger the animation.</p>
<h2 id="configuration">Configuration</h2>
<p>The plugin needs to know the containing element to slide inside of.</p>
<ul><li><tt>containerSelector</tt> sets the text of the "on" state. Defaults to: <strong>#maincontent</strong></li></ul>
<div class="highlight"><pre class="highlight plaintext"><code>$('.page').pageSlider({
containerSelector: "#frame"
});
</code></pre></div>
<h2 id="events">Events</h2>
<p>The plugin calls a <tt>changingPage</tt> event whenever the animation begins. If you have dependent elements you want to update together with the slide, you can attach them to the event via the normal jQuery event model. This callback is used in the video above to update the sidebar navigation when the history changes.</p>
<div class="highlight"><pre class="highlight plaintext"><code>$(document).bind('changingPage', function(anchor_name) {
// Update some other dependent element based on anchor_name
});
</code></pre></div>
<h2 id="demo">Demo</h2>
<p><a href="/pageSlider/demo.html">See the demo here</a>.</p>
Speaking at RefreshPDX on Sass/2009/07/22/speaking-at-refreshpdx.html2009-07-22T00:00:00ZT00:00:00-08:002009-07-22T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>It's late notice, but I'll be speaking on Sass and Compass at <a href="http://refreshpdx.org/">Refresh Portland</a> on Thursday, July 23rd at <a href="http://maps.google.com/maps?f=q&hl=en&q=915+SW+Stark+St,+Portland,+Multnomah,+Oregon+97205,+United+States&sll=37.0625,-95.677068&sspn=49.176833,77.519531&ie=UTF8&cd=1&geocode=0,45.521796,-122.680205&ll=45.521804,-122.680206&spn=0.021408,0.037851&t=p&z=15&iwloc=addr">Jive Software</a>.</p>
<p>The presentation should be streamed (and then archived) on Ustream and I'll post the slides here on Friday.</p>
<p>It's late notice, but I'll be speaking on Sass and Compass at <a href="http://refreshpdx.org/">Refresh Portland</a> on Thursday, July 23rd at <a href="http://maps.google.com/maps?f=q&hl=en&q=915+SW+Stark+St,+Portland,+Multnomah,+Oregon+97205,+United+States&sll=37.0625,-95.677068&sspn=49.176833,77.519531&ie=UTF8&cd=1&geocode=0,45.521796,-122.680205&ll=45.521804,-122.680206&spn=0.021408,0.037851&t=p&z=15&iwloc=addr">Jive Software</a>.</p>
<p>The presentation should be streamed (and then archived) on Ustream and I'll post the slides here on Friday.</p>
Simplifying CSS with Sass Presentation/2009/07/22/simplifying-css-presentation.html2009-07-22T00:00:00ZT00:00:00-08:002009-07-22T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Here are my slides from tonight's Refresh PDX presentation on Sass and Compass.</p>
<p><a href="http://www.slideshare.net/tdreyno/simplifying-css-with-sass">Simplifying CSS With Sass</a></p>
<div class='flash'>
<object height='355' style='margin:0px' width='425'>
<param name='movie' value='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=simplifyingcsswithsass-090724010510-phpapp02&rel=0&stripped_title=simplifying-css-with-sass' />
<param name='allowFullScreen' value='true' />
<param name='allowScriptAccess' value='always' />
<embed allowfullscreen='true' allowscriptaccess='always' height='355' src='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=simplifyingcsswithsass-090724010510-phpapp02&rel=0&stripped_title=simplifying-css-with-sass' type='application/x-shockwave-flash' width='425'></embed>
</object>
</div>
<p>Here are my slides from tonight's Refresh PDX presentation on Sass and Compass.</p>
<p><a href="http://www.slideshare.net/tdreyno/simplifying-css-with-sass">Simplifying CSS With Sass</a></p>
<div class='flash'>
<object height='355' style='margin:0px' width='425'>
<param name='movie' value='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=simplifyingcsswithsass-090724010510-phpapp02&rel=0&stripped_title=simplifying-css-with-sass' />
<param name='allowFullScreen' value='true' />
<param name='allowScriptAccess' value='always' />
<embed allowfullscreen='true' allowscriptaccess='always' height='355' src='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=simplifyingcsswithsass-090724010510-phpapp02&rel=0&stripped_title=simplifying-css-with-sass' type='application/x-shockwave-flash' width='425'></embed>
</object>
</div>
Easy Google Maps with jQuery/2009/07/22/google-maps-with-jquery.html2009-07-22T00:00:00ZT00:00:00-08:002009-07-22T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>The other day I needed a simple way to include a Google Map, so I wrote this jQuery function.</p>
<div class="highlight"><pre class="highlight plaintext"><code>$.fn.googleMap = function(address, options) {
var defaults = {
lat: 44.081996,
long: -123.0286928,
zoom: 14,
mapTypeId: google.maps.MapTypeId...</code></pre></div><p>The other day I needed a simple way to include a Google Map, so I wrote this jQuery function.</p>
<div class="highlight"><pre class="highlight plaintext"><code>$.fn.googleMap = function(address, options) {
var defaults = {
lat: 44.081996,
long: -123.0286928,
zoom: 14,
mapTypeId: google.maps.MapTypeId.HYBRID
};
options = $.extend(defaults, options || {});
var center = new google.maps.LatLng(options.lat, options.long);
var map = new google.maps.Map(this.get(0), $.extend(options, { center: center }));
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ address: address }, function(results, status) {
if (status == google.maps.GeocoderStatus.OK && results.length) {
if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
position: results[0].geometry.location,
map: map
});
}
}
});
};
</code></pre></div>
<p>Basically, the lat & long are default coordinates, but you pass in an address which Google focuses the map on.</p>
<p>This requires the latest (v3) version of the Google Map API.</p>
<h2 id="usage">Usage</h2>
<div class="highlight"><pre class="highlight plaintext"><code><script src='http://maps.google.com/maps/api/js?sensor=false' type='text/javascript'>
</script>
<script type='text/javascript'>
$(document).ready(function() {
$('#map-container').googleMap("3333 RiverBend Drive, Springfield, OR");
});
</script>
</code></pre></div>Raphaël. The Return of Browser SVG/2009/07/13/return-of-svg.html2009-07-13T00:00:00ZT00:00:00-08:002009-07-13T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Maybe we've all been too hasty in declaring the <tt>canvas</tt> tag the new king of web interaction. I've just stumbled upon <a href="http://raphaeljs.com/">Raphaël</a>—a javascript library for interacting with SVG. The library is cross-browser thanks to VML on Internet Explorer. </p>
<p>I really like...</p><p>Maybe we've all been too hasty in declaring the <tt>canvas</tt> tag the new king of web interaction. I've just stumbled upon <a href="http://raphaeljs.com/">Raphaël</a>—a javascript library for interacting with SVG. The library is cross-browser thanks to VML on Internet Explorer. </p>
<p>I really like the idea of having real DOM nodes when manipulating things via javascript. The <tt>canvas</tt> tag always seemed a big too much like Flash for my liking. Here are a few of my favorite demos:</p>
<ul>
<li><a href="http://raphaeljs.com/australia.html">A vector map of Australia</a></li>
<li><a href="http://raphaeljs.com/github/impact.html">Github-style impact chart</a></li>
<li><a href="http://raphaeljs.com/analytics.html">Interactive analytics graph</a></li>
<li><a href="http://raphaeljs.com/ichart.html">Draggable graph</a></li>
</ul>
<p>Thanks to <a href="http://pixelmatrixdesign.com/">Josh Pyles</a> for pointing it out.</p>
iPhone-style Checkboxes for Prototype/2009/06/29/prototype-iphone-style-checkboxes.html2009-06-29T00:00:00ZT00:00:00-08:002009-06-29T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Big thanks to <a href="http://jqr.github.com/">Elijah Miller</a> for stepping up and finishing the work on the Prototype version of the iPhone-style checkboxes. Elijah now has write-access to the official repository at GitHub and will be maintaining it alongside my jQuery version.</p>
<h2 id="examples">Examples</h2><p>Big thanks to <a href="http://jqr.github.com/">Elijah Miller</a> for stepping up and finishing the work on the Prototype version of the iPhone-style checkboxes. Elijah now has write-access to the official repository at GitHub and will be maintaining it alongside my jQuery version.</p>
<h2 id="examples">Examples</h2>
<div class='table'>
<table>
<tr>
<td style='vertical-align: middle !important;'>
A checkbox defaulting to <strong>checked</strong>
</td>
<td>
<input checked='checked' class='normal' type='checkbox' />
</td>
</tr>
<tr>
<td style='vertical-align: middle !important;'>
A checkbox defaulting to <strong>unchecked</strong>
</td>
<td>
<input class='normal' type='checkbox' />
</td>
</tr>
</table>
</div>
<p><link charset='utf-8' href='/iphone-style-checkboxes/style.css' media='screen' rel='stylesheet' type='text/css' />
<script src='/iphone-style-checkboxes/prototype/prototype-1.6.0.3.js' type='text/javascript'></script>
<script src='/iphone-style-checkboxes/prototype/scriptaculous-effects-1.8.2.js' type='text/javascript'></script>
<script src='/iphone-style-checkboxes/prototype/iphone-style-checkboxes.js' type='text/javascript'></script>
<script type='text/javascript'>
new iPhoneStyle('#post input[type=checkbox].normal');
</script></p>
<h2 id="download-and-implement">Download and implement</h2>
<p>As with the jQuery version, <a href="http://github.com/tdreyno/iphone-style-checkboxes/zipball/master">download the package</a>, unzip it and place the javascript, images and stylesheet where you please. You'll need to update the stylesheet to point to the new location of your images if they have changed relative to the stylesheet.</p>
<p>Once the files are available to your site, activating the script is very easy:</p>
<div class="highlight"><pre class="highlight plaintext"><code><head>
<script src="prototype.js" type="text/javascript"></script>
<script src="scriptaculous.js" type="text/javascript"></script>
<script src="prototype/iphone-style-checkboxes.js" type="text/javascript"></script>
<link rel="stylesheet" href="path_to/style.css" type="text/css" media="screen" />
<script type="text/javascript">
document.observe("dom:loaded", function() {
new iPhoneStyle('input[type=checkbox]');
});
</script>
</head>
</code></pre></div>
<p>The initialization method takes a handful of options.</p>
<ul><li><tt>checkedLabel</tt> sets the text of the "on" state. Defaults to: <strong>ON</strong></li><li><tt>uncheckedLabel</tt> sets the text of the "off" state. Defaults to: <strong>OFF</strong></li></ul>
<p>For example:</p>
<div class="highlight"><pre class="highlight plaintext"><code>new iPhoneStyle('input[type=checkbox]', {
checkedLabel: 'YES',
uncheckedLabel: 'NO'
});
</code></pre></div>
<div class='table'>
<table>
<tr>
<td style='vertical-align: middle !important;'>
A checkbox defaulting to <strong>checked</strong>
</td>
<td>
<input checked='checked' class='yesno' type='checkbox' />
</td>
</tr>
<tr>
<td style='vertical-align: middle !important;'>
A checkbox defaulting to <strong>unchecked</strong>
</td>
<td>
<input class='yesno' type='checkbox' />
</td>
</tr>
</table>
</div>
<script type='text/javascript'>
new iPhoneStyle('#post input[type=checkbox].yesno', { checkedLabel: 'YES', uncheckedLabel: 'NO', background: '#F9F3E8' });
</script>
<h2 id="original-version-and-contributing">Original version and Contributing</h2>
<p>You can read about the original jQuery version <a href="/2009/06/16/iphone-style-checkboxes.html">here</a>.
Both versions are maintained using GitHub: <a href="http://github.com/tdreyno/iphone-style-checkboxes">http://github.com/tdreyno/iphone-style-checkboxes</a></p>
Introducing iPhone-style Checkboxes/2009/06/16/iphone-style-checkboxes.html2009-06-16T00:00:00ZT00:00:00-08:002009-06-16T00:00:00ZT00:00:00-08:00Thomas Reynolds<!doctype html>
<html>
<head>
<title>iOS Checkboxes « Thomas Reynolds</title>
<meta http-equiv="refresh" content="0;url=http://ios-checkboxes.awardwinningfjords.com/">
</head>
<body>
<p>You are being redirected to: <a href="http://ios-checkboxes.awardwinningfjords.com/">http://ios-checkboxes.awardwinningfjords.com/</a></p>
</body>
</html><!doctype html>
<html>
<head>
<title>iOS Checkboxes « Thomas Reynolds</title>
<meta http-equiv="refresh" content="0;url=http://ios-checkboxes.awardwinningfjords.com/">
</head>
<body>
<p>You are being redirected to: <a href="http://ios-checkboxes.awardwinningfjords.com/">http://ios-checkboxes.awardwinningfjords.com/</a></p>
</body>
</html>WWDC 2009 Predictions/2009/06/04/wwdc-2009-predictions.html2009-06-04T00:00:00ZT00:00:00-08:002009-06-04T00:00:00ZT00:00:00-08:00Thomas Reynolds<h2>iPhone</h2>
<ul>
<li>✓ New model</li>
<li>✓ Video support</li>
<li>✓ 32Gb</li>
<li>✓ Compass & turn-by-turn partnership</li>
<li>✓ Pre/Zune bashing</li>
<li>✓ iTunes WiFi Video Store</li>
</ul>
<h2>Snow Leopard</h2>
<ul>
<li>Secret sauce released: theme updates, ✓ Cocoa/64bit magic, ✓ Safari 4</li>
<li>✓ RC handed out to...</li>
</ul><h2>iPhone</h2>
<ul>
<li>✓ New model</li>
<li>✓ Video support</li>
<li>✓ 32Gb</li>
<li>✓ Compass & turn-by-turn partnership</li>
<li>✓ Pre/Zune bashing</li>
<li>✓ iTunes WiFi Video Store</li>
</ul>
<h2>Snow Leopard</h2>
<ul>
<li>Secret sauce released: theme updates, ✓ Cocoa/64bit magic, ✓ Safari 4</li>
<li>✓ RC handed out to developers</li>
<li>✓ Out in September</li>
<li>✓ Windows 7 bashing</li>
</ul>
<h2>MacBooks</h2>
<ul>
<li>✓ Unibody line updated</li>
<li>✓ MacBook Air revision</li>
<li>New Snow Leopard-only features: new gestures, video cards, etc</li>
</ul>
Simplify image paths with image_url()/2009/05/11/simplify-image-paths-with-image-url.html2009-05-11T00:00:00ZT00:00:00-08:002009-05-11T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Recently Compass introduced a Sass method called image_url() which allows you to refer to images by their file name only. When the Sass is compiled, the CSS url() method is populated with a path generated by Compass.</p>
<p>When you start a new project using...</p><p>Recently Compass introduced a Sass method called image_url() which allows you to refer to images by their file name only. When the Sass is compiled, the CSS url() method is populated with a path generated by Compass.</p>
<p>When you start a new project using the compass command-line tool, it will generate a config.rb file which contains options specific to your new project. There is a variable called http<em>images</em>path which is used by Compass to generate the correct image paths. I have the value setup for this site as such</p>
<div class="highlight"><pre class="highlight plaintext"><code>http_images_path = "/wp-content/themes/default/images/"
</code></pre></div>
<p>Now when I use the image_url() method for the header on this site:</p>
<div class="highlight"><pre class="highlight plaintext"><code>h1
background= image_url("title-embellishment.gif") "no-repeat" 17px 7px
</code></pre></div>
<p>It will generate this CSS:</p>
<div class="highlight"><pre class="highlight plaintext"><code>h1 {
background: url(/images/title-embellishment.gif) no-repeat 17px 7px; }
</code></pre></div>
<p>This makes it trivial to change image paths for the entire site with one line in config.rb. Never again worry about relative paths, ../../images/ and the like.</p>
Using Compass to implement the Blueprint grid-system & consistent vertical-rhythm/2009/05/07/blueprint-grids-vertical-rhythm.html2009-05-07T00:00:00ZT00:00:00-08:002009-05-07T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Using Sass & Compass I updated the css on this site to use Blueprint's 950px grid system and their typography for consistent vertical rhythm.
The full Sass is included below:</p>
<div class="highlight"><pre class="highlight plaintext"><code>@import base.sass
body
background: #F9F3E8
a
font-weight: bold
h1...</code></pre></div><p>Using Sass & Compass I updated the css on this site to use Blueprint's 950px grid system and their typography for consistent vertical rhythm.
The full Sass is included below:</p>
<div class="highlight"><pre class="highlight plaintext"><code>@import base.sass
body
background: #F9F3E8
a
font-weight: bold
h1, h2, h3
font-family= !header_font_family
font-weight: 200
a
text-decoration: none
color= !header_color
font-weight: 200
h1
margin-top: 0
background= image_url("title-embellishment.gif") "no-repeat" 17px 7px
h2
margin: 1.5em 0 0 0
hr
+colruler
color= !border_color
background= !border_color
#header
height: 108px
background: #6B4419
h2
height: 108px
+replace-text("header.gif")
+link-fills-element
p
display: none
#post
+container(790px)
padding-top= (!baseline * 2)
h1, h2, p, blockquote, ul, ol, pre
+prepend(2)
+append(2)
hr
margin-left: 80px
+span(16)
blockquote
color: #592E08
font-family= !quote_font_family
background= image_url("quote.gif") "no-repeat"
strong
color= !darker_font_color
pre
color= !darker_font_color
background= #F2EADD image_url("code.gif") "no-repeat"
overflow: visible
padding-top: 1.5em
padding-bottom: 1.5em
strong
font-weight: normal
color: #000
.blurb-set
+container(630px)
+prepend(2)
+append(2)
.post-blurb
+column(8)
width: 290px
padding= !baseline 20px !baseline 0
h3
margin-top: 0
.last
+last
padding-right: 0 !important
#comments
+container(790px)
padding-top: 1.5em
h2
color: #543616
border-bottom= 3px "solid" !border_color
+prepend(2)
margin= 0 0 (!baseline - 3px) 0
span
height= (!baseline * 2)
overflow: hidden
display: inline
font-weight: bold
font-family: 'Helvetica Neue', arial, sans-serif
color: #fff
padding: 0 10px
-webkit-border-radius: 0.5em
-moz-border-radius: 0.5em
background: #AF512C
ul
+no-bullets
margin: 0 0 3em 0
padding: 0
li
+prepend(2)
+append(2)
padding-top: 1.5em
padding-bottom: 1.5em
background= image_url("quote-odd.gif") "no-repeat" 0 -23px
cite
font-weight: bold
font-style: normal
color: #AF512C
&amp;.odd
background= #F2EADD image_url("quote-even.gif") "no-repeat" 0 -23px
&amp;.comment-author-admin
background= #8F704E image_url("quote-myself.gif") "no-repeat" 0 -23px
cite
color: #fff
p
color: #D2C6B8
#footer
text-align: left
.wrapper
+container(630px)
#copyright
background: #603D17
padding-top: 1.5em
padding-bottom: 1.5em
+clearfix
p
color: #B09E8B
margin: 0
a
color: #B09E8B
font-weight: normal
&amp;.left
+float-left
&amp;.right
+float-right
#reply
margin-top: 1.5em
background: #f2eadd
h2
color= !darker_font_color
margin-top: 0.75em
.text input,
.textarea textarea
outline: 0
border: 2px solid #D3CBBD
-webkit-border-radius: 0.5em
-moz-border-radius: 0.5em
background: #fff
font-size: 1em
font-family= !blueprint_font_family
&amp;.example
color: #999
.text
height= (!baseline * 2)
input
padding: 4px 6px
width: 305px
.textarea
height= (!baseline * 10)
textarea
padding: 6px 4px
width: 618px
height: 150px
.submit
height= (!baseline * 2)
</code></pre></div>NHaml idiosyncrasies/2009/04/30/nhaml-idiosyncrasies.html2009-04-30T00:00:00ZT00:00:00-08:002009-04-30T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><a href="http://code.google.com/p/nhaml/">NHaml</a> is an implementation of Haml for the .NET runtime. Specifically it runs inside .NET's new MVC architecture. This implementation is missing quite a few Haml niceties and the language has actually been altered in many places to be more C#-like...</p><p><a href="http://code.google.com/p/nhaml/">NHaml</a> is an implementation of Haml for the .NET runtime. Specifically it runs inside .NET's new MVC architecture. This implementation is missing quite a few Haml niceties and the language has actually been altered in many places to be more C#-like. Personally, I think this is a poor decision. Imagine if Javascript had different syntax depending on the browser it was running in? Well... I guess Microsoft has JScript and VBScript so maybe this is just how Windows programmers operate. But, I digress. Here are some gotchas should you contemplate using NHaml.</p>
<h2 id="instead-of-ruby-hashes-parameters-are-c-key-value-pairs">Instead of Ruby hashes, parameters are C# Key-Value pairs</h2>
<p>This means Ruby's symbols (prefixed with a colon) are now just plain keys. Similarly, the hashrocket (=>) becomes a normal equals sign</p>
<div class="highlight"><pre class="highlight plaintext"><code>Before: %link{ :type => "text/css", :rel => "stylesheet", :src => "style.css" }
After: %link{ type="text/css", rel="stylesheet", src="style.css" }
</code></pre></div>
<p><strong>[Edit: As of NHaml 2.0 beta 2, the syntax for attributes has changed and now appears exactly like normal HTML attributes (no commas are used). The above code would now be written is as follows:]</strong></p>
<div class="highlight"><pre class="highlight plaintext"><code>%link{ type="text/css" rel="stylesheet" src="style.css" }
</code></pre></div>
<h2 id="single-quotes-are-not-allowed">Single-quotes are not allowed</h2>
<p>C# apparently uses single-quotes to denote a character, not a string.</p>
<div class="highlight"><pre class="highlight plaintext"><code>Before: %input{ :type => 'text' }
After: %input{ type="text" }
</code></pre></div>
<h2 id="lines-cannot-be-started-with-an-ampersand-character">Lines cannot be started with an ampersand (&) character</h2>
<p>NHaml has a special meaning for lines like this. Apparently it is for automatically escaping the contents of that line. You will need to escape the ampersand:</p>
<div class="highlight"><pre class="highlight plaintext"><code>Before: &ldquo;Hi&rdquo;
After: \&ldquo;Hi&rdquo;
</code></pre></div>
<h2 id="nhaml-hates-white-space-only-lines">NHaml HATES white-space-only lines</h2>
<p>Basically, if you're using empty lines to space out your code, NHaml requires that they contain as much indentation as the section they are supposed to be a part of or else they will clear out your nesting.</p>
<p>Given the following Haml</p>
<div class="highlight"><pre class="highlight plaintext"><code>%ul
%li
Text
%li
Text2
</code></pre></div>
<p>NHaml will render this as:</p>
<div class="highlight"><pre class="highlight plaintext"><code><ul>
<li>
Text
</li>
</ul>
<li>
Text2
</li>
</code></pre></div>
<p>So remember to remove white-space-only lines until this issue is resolved.</p>
<h2 id="conclusion">Conclusion</h2>
<p>All in all, I'm still really happy to be able to use Haml in the .NET environment. It took me 5 hours yesterday to build a relatively complicated 20-page site in Haml. Today it took me 8 hours to get it working in NHaml, but this is a one-time penalty. Next time I can write my Haml with NHaml in mind.</p>
<p>I want to say thanks to the NHaml team. I hope the project is a success because it still needs some love and I would really like Sass support. I kind of feel sorry for C# programmers. The culture doesn't flock to open source like it does in the open source languages (Python, Ruby, etc). There seem to be fewer C# developers who live in HTML and are interested improving the front-end side of the .NET stack. However, it looks like things are improving.</p>
A Compass & Sass Screencast via Chris Eppstein/2009/04/26/a-compass-sass-screencast-via-chris-eppstein.html2009-04-26T00:00:00ZT00:00:00-08:002009-04-26T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Compass author—and Sass contributor—Chris Eppstein has put a screencast together showing how to use Compass. Enjoy.</p>
<div class='flash'>
<object data='http://vimeo.com/moogaloop.swf?clip_id=4335944&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1' height='225' type='application/x-shockwave-flash' width='400'>
<param name='allowfullscreen' value='true' />
<param name='allowscriptaccess' value='always' />
<param name='src' value='http://vimeo.com/moogaloop.swf?clip_id=4335944&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1' />
</object>
</div>
<p><a href="http://vimeo.com/4335944">Compass: A Real Stylesheet Framework</a> from Chris Eppstein.</p>
<p>Compass author—and Sass contributor—Chris Eppstein has put a screencast together showing how to use Compass. Enjoy.</p>
<div class='flash'>
<object data='http://vimeo.com/moogaloop.swf?clip_id=4335944&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1' height='225' type='application/x-shockwave-flash' width='400'>
<param name='allowfullscreen' value='true' />
<param name='allowscriptaccess' value='always' />
<param name='src' value='http://vimeo.com/moogaloop.swf?clip_id=4335944&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1' />
</object>
</div>
<p><a href="http://vimeo.com/4335944">Compass: A Real Stylesheet Framework</a> from Chris Eppstein.</p>
Creating bullet-proof HTML emails/2009/04/06/creating-bullet-proof-html-emails.html2009-04-06T00:00:00ZT00:00:00-08:002009-04-06T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>This screencast will demonstrate how a bullet-proof, table-based email can be sliced and coded using ImageReady CS2. Other versions of Photoshop will work similarly, but I prefer CS2.</p>
<p>The resulting HTML email will display perfectly in the majority...</p><p>This screencast will demonstrate how a bullet-proof, table-based email can be sliced and coded using ImageReady CS2. Other versions of Photoshop will work similarly, but I prefer CS2.</p>
<p>The resulting HTML email will display perfectly in the majority of modern email clients such as gmail, Apple Mail and Outlook.</p>
<p>This table-based approach is required thanks to the changes made in the Outlook 2007 rendering engine. Please read Campaign Monitor's article, <a href="http://www.campaignmonitor.com/blog/post/2393/microsoft-takes-email-design-b/">Microsoft takes email design back 5 years</a>, for an overview of the situation.</p>
<div class='flash'>
<object height='250' width='400'>
<param name='allowfullscreen' value='true' />
<param name='allowscriptaccess' value='always' />
<param name='movie' value='http://vimeo.com/moogaloop.swf?clip_id=4018544&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1' />
<embed allowfullscreen='true' allowscriptaccess='always' height='250' src='http://vimeo.com/moogaloop.swf?clip_id=4018544&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1' type='application/x-shockwave-flash' width='400'></embed>
</object>
</div>
Sass Introduction slides/2009/04/02/sass-introduction-slides.html2009-04-02T00:00:00ZT00:00:00-08:002009-04-02T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>Here's the slides I will be presenting at Jive Software:</p>
<div class='flash'>
<object data='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=sass-090402192738-phpapp01&rel=0&stripped_title=sass-introduction' height='355' type='application/x-shockwave-flash' width='425'>
<param name='allowFullScreen' value='true' />
<param name='allowScriptAccess' value='always' />
<param name='src' value='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=sass-090402192738-phpapp01&rel=0&stripped_title=sass-introduction' />
<param name='allowfullscreen' value='true' />
</object>
</div>
<p>Here's the slides I will be presenting at Jive Software:</p>
<div class='flash'>
<object data='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=sass-090402192738-phpapp01&rel=0&stripped_title=sass-introduction' height='355' type='application/x-shockwave-flash' width='425'>
<param name='allowFullScreen' value='true' />
<param name='allowScriptAccess' value='always' />
<param name='src' value='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=sass-090402192738-phpapp01&rel=0&stripped_title=sass-introduction' />
<param name='allowfullscreen' value='true' />
</object>
</div>
Don't repeat yourself, use Sass mixins/2009/04/02/dont-repeat-yourself-use-sass-modules.html2009-04-02T00:00:00ZT00:00:00-08:002009-04-02T00:00:00ZT00:00:00-08:00Thomas Reynolds<p><strong>Update (2011-08-23): Use to Sass 3 syntax</strong></p>
<p>There are quite a few situations in CSS where you are simply copy & pasting the same set of styles in multiple places. If at some point, you want to tweak these styles, you'll need to track down and update...</p><p><strong>Update (2011-08-23): Use to Sass 3 syntax</strong></p>
<p>There are quite a few situations in CSS where you are simply copy & pasting the same set of styles in multiple places. If at some point, you want to tweak these styles, you'll need to track down and update each set of styles. Sass introduces the concept of mixins which are blocks of nested Sass code which can be applied to any selector in your Sass document. Think of them as variables which can hold multiple levels of information. The syntax for defining a module is simple:</p>
<div class="highlight"><pre class="highlight plaintext"><code>=module-name
style1: value1
style2: value2
.wrapper
style3: value3
</code></pre></div>
<p>Then you can inject this module into a selector:</p>
<div class="highlight"><pre class="highlight plaintext"><code>#frame #left
+module-name
</code></pre></div>
<p>Which will generate CSS that looks like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>#frame #left {
style1: value1;
style2: value2; }
#frame #left .wrapper {
style3: value3; }
</code></pre></div>
<p>In my opinion, this is Sass' killer feature. The repetition so common in large CSS files can be extracted into reusable functions. To illustrate this point, I'm going to take two of the most-frequently repeated blocks of CSS: the clearfix and the replacement of text with an image.</p>
<h2 id="clearfix">Clearfix</h2>
<p>The Sass definition for clearfix—pulled from the Compass project—is declared as such:</p>
<div class="highlight"><pre class="highlight plaintext"><code>=clearfix
overflow: auto
overflow: -moz-scrollbars-none
// This makes ie6 get layout
display: inline-block
// and this puts it back to block
&amp;
display: block
</code></pre></div>
<p>Many developers create a .clearfix class and apply it on the HTML-side to blocks which need the hack. I've never been a huge fan of this as you are making presentational changes to the content-side of the equation. The old-school .clearfix class can be accomplished pretty simply though, so it is worth showing:</p>
<div class="highlight"><pre class="highlight plaintext"><code>.clearfix
+clearfix
</code></pre></div>
<p>On the other hand, I prefer to include the clearfix directly on the selectors that need it:</p>
<div class="highlight"><pre class="highlight plaintext"><code>#left
+clearfix
div
float: left
</code></pre></div>
<p>And since this is a new concept, here is the CSS which will be generated:</p>
<div class="highlight"><pre class="highlight plaintext"><code>#left {
overflow: auto;
overflow: -moz-scrollbars-none;
display: inline-block; }
#left {
display: block; }
#left div {
float: left; }
</code></pre></div>
<p>This actually results in a lot of duplication in the <em>rendered</em> CSS over the .clearfix method. I guess it depends what you want to optimize your development for. If you develop entirely in Sass, then it is a non-issue. However, if you generate CSS and hand it over to a client or another developer, they may not like this kind of repetition.</p>
<h2 id="module-parameters">Module parameters</h2>
<p>Sass mixins can also take parameters that are used when generating the CSS. Here is the Sass definition for the often-used trick of displaying an image behind text (usually a H1-H6 tag) and shifting the text out of view.</p>
<div class="highlight"><pre class="highlight plaintext"><code>=replace-text( $img, $x: 50%, $y: 50% )
text-indent: -9999em
overflow: hidden
background:
image: url($img)
repeat: no-repeat
position: $x $y
</code></pre></div>
<p>As you can see, we must pass in the location of the replacement image and optionally the background position. The simplest usage of this module looks something like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>#header h1
+replace-text("/images/welcome.jpg")
</code></pre></div>
<p>And for completeness, here is the generated CSS:</p>
<div class="highlight"><pre class="highlight plaintext"><code>#header h1 {
text-indent: -9999em;
overflow: hidden;
background-image: url("/images/welcome.jpg");
background-repeat: no-repeat;
background-position: 50% 50%; }
</code></pre></div>
<h2 id="mixin-libraries">Mixin libraries</h2>
<p>In the next article, I'll go through a number of Sass mixins which are distributed with the Compass project.</p>
Refactoring with Sass/2009/03/14/refactoring-with-sass.html2009-03-14T00:00:00ZT00:00:00-08:002009-03-14T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I had intended to jump right into Compass modules and user-defined "functions," but that's a rather high-level concept and requires a relatively strong understanding of Sass which I shouldn't assume readers have because Sass isn't really that popular...</p><p>I had intended to jump right into Compass modules and user-defined "functions," but that's a rather high-level concept and requires a relatively strong understanding of Sass which I shouldn't assume readers have because Sass isn't really that popular. I'll save the complicated stuff for the next article. Instead, I'll look at how you can take an existing CSS document and convert to Sass in preparation for the article on more-complicated techniques.</p>
<h2 id="converting-css-to-sass">Converting CSS to Sass</h2>
<p>There are two ways to convert an existing CSS file to Sass. The Haml gem comes with a command called css2sass which parses your CSS document, converts it to Sass-styled code and nests the selectors hierarchically to reduce repetition. You can run the conversion and save the output to a new file by running:</p>
<div class="highlight"><pre class="highlight plaintext"><code>css2sass OLDFILE.css > NEWFILE.sass
</code></pre></div>
<p>However, there is one large caveat. Because css2sass rearranges your selectors, you can run into problems with specificity and order. If you have been working quickly and not refactoring as you were developing (aka doing real work), then you may have begun littering your CSS with more and more one-off commands that altered css defined earlier in the document. They "worked" because css overrides styles as it reads through the document. The sass produced by css2sass may have a different order and can cause your little tweaks to be ignored.</p>
<p>The safer alternative is to convert from CSS to Sass by hand. Simply remove all curly braces and semicolons and you should have a valid—if not optimized—Sass document. If you've been inconsistent with using either tabs or spaces, Sass will warn you. You'll need to standardize on one or the other before moving forward. If you start out with some CSS like this:</p>
<div class="highlight"><pre class="highlight plaintext"><code>#left {
float: left;
display: inline;
width: 242px;
}
#left ul {
list-style-type: none;
margin: 0 8px 0 0;
}
#left ul li {
font-size: 13px;
}
</code></pre></div>
<p>The first-pass of conversion to Sass will now look like:</p>
<div class="highlight"><pre class="highlight plaintext"><code>#left
float: left
display: inline
width: 242px
#left ul
list-style-type: none
margin: 0 8px 0 0
#left ul li
font-size: 13px
</code></pre></div>
<p>The next step is to start at the top (#left) and try to modify the nesting so that it only appears once in the Sass file. Simply indent anything starting with #left and remove the id selector. We will also do the same with the "ul li" selector. Exchange the explicit selector for hierarchical indentation.</p>
<div class="highlight"><pre class="highlight plaintext"><code>#left
float: left
display: inline
width: 242px
ul
list-style-type: none
margin: 0 8px 0 0
li
font-size: 13px
</code></pre></div>
<p>So far, all we've done is removed some punctuation and a little duplication. If we ever need to change the id selector, we can do it in one place and all the nested styles beneath it will automatically be updated thanks to Sass. Personally, this simple improvement was enough to get me to convert to Sass full-time.</p>
<p>In the next article, I'll look at the included modules in Compass that we can use to reduce code duplication and save time. Once we see why such modules are useful, we'll take a look at how to define our own.</p>
Compass, the future of Sass development/2009/03/11/compass-the-future-of-sass-development.html2009-03-11T00:00:00ZT00:00:00-08:002009-03-11T00:00:00ZT00:00:00-08:00Thomas Reynolds<p>I've been a fan of Haml and Sass for a long time. Ever since I ran my mouth in #merb and Hampton Caitlin rightfully put me in my place. If you have no clue what Haml & Sass are—or if you've heard the buzz, but never actually checked them out—you can...</p><p>I've been a fan of Haml and Sass for a long time. Ever since I ran my mouth in #merb and Hampton Caitlin rightfully put me in my place. If you have no clue what Haml & Sass are—or if you've heard the buzz, but never actually checked them out—you can view <a href="http://peepcode.com/products/haml-and-sass">this excellent PeepCode screencast on the subject</a>. I currently use both for the initial coding of all the sites I develop. However, I am not lucky enough to work with a Haml-enabled framework on the backend like Rails or Merb so I have to compile to HTML and CSS when I begin integrating the front-end with the back-end¹.</p>
<p>This situation sucks. Sass makes me a faster in my initial development, but it also speeds up tweaking small site-wide issues and overall maintenance. I develop my Sass modularly and try to use variables for site-wide colors, border and fonts. Wouldn't it be great if I could use Sass throughout the entire development cycle?</p>
<h2 id="enter-compass">Enter Compass</h2>
<p>Compass is a new Sass-centric library from <a href="http://github.com/chriseppstein">Chris Eppstein</a>.
There are two components of Compass. The first is a handful of libraries and code snippets implemented in Sass so you can easily apply the rules of <a href="http://www.blueprintcss.org/">Blueprint</a>, <a href="http://960.gs/">960.gs</a> or <a href="http://developer.yahoo.com/yui/grids/">YUI grids</a> to you website entirely in Sass without dirtying up your HTML with presentational classes. The second component is the compass command-line tool which continuously watches you Sass files and compiles them to CSS on-the-fly. While I do am a huge fan of grid-based design and I do appreciate the implemented CSS grid systems, I usually code each site from scratch rather than rely on someone else's large CSS library. Therefore this article will focus on getting Compass installed and using it to generate CSS on-the-fly.</p>
<h2 id="getting-started">Getting Started</h2>
<p>This will download, compile and install the Haml gem. The next step is making sure RubyGems is new enough to play nicely with GitHub-hosted gems. Then we'll be able to install compass from GitHub. From the terminal run:</p>
<div class="highlight"><pre class="highlight plaintext"><code>sudo gem update --system
sudo gem install compass
</code></pre></div>
<h2 id="continuous-compilation">Continuous Compilation</h2>
<p>Alright, let's move to our web directory—wherever that may be. I like to keep all my CSS and Sass together so I have a base css/ directory and css/sass/ directory under that. Given that structure, I can have compass watch my Sass like so:</p>
<div class="highlight"><pre class="highlight plaintext"><code>cd PROJECT_DIR
compass --watch --css-dir css --sass-dir css/sass
</code></pre></div>
<p>Compass will sit patiently in the terminal, monitoring the folder I specified and compiling the Sass files to CSS whenever I save an existing file or add a new one. In my next article, I will discuss converting existing CSS files to Sass, the refactoring process and the usage of compass' included Sass modules for common CSS such as the <a href="http://www.positioniseverything.net/easyclearing.html">clearfix hack</a> and <a href="http://phark.typepad.com/phark/2003/08/accessible_imag.html">Mike Rundle's image replacement</a>.</p>
<hr>
<p>¹ Luckily for me, Microsoft's <a href="http://andrewpeters.net/2007/12/19/introducing-nhaml-an-aspnet-mvc-view-engine/">ASP.NET will soon have access to HAML</a> via the MVC Contribs project. Alas, no native Sass support is on the horizon.</p>