<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Warpspire &#187; Tips &amp; Resources</title>
	<atom:link href="http://www.warpspire.com/category/tipsresources/feed" rel="self" type="application/rss+xml" />
	<link>http://warpspire.com</link>
	<description>my god, it's full of stars</description>
	<pubDate>Mon, 09 Jun 2008 23:49:19 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>Quick &#038; Dirty: Add changesets since last deploy for your Rails apps with Lighthouse</title>
		<link>http://warpspire.com/tipsresources/programming/quick-dirty-add-changesets-since-last-deploy-for-your-rails-apps-with-lighthouse/</link>
		<comments>http://warpspire.com/tipsresources/programming/quick-dirty-add-changesets-since-last-deploy-for-your-rails-apps-with-lighthouse/#comments</comments>
		<pubDate>Mon, 09 Jun 2008 23:49:19 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
		
		<category><![CDATA[Application Development]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://warpspire.com/?p=272</guid>
		<description><![CDATA[One of the most common problems for me is knowing when I last deployed my apps, and what I&#8217;ve done since then.  I often will leave an app on the side for a month or two at a time, and there&#8217;s a good chance I implemented some new fix, waited until a low-traffic time [...]]]></description>
			<content:encoded><![CDATA[<p>One of the most common problems for me is knowing when I last deployed my apps, and what I&#8217;ve done since then.  I often will leave an app on the side for a month or two at a time, and there&#8217;s a good chance I implemented some new fix, waited until a low-traffic time to deploy and subsequently forgot.  I end up in a state of not really knowing what&#8217;s up with the deploy.</p>

<p>So I finally sat down and hacked together a quick &#8216;System&#8217; screen in my apps.  Here&#8217;s an example:</p>

<div class="figure">
<img src="/images/posts/clipgarden_system.gif" alt="Example from Clipgarden's Admin" />
<small>System screen for Clipgarden (rendered in Fluid.app)</small>
</div>

<p>It tells me:</p>

<ul>
<li>How long it&#8217;s been since the last deploy</li>
<li>The currently deployed revision</li>
<li>Changes committed to the repository that are not yet deployed</li>
</ul>

<p>This has been pretty awesome for me so far as it&#8217;s a really easy way to figure out if a certain fix or feature has been deployed yet (ever given the answer &#8220;well it&#8217;s committed, but not deployed&#8221;?). </p>

<h2>Setup</h2>

<p>In order for this code to work, you&#8217;ll need a <a href="http://lighthouseapp.com">Lighthouse</a> account, and set it up to pull in changesets from your repository.  I personally do this through <a href="http://github.com">Github</a> since it&#8217;s just so damn easy.  I won&#8217;t go into how to do this since there&#8217;s plenty of tutorials out there.</p>

<h2>The Code</h2>

<p>You&#8217;ll need to add the <a href="http://github.com/Caged/lighthouse-api/tree/master">lighthouse api</a> to your <code>lib/</code> folder and then the following code should get you going.  This code also assumes you&#8217;re using Capistrano or Vlad for your deployment so that a <code>REVISION</code> file is created in your root folder.  If it doesn&#8217;t exist, there&#8217;s no harm done &#8212; but you won&#8217;t be getting any results.  </p>

<p>Note that this also makes this fix a little hard to test in development since the whole idea is that it&#8217;s deploy-centric.  I&#8217;d recommend copying down an old REVISION and throwing it in your rails root (but don&#8217;t commit!) for testing.</p>

<h3>New model: system.rb</h3>

<pre><code class="ruby">class System

  @@lighthouse_account = "ACCOUNT_NAME[CHANGE]&#8221;
  @@lighthouse_token = &#8220;BEACON_TOKEN[CHANGE]&#8221;
  @@lighthouse_project_id = PROJECT_ID[CHANGE]

  @@revision = nil
  def self.revision
    return @@revision unless @@revision.nil?
    if File.exists?(RAILS_ROOT + &#8220;/REVISION&#8221;)
      @@revision = IO.read(RAILS_ROOT + &#8220;/REVISION&#8221;).to_s.strip
    else
      @@revision = &#8220;unknown (in development mode)&#8221;
    end
    @@revision
  end

  @@deployed_at = nil
  def self.deployed_at
    return @@deployed_at unless @@deployed_at.nil?
    if File.exists?(RAILS_ROOT + &#8220;/REVISION&#8221;)
      @@deployed_at = File.mtime(RAILS_ROOT + &#8220;/REVISION&#8221;)
    else
      @@deployed_at = Time.now
    end
    @@deployed_at
  end

  @@lighthouse_project = nil
  def self.lighthouse_project
    return @@lighthouse_project unless @@lighthouse_project.nil?
    Lighthouse.account = @@lighthouse_account
    Lighthouse.token = @@lighthouse_token
    @@lighthouse_project = Lighthouse::Project.find(@@lighthouse_project_id)
    @@lighthouse_project
  end

  def self.changesets_since_deploy
    return [] if self.revision == &#8220;unknown (in development mode)&#8221;
    all_changesets = lighthouse_project.changesets
    changesets_since = []
    all_changesets.each do |changeset|
      break if changeset.revision == self.revision
      changesets_since &lt;&lt; changeset
    end
    changesets_since
  end

end
</code></pre>

<h3>Get the changesets in your controller</h3>

<pre><code class="ruby">def index
  @changesets = System.changesets_since_deploy
end
</code></pre>

<h3>Build a simple view</h3>

<pre><code class="html">&lt;h1&gt;System Status&lt;/h1&gt;
&lt;p&gt;The system was last updated &lt;%= distance_of_time_in_words(System.deployed_at, Time.now) %&gt; ago with revision &lt;%= System.revision %&gt;&lt;/p&gt;

&lt;% unless @changesets.empty? %&gt;
&lt;h2&gt;Changes made but not deployed&lt;/h2&gt;

&lt;div class="metabar"&gt;
  &lt;p class="secondary"&gt;&lt;%= @changesets.size %&gt; changeset&lt;%='s' unless @changesets.size == 1%&gt;&lt;/p&gt;
&lt;/div&gt;&lt;!-- /.metabar --&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Change&lt;/th&gt;
    &lt;th&gt;Commited At&lt;/th&gt;
  &lt;/tr&gt;
  &lt;% for changeset in @changesets %&gt;
    &lt;tr&gt;
      &lt;td class="small"&gt;
        &lt;%= changeset.body_html %&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;%= changeset.changed_at.to_formatted_s(:admin) %&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;% end %&gt;
&lt;/table&gt;
&lt;div class="metabar"&gt;
  &lt;p class="secondary"&gt;&lt;%= @changesets.size %&gt; changeset&lt;%='s' unless @changesets.size == 1%&gt;&lt;/p&gt;
&lt;/div&gt;&lt;!-- /.metabar --&gt;

&lt;% else %&gt;
&lt;p&gt;No changes!&lt;/p&gt;
&lt;% end %&gt;
</code></pre>

<h2>Downfalls</h2>

<p>There are a few downfalls to this quick &amp; dirty approach.  The most noticeable is that each and every one of your requests to this system page make an API call to Lighthouse.  However, so long as you put this page in the admin section of your site, you should be fine.  In a perfect world, we&#8217;d cache the results locally.</p>

<p>Have fun and let me know if you have any improvements, or any way to add this into some kind of useful distributed form (plugin?).</p>
]]></content:encoded>
			<wfw:commentRss>http://warpspire.com/tipsresources/programming/quick-dirty-add-changesets-since-last-deploy-for-your-rails-apps-with-lighthouse/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Top reasons your CSS columns are messed up</title>
		<link>http://warpspire.com/tipsresources/web-production/css-column-tricks/</link>
		<comments>http://warpspire.com/tipsresources/web-production/css-column-tricks/#comments</comments>
		<pubDate>Mon, 12 May 2008 17:51:04 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
		
		<category><![CDATA[Web Production]]></category>

		<guid isPermaLink="false">http://warpspire.com/tipsresources/web-production/css-column-tricks/</guid>
		<description><![CDATA[I believe the recent surge in popularity of CSS frameworks comes from a lack of basic understanding of the CSS box model and how it's implemented across browsers.  I wanted to share with you some quick tips on how to avoid easy pitfalls so you can create your own CSS framework in no time flat, without all the cruft of having ten thousand column combinations available.  Keeping these quick tips in mind at all times will allow you to do something I like to call <em>defensive coding</em> -- and really that's all CSS frameworks are: defensively coded snippets of CSS.]]></description>
			<content:encoded><![CDATA[<p>I believe the recent surge in popularity of CSS frameworks comes from a lack of basic understanding of the CSS box model and how it&#8217;s implemented across browsers.  I wanted to share with you some quick tips on how to avoid easy pitfalls so you can create your own CSS framework in no time flat, without all the cruft of having ten thousand column combinations available.  Keeping these quick tips in mind at all times will allow you to do something I like to call <em>defensive coding</em> &#8212; and really that&#8217;s all CSS frameworks are: defensively coded snippets of CSS.</p>

<h2>Your margins are doubled in IE6</h2>

<div class="figure">
<img src="/images/posts/css-column-tricks/ie6doublefloat.gif" />
</div>

<p>Here&#8217;s a super common pitfall: IE6 will double margins facing the direction of the float.  Example problematic code:</p>

<pre><code class="css">.sidebar{
  float:left;
  margin-left:20px;
}
</code></pre>

<p>This sidebar will have a 40px left margin in IE6 &#8212; almost certainly throwing the sidebar down below the content, and not next to the content as it should be.  Easy fix: add <code>display:inline;</code>  No side effects in any browser, and IE6 obeys margins perfectly.</p>

<pre><code class="css">.sidebar{
  float:left;
  margin-left:20px;
  display:inline
}
</code></pre>

<p><strong>Why it works:</strong> By declaring <code>float</code> on an element, you implicitly demand that it must be rendered as a block element &#8212; thus rendering the <code>display:inline</code> inert.  However, due to IE6&#8217;s awesome CSS engine, it fixes a bizarre bug that is the #2 reason I see CSS columns fail in IE6.</p>

<h2>Your content is wider than your column</h2>

<div class="figure">
<img src="/images/posts/css-column-tricks/extendingcolumns.gif" />
</div>

<p>Let&#8217;s pretend you&#8217;ve got this simplistic setup of code:</p>

<pre><code class="css">.columns{
  width:500px;
}
.columns .main{
  float:left;
  width:400px;
}
.columns .sidebar{
  float:right;
  width:100px;
}
</code></pre>

<p>HTML:</p>

<pre><code class="html">&lt;html&gt;
...
&lt;div class="columns"&gt;
  &lt;div class="main"&gt;
    &lt;img src="/images/awesome.gif" /&gt;
  &lt;/div&gt;&lt;!-- /.main --&gt;
  &lt;div class="sidebar"&gt;
    &lt;p&gt;Sidebar rules!&lt;/p&gt;
  &lt;/div&gt;&lt;!-- /.sidbear --&gt;
&lt;/div&gt;&lt;!-- /.columns --&gt;
...
&lt;/html&gt;
</code></pre>

<p>Harmless right? You might view this in Firefox and everything will be fine. But then you look at it in IE6 and your sidebar has mysteriously dissapeared below <code>.main</code>.  WTF? You look at the HTML, the CSS, and everything&#8217;s fine.  <strong>What could possibly be wrong?</strong>  A common problem here is if <code>awesome.gif</code> is 510px wide.  What this does is push out <code>.main</code> to 510px, and suddenly there&#8217;s not enough room for <code>.sidebar</code> inside <code>.columns</code> any longer.  Ack! </p>

<p>Easy fix: add <code>overflow:hidden</code> to your columns.  This forces the width restriction to crop any extruding content.  New magical CSS:</p>

<pre><code class="css">.columns{
  width:500px;
}
.columns .main{
  float:left;
  width:400px;
  overflow:hidden;
}
.columns .sidebar{
  float:right
  width:100px;
  overflow:hidden;
}
</code></pre>

<h2>Your margins extend past your container</h2>

<div class="figure">
<img src="/images/posts/css-column-tricks/negativemargin.gif" />
</div>

<p>So you&#8217;re building out a simple product listing template out, and you throw it in an unordered list:</p>

<pre><code class="css">ul.listing{
  margin:0;
  width:400px;
}
ul.listing li{
  list-style-type:none;
  float:left;
  margin:0 20px 0 0;
  width:85px;
}
</code></pre>

<p>HTML:</p>

<pre><code class="html">&lt;html&gt;
...
&lt;ul class="listing"&gt;
  &lt;li&gt;Product #1&lt;/li&gt;
  &lt;li&gt;Product #2&lt;/li&gt;
  &lt;li&gt;Product #3&lt;/li&gt;
  &lt;li&gt;Product #4&lt;/li&gt;
&lt;/ul&gt;
...
&lt;/html&gt;
</code></pre>

<p>This CSS will work just fine in something like Firefox, but for mysterious reasons you&#8217;ll see that Product #4 appears on it&#8217;s own line in IE6.  What&#8217;s happening here? I mean 4 columns x 85px + 3 gaps x 20px = 400px, right? Except that your 4th gap is hanging over the right edge &#8212; pushing the true width of the blocks to 420px.  Firefox is smart and lets that margin just hang out there &#8212; but IE6 will apply that margin within the parent wrapper &#8212; throwing the 4th item down since it takes up 20px more than it should have.</p>

<p>The fix? Apply a left margin to each item, with a negative margin to the wrapper.  This means that every item has a visible margin, but the whole block of elements are yanked back by the negative margin:</p>

<pre><code class="css">ul.listing{
  margin:0 0 0 -20px;
  width:420px;
}
ul.listing li{
  list-style-type:none;
  float:left;
  margin:0 0 0 20px;
  width:85px;
}
</code></pre>

<p>This gets around the nasty solution of adding a class to the first or last item in every row &#8212; something I&#8217;ve seen with abundance around the web.</p>

<h2>Building a CSS framework in no time</h2>

<p>Wev&#8217;e got to start out with some basic HTML.  Here&#8217;s what I&#8217;ve been using lately:</p>

<pre><code class="html">&lt;html&gt;
...
&lt;div class="columns col2"&gt;
  &lt;div class="column first"&gt;
    ...
  &lt;/div&gt;&lt;!-- /.first --&gt;
  &lt;div class="column last"&gt;
    ...
  &lt;/div&gt;&lt;!-- /.last --&gt;
&lt;/div&gt;&lt;!-- /.columns --&gt;
...
&lt;/html&gt;
</code></pre>

<p>For different column widths, I&#8217;ve been changing out the <code>col2</code> declaration to things like <code>col2A, col2B, col2C</code> and so on. You could easily give them more semantic names like <code>products-columns</code> too.</p>

<h3>Self clearing is the future</h3>

<p>The first step for any column framework is self-clearing. It&#8217;s easy, practical, and reduces all those damn clearing divs.</p>

<pre><code class="css">.columns:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
}
* html .columns {height: 1%;}
.columns{ display:inline-block; }
.columns{ display:block; }
</code></pre>

<h3>Float those columns</h3>

<p>Next step is to actually float those columns. So let&#8217;s add a couple more declarations:</p>

<pre><code class="css">.columns .column{
  float:left;
  overflow:hidden;
  display:inline;
}
.columns .last{ float:right; }

.col2 .first{ width:500px; }
.col2 .last{ width:100px; }

.col2A .first{ width:400px; }
.col2B .last{ width:200px; }

.col3 .first{ width:100px; }
.col3 .second{ width:280px; margin-left:20px; }
.col3 .last{ width:200px; }
</code></pre>

<h3>Done&#8230; uh, what?</h3>

<p>Oh, yeah. That&#8217;s it. That&#8217;s all it takes to create reliable columns in CSS. Really.</p>

<p>Here&#8217;s an <a href="/images/posts/css-column-tricks/example.html">example page</a> to prove it!</p>
]]></content:encoded>
			<wfw:commentRss>http://warpspire.com/tipsresources/web-production/css-column-tricks/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Deploying Merb with Git, Vlad the Deployer, and Ubuntu (Fiesty Fawn)</title>
		<link>http://warpspire.com/tipsresources/application-development/deploying-merb-with-git-vlad-the-deployer-and-ubuntu-fiesty-fawn/</link>
		<comments>http://warpspire.com/tipsresources/application-development/deploying-merb-with-git-vlad-the-deployer-and-ubuntu-fiesty-fawn/#comments</comments>
		<pubDate>Fri, 02 May 2008 21:22:28 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
		
		<category><![CDATA[Application Development]]></category>

		<guid isPermaLink="false">http://warpspire.com/tipsresources/application-development/deploying-merb-with-git-vlad-the-deployer-and-ubuntu-fiesty-fawn/</guid>
		<description><![CDATA[I had the need recently to deploy a merb app. Since this whole project is about trying new things (merb, rspec, etc) I thought I might as well give <a href="http://rubyhitsquad.com/Vlad_the_Deployer.html">Vlad</a> a try.  Unfortunately, as most things sysadmin go I ran into some bumps. So I thought I'd write it out so future googlers have less of a problem getting things going.]]></description>
			<content:encoded><![CDATA[<p>I had the need recently to deploy a merb app. Since this whole project is about trying new things (merb, rspec, etc) I thought I might as well give <a href="http://rubyhitsquad.com/Vlad_the_Deployer.html">Vlad</a> a try.  Unfortunately, as most things sysadmin go I ran into some bumps. So I thought I&#8217;d write it out so future googlers have less of a problem getting things going.</p>

<h2>Vlad deploy file</h2>

<p>Vlad comes with turnkey deployment <em>for rails</em> with apache and mongrel. We&#8217;re using merb, so we&#8217;ve got to make a few changes.  Under <code>config/deploy.rb</code> go ahead and throw something similar to this in:</p>

<pre><code class="ruby">require 'vlad'

set :application, "applicationname"
set :domain, "yourserver.com"
set :deploy_to, "/path/to/deploy"
set :repository, 'git://github.com/kneath/greed.git'

namespace :vlad do
  ##
  # Merb app server

  set :merb_address,       "127.0.0.1"
  set :merb_clean,         false
  set :merb_command,       'merb'
  set :merb_conf,          nil
  set :merb_extra_config,  nil
  set :merb_environment,   "production"
  set :merb_group,         nil
  set :merb_port,          4000
  set :merb_prefix,        nil
  set :merb_servers,       1
  set :merb_user,          nil

  desc "Prepares application servers for deployment. merb
configuration is set via the merb_* variables.".cleanup

  remote_task :setup_app, :roles =&gt; :app do
    "rake"
  end

  def merb(cmd) # :nodoc:
    "cd #{current_path} &amp;&amp; #{merb_command} -p #{merb_port} -c #{merb_servers} -e #{merb_environment} #{cmd}"
  end

  desc "Restart the app servers"

  remote_task :start_app, :roles =&gt; :app do
    run merb('')
  end

  remote_task :start_app =&gt; :stop_app

  desc "Stop the app servers"

  remote_task :stop_app, :roles =&gt; :app do
    run merb("-K all")
  end

  remote_task :migrate_merb, :roles =&gt; :db do
    run "cd #{current_release}; rake db:migrate MERB_ENV=#{merb_environment}"
  end

  task :update do
    run "cp #{shared_path}/database.yml #{current_path}/config/database.yml"
  end
end

task :deploy =&gt; ["vlad:update", "vlad:migrate_merb", "vlad:start_app"]
</code></pre>

<p>(I apologize for no credit given to the author of this, but it was in a pastie I found via ma.gnolia.com and I don&#8217;t even know where it is anymore)</p>

<h3>Setup the server</h3>

<p>Go ahead and run <code>rake vlad:setup</code>  and make sure all your ssh workings are going good. It should create a /path/to/deploy/shared folder.  Inside of that folder, go ahead and throw down your database.yml file with production passwords in it (You <em>aren&#8217;t</em> keeping passwords in your source control are you?).</p>

<p>After that, your server should be all set up!</p>

<h2>Gitting set up</h2>

<h3>Vlad</h3>

<p>Got Vlad 1.2+? Git submodule is already installed. You just need to edit your rake file and change the vlad require to something like this:</p>

<pre><code class="ruby">begin
  require 'vlad'
  Vlad.load :scm =&gt; "git"
rescue LoadError
  # do nothing
end
</code></pre>

<p>Then in your <code>deploy.rb</code> change  your repository location to your git url:</p>

<pre><code class="ruby">set :repository, 'git://github.com/kneath/greed.git'
</code></pre>

<h3>The Server</h3>

<p>Your server must have git installed in order to deploy from a git repository. Some might think a simple <code>sudo apt-get install git-core</code> would do the trick. Well, almost &#8212; you&#8217;ll run into the following error if you do that:</p>

<pre><code>fatal: You must specify an archive format
</code></pre>

<p>Reason for this: <code>apt-get install git-core</code> installs a 1.4x version of git on your Ubuntu machine, and apparently a default for <code>git archive</code> was added in a later version.  Solution: install from source. Go to a temporary source folder and run the following commands:</p>

<pre><code>sudo apt-get remove git-core
wget http://kernel.org/pub/software/scm/git/git-1.5.5.1.tar.bz2
sudo apt-get build-dep git-core
tar xjf git-1.5.5.1.tar.bz2
cd git-1.5.5.1/
./configure
make
sudo make install
</code></pre>

<p>All might not be well with those commands though. If you hit something like:</p>

<pre><code>SUBDIR git-gui
MSGFMT    po/de.msg make[1]: *** [po/de.msg] Error 127
</code></pre>

<p>You&#8217;ll need to install gettext (totally makes sense, right?).  <code>sudo apt-get install gettext</code> and then start the previous sequence of commands where you left off.</p>

<h2>Deploy</h2>

<p>After this, everything worked just fine for me.  <code>rake deploy</code> and vlad should update your code, run the migrations, and start up your servers.</p>
]]></content:encoded>
			<wfw:commentRss>http://warpspire.com/tipsresources/application-development/deploying-merb-with-git-vlad-the-deployer-and-ubuntu-fiesty-fawn/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Greedy</title>
		<link>http://warpspire.com/tipsresources/personal/greedy/</link>
		<comments>http://warpspire.com/tipsresources/personal/greedy/#comments</comments>
		<pubDate>Wed, 30 Apr 2008 18:36:26 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
		
		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://warpspire.com/tipsresources/personal/greedy/</guid>
		<description><![CDATA[Now that I've gone and <a href="/features/ch-ch-ch-changes/">left my job</a>, one of my mandates to myself was that I was going to take all of these random projects of mine seriously.  So what's the first step? I have to figure out a way to make at least some of these projects profitable.  The first step in my mind is to try out private ad sales.]]></description>
			<content:encoded><![CDATA[<p>Now that I&#8217;ve gone and <a href="/features/ch-ch-ch-changes/">left my job</a>, one of my mandates to myself was that I was going to take all of these random projects of mine seriously.  So what&#8217;s the first step? I have to figure out a way to make at least some of these projects profitable.  The first step in my mind is to try out private ad sales.</p>

<h2>Advertising available now</h2>

<p>Starting today you can go ahead and <a href="/advertising">order some ads on Warpspire</a>, or if gaming is your thing <a href="http://totalspore.com/advertising">get some Total Spore ads</a>.  This is the first time I&#8217;ve ever tried the whole private ads thing, so it&#8217;s very much an experiment right now.  However, I do want to make it clear that I&#8217;m going to do my best to keep the ads relevant to the sites&#8217; respective audiences.</p>

<p>The only thing about private ads is that you&#8217;ve got to manage them yourself. And pretty much all ad serving software sucks.</p>

<h2>Greed</h2>

<p>A while (long while) ago I teamed up with <a href="http://sabotagemedia.com">Josh Pigford</a> to build an ad serving application.  Things didn&#8217;t quite work out, mostly because my own goals were higher than my free time.  Well, my free time came back and I kicked down my goals a few meters on the goal post.  What came out is <a href="http://github.com/kneath/greed">Greed</a>.</p>

<p>Greed is a simple ad serving web application written in merb.  I&#8217;ve never written an application in merb before, so I decided to try it out.  Greed is also open source, so fork it, hack it, and use it! I&#8217;ll try and post up my thoughts on merb in the next few weeks.</p>
]]></content:encoded>
			<wfw:commentRss>http://warpspire.com/tipsresources/personal/greedy/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Design Exercises</title>
		<link>http://warpspire.com/tipsresources/design/design-exercises/</link>
		<comments>http://warpspire.com/tipsresources/design/design-exercises/#comments</comments>
		<pubDate>Mon, 28 Apr 2008 00:41:09 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
		
		<category><![CDATA[Design]]></category>

		<guid isPermaLink="false">http://warpspire.com/tipsresources/design/design-exercises/</guid>
		<description><![CDATA[The idea of a design exercise is nothing new, but I recently read <a href="http://twitter.com/cameronmoll/statuses/789096197">a tweet</a> from Cameron Moll that made me rethink about how I really work through the design process.]]></description>
			<content:encoded><![CDATA[<p>The idea of a design exercise is nothing new, but I recently read <a href="http://twitter.com/cameronmoll/statuses/789096197">a tweet</a> from Cameron Moll that made me rethink about how I really work through the design process.</p>

<p>Design is a tricky thing. There&#8217;s no one right way to do something &#8212; it&#8217;s a mix of style, aesthetics, and culture.  This means that you can solve any design problem a dozen different ways and still come up with something that is interpreted as a success by your client.  It can be easy to fall into a design rut, always falling back to your same old tricks.  People encourage you by complimenting the work, but deep down sometimes you might wonder if you could have done something better.</p>

<p>That&#8217;s why I think design exercises are an important factor of any designer&#8217;s career.  Every now and then you need to force yourself to solve a problem differently &#8212; it&#8217;ll force you to branch out and look for new tools and techniques.  It&#8217;ll force your brain into a new line of thinking and you might even find a new style of design that you prefer.  When I look back on my personal projects&#8217; designs, I find that I&#8217;ve almost always forced myself into a design exercise from the beginning.  The rewards have been monumental personally, so I thought I might work through some of my past work and how I worked design exercises into them.</p>

<h2>Examples from Warpspire&#8217;s past</h2>

<div class="figure">
<a href="/images/posts/design-process/warpspire_3-full.jpg"><img src="/images/posts/design-process/warpspire_3.jpg" /></a>
<small>Version 3, circa Summer 2004</small>
</div>

<p><strong>Exercise:</strong> Work with texture to create an appearance of aging.</p>

<p><strong>Solution:</strong> This site came out just before Cameron Moll&#8217;s Wicked Worn series (or at least, before I had read it).  However, I wanted to design something that was notably non-digital-ly.  Forcing myself into this style made me look for new approaches to designing, and two great things came of this: the discovery of the incredible diversity of free Photoshop brushes, and the use of photographs/scans in nonstandard ways.  </p>

<p>What I mean by that last point is using a photograph for something other than a picture in the page.  Creating the envelope in the upper left was incredibly challenging to me at the time, and the only way I was able to reliably recreate it was to use a photograph of an envelope as a stencil of sorts.</p>

<div class="figure">
<a href="/images/posts/design-process/warpspire_4-full.jpg"><img src="/images/posts/design-process/warpspire_4.jpg" /></a>
<small>Version 4, circa Winter 2005</small>
</div>

<p><strong>Exercise:</strong> Use color and create something notably non-bloggy.</p>

<p><strong>Solution:</strong> This design of Warpspire marked the first design I had created that used any kind of bold or vivid colors; my past designs had always relied on muted or monochromatic color schemes.  Forcing myself to work with color ended up in me throwing out nearly a dozen comps, but it was invaluable experience &#8212; by the end of it I felt infinitely more comfortable using color in my design.</p>

<div class="figure">
<a href="/images/posts/design-process/warpspire_5-full.jpg"><img src="/images/posts/design-process/warpspire_5.jpg" /></a>
<small>Version 5, circa Summer 2007</small>
</div>

<p><strong>Exercise:</strong> Highlight a diverse collection of content on the homepage while dividing opinion from tutorial-type content.</p>

<p><strong>Solution:</strong> Forcing myself to let the content do the designing was really tricky. I strayed away from any unnecessary visual clutter, and couldn&#8217;t fall back to cheesy ornamentals throughout the site.  I think the single largest benefit of this design style was learning to use stock images better.  Even adding a mediocre stock image to a design can make the end result visually stunning.</p>

<h2>Conclusion</h2>

<p>I think the idea of assigning yourself design exercises is a great idea.  If you just design with all the tools you have, your designs will soon get stale and you won&#8217;t be adding any new tools to your toolbox.  By forcing yourself to solve a problem in a different way it forces you to break your normal thinking pattern and explore. It keeps your creative juices flowing and can force you to design in a style you usually wouldn&#8217;t turn to.</p>

<p>I actually do the same technique with my programming &#8212; every now and then I <a href="/tipsresources/programming/a-language-a-year/">learn a new language</a>.  Pretty much any problem <em>can</em> be solved with the language of your choice, but it&#8217;s a good idea to force yourself into new uncomfortable languages just to broaden your knowledge base.</p>
]]></content:encoded>
			<wfw:commentRss>http://warpspire.com/tipsresources/design/design-exercises/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Reducing comments and increasing documentation</title>
		<link>http://warpspire.com/tipsresources/programming/reducing-comments-and-increasing-documentation/</link>
		<comments>http://warpspire.com/tipsresources/programming/reducing-comments-and-increasing-documentation/#comments</comments>
		<pubDate>Sat, 12 Apr 2008 07:22:07 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://warpspire.com/tipsresources/programming/reducing-comments-and-increasing-documentation/</guid>
		<description><![CDATA[When I first started programming, my only goal was to get things to work.  Now that I've gone past how to get things to work, I've reached a new point in development: maintaining my own code.  I never thought that things like documentation were important when you're dealing with your own code.  I mean, <em>you know</em> what you're thinking, right?]]></description>
			<content:encoded><![CDATA[<p>When I first started programming, my only goal was to get things to work.  Now that I&#8217;ve gone past how to get things to work, I&#8217;ve reached a new point in development: maintaining my own code.  I never thought that things like documentation were important when you&#8217;re dealing with your own code.  I mean, <em>you know</em> what you&#8217;re thinking, right?</p>

<p>Well I was oh so wrong.  Documenting your own code is <em>critical</em> to future maintenance.  It&#8217;s been almost a year since I launched the <a href="http://poetrywithmeaning.com/blog/show/4598">rewrite of Poetry with meaning</a> and it&#8217;s become incredibly frustrating maintaining the site.  I realized the reason for this is lack of documentation and code testing (more on this later).  Coming back to 2,000 lines of code without looking at it for 4 or 5 months is just painful.  The problem with the code base is that I was taking too much time <em>commenting</em> the code &#8212; and no time <em>documenting</em> it.</p>

<p>Let&#8217;s take an example of some <em>commented</em> but not <em>documented</em> code:</p>

<pre><code class="ruby"># clean the filename
stripped_location = @file_location.gsub(/(.+)\.(.+)/, '\1')
stripped_location = @options[:redo] ? stripped_location.gsub(/(.+)_original/, &#8216;\1&#8242;) : stripped_location
</code></pre>

<p>This code doesn&#8217;t really tell me anything.  Cleans the filename? Coming back to this code months after it was written doesn&#8217;t tell me a thing.</p>

<p>What I should have been doing is documenting the code.  Documentation to me answers the &#8220;what does this do?&#8221; question.  Here&#8217;s an example of some code in progress:</p>

<pre><code class="ruby">module Overseer
  module Backup
    # Creates a backup for one mysql database. The resulting export will be 
    # gzipped and named with the date first and then the databse name
    #
    # Usage:
    #   Overseer::Backup::Mysql.new(:username =&gt; "webdb", :password =&gt; "ultimatetest", :host =&gt; "mysql.example.com", :database =&gt; "pwm_production")
    #   For database called "pwm_production" backed up on April 7, 2008 , the final name will be: 2008.04.07.pwm_production.sql.gz
    #
    # Options:
    # * :username - database username
    # * :password - database password
    # * :host (optional) - the database host name
    # * :database - the name of the database
    class Mysql

      attr_accessor :username, :password, :host, :database

      def initialize(options = {})
        @username = options[:username]
        @password = options[:password]
        @host = options[:host].nil? ? &#8220;localhost&#8221; : options[:host]
        @database = options[:database]
      end

    end
  end
end
</code></pre>

<p>I haven&#8217;t even really written anything useful yet &#8212; but by writing the documentation I&#8217;ll know what I was doing a week from today instead of just blindly looking at the code.  My documentation tells me <em>how</em> to use the code, not <em>what</em> the code does.</p>

<p>Documenting your code also forces you to really think the functionality through. It makes you think about the architecture of your code before you write it and forces you to think about how it will be <em>used</em> instead of how it was written.  It all comes back to the idea that code is written for humans, not machines &#8212; so why not start with writing your code 100% human style? (in text!)</p>
]]></content:encoded>
			<wfw:commentRss>http://warpspire.com/tipsresources/programming/reducing-comments-and-increasing-documentation/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Scaling is for nerds</title>
		<link>http://warpspire.com/tipsresources/programming/scaling-is-for-nerds/</link>
		<comments>http://warpspire.com/tipsresources/programming/scaling-is-for-nerds/#comments</comments>
		<pubDate>Tue, 18 Mar 2008 00:13:21 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://warpspire.com/tipsresources/programming/scaling-is-for-nerds/</guid>
		<description><![CDATA[One of the most interesting bits of information from SXSW for me was a small conversation I had while walking to Dinner with <a href="http://www.felocity.org/">Jakob Heuser</a> from Gaia Online.  We were discussing frameworks and scaling, and more or less his opinion was that frameworks don't scale. Don't matter if it's Rails, Django, Symphony -- they don't scale in a general sense.  I agree with him completely, but let me qualify that a bit first.]]></description>
			<content:encoded><![CDATA[<p>One of the most interesting bits of information from SXSW for me was a small conversation I had while walking to Dinner with <a href="http://www.felocity.org/">Jakob Heuser</a> from Gaia Online.  We were discussing frameworks and scaling, and more or less his opinion was that frameworks don&#8217;t scale. Don&#8217;t matter if it&#8217;s Rails, Django, Symphony &#8212; they don&#8217;t scale in a general sense.  I agree with him completely, but let me qualify that a bit first.</p>

<p>The question that struck me in particular came when someone was badgering him at around what size site would you encounter problems scaling Rails.  His response was something along the lines of: &#8220;No offense, but you won&#8217;t ever build a site popular enough to worry about it.&#8221;  And it&#8217;s damn true.</p>

<p>Who cares if your framework can scale if it&#8217;s never going to be big enough to worry about? The truth is that almost all web ventures never become big enough to even need a separate database server, let alone a farm of memcached servers, file servers, and enough computing power to plan a trip to Orion.  That doesn&#8217;t mean they won&#8217;t become profitable. You can be extremely profitable with relatively low traffic.</p>

<p>So don&#8217;t worry about scaling &#8212; scaling is for nerds.  By the time you hit pain points, you can bring in someone who really knows what they&#8217;re doing.  Most importantly, by the time you hit pain points, you should be profitable enough to not worry about bringing in someone who knows what they&#8217;re doing.</p>

<p>And no, just because your site goes down for an hour while on the home page of digg.com doesn&#8217;t mean that you need to worry about scaling.</p>
]]></content:encoded>
			<wfw:commentRss>http://warpspire.com/tipsresources/programming/scaling-is-for-nerds/feed/</wfw:commentRss>
		</item>
		<item>
		<title>South by South West 08</title>
		<link>http://warpspire.com/tipsresources/personal/south-by-south-west-08/</link>
		<comments>http://warpspire.com/tipsresources/personal/south-by-south-west-08/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 17:54:53 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
		
		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://warpspire.com/tipsresources/personal/south-by-south-west-08/</guid>
		<description><![CDATA[Almost forgot to mention -- I'm heading out to SXSWi this year for the first time.  I'm totally stoked, regardless of how "uncool" it's become to go.  I'll be the short kid with way too much hair on my head. Come on up and talk to me -- you can grab one of my <a href="http://helvetino.com">new fangled cards</a>.

More info on that previous link soon :)]]></description>
			<content:encoded><![CDATA[<p>Almost forgot to mention &#8212; I&#8217;m heading out to SXSWi this year for the first time.  I&#8217;m totally stoked, regardless of how &#8220;uncool&#8221; it&#8217;s become to go.  I&#8217;ll be the short kid with way too much hair on my head. Come on up and talk to me &#8212; you can grab one of my <a href="http://helvetino.com">new fangled cards</a>.</p>

<p>More info on that previous link soon :)</p>
]]></content:encoded>
			<wfw:commentRss>http://warpspire.com/tipsresources/personal/south-by-south-west-08/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Your mom&#8217;s not accessible</title>
		<link>http://warpspire.com/tipsresources/web-production/your-moms-not-accessible/</link>
		<comments>http://warpspire.com/tipsresources/web-production/your-moms-not-accessible/#comments</comments>
		<pubDate>Tue, 12 Feb 2008 02:35:13 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
		
		<category><![CDATA[Web Production]]></category>

		<guid isPermaLink="false">http://warpspire.com/tipsresources/interactive-development/your-moms-not-accessible-or-the-power-of-inaccurate-preaching/</guid>
		<description><![CDATA[A few days ago, Arron Cannon over at North Temple threw up a post titled: <a href="http://northtemple.com/1285">Is Adobe Flex Really Accessible...</a>  which was full of inaccuracies based solely on his inexperience with Flex (read Adam Lehman's <a href="http://www.adrocknaphobia.com/post.cfm/is-adobe-flex-really-accessible-you-bet-your-robot-voice-it-is">response on the subject</a>).  This isn't meant as an insult, but rather a factual observation: Arron simply doesn't have a lot (any?) experience with the technology.]]></description>
			<content:encoded><![CDATA[<p>A few days ago, Arron Cannon over at North Temple threw up a post titled: <a href="http://northtemple.com/1285">Is Adobe Flex Really Accessible&#8230;</a>  which was full of inaccuracies based solely on his inexperience with Flex (read Adam Lehman&#8217;s <a href="http://www.adrocknaphobia.com/post.cfm/is-adobe-flex-really-accessible-you-bet-your-robot-voice-it-is">response on the subject</a>).  This isn&#8217;t meant as an insult, but rather a factual observation: Arron simply doesn&#8217;t have a lot (any?) experience with the technology.</p>

<p>But that didn&#8217;t stop him from preaching (all comments are disabled and Arron does not respond to email) that you shouldn&#8217;t use the technology.  Quite honestly, it pissed me off.  I sent an email to Arron shortly after reading his post on Thursday, and Arron seemed fit to ignore my email completely.</p>

<p>Here is the letter I sent to him:</p>

<blockquote>
  <p>Arron,</p>
  
  <p>While I appreciate your intrigue about Flex, I feel like you&#8217;re
  unfairly damning a technology for all the wrong reasons.  As per your
  technical argument, you&#8217;re probably right. However that comes with the
  caveat that JAWS can rarely navigate the majority of the HTML web as
  it sits today with any sort of ease.  It&#8217;s no lie to anyone who&#8217;s
  tried to legitimately use screen readers that the technology is highly
  divisive and non-functional (different readers render differently,
  function differently, and support different aspects by default).</p>
  
  <p>The sad and unfortunate fact is that anyone who wants a truly
  accessible site must work very hard, testing and using various screen
  readers throughout development. (no free lunch indeed). Using
  standards &amp; best practices only gets us half-way there.</p>
  
  <p>Suggesting that Flex should not be used (&#8221;However, until that happens,
  I can not recommend Adobe Flex.&#8221;) is like saying we shouldn&#8217;t move
  forward with HD programming because some  people still have SD TV
  sets.  Flex is a revolutionary technology that redefines the rules of
  what we&#8217;re capable of delivering over the web.  It <em>can</em> be
  accessible, and even more so than HTML ever could if you have the
  desire (you could script your own narrative to guide visually disabled
  through the form process, accepting voice input and encoding to
  textual input to the form if you felt the need).</p>
  
  <p>At the end of the day, if you&#8217;re looking to deliver a site targeted at
  visually impaired people, Flex is almost certainly not your choice.
  The same way social security benefits advertisements will continue to
  be broadcast in high-contrast SD programming on TV.</p>
  
  <p>But is that reason to not use a technology?</p>
</blockquote>

<p>The summary of the above is twofold:</p>

<ul>
<li>Even HTML is not accessible by default. You must work very hard to make a fully accessible website using HTML, CSS and (should you dare) Javascript.</li>
<li>Flex doesn&#8217;t really need to be accessible.  That&#8217;s not the target of the technology.</li>
</ul>

<p>Much talk and little action is done on the web in terms of &#8220;accessibility&#8221; and making sites available to the visually impaired.  I encourage anyone who has never used JAWS to go ahead and use it on your own site.  Then I suggest you try a couple other competing screen reading solutions.  I think you&#8217;ll find that it&#8217;s kind of a crap shoot.  Navigating most &#8220;accessible&#8221; and semantic web sites is maddening at best.  Most of the time it feels as though someone&#8217;s asking you to read War &amp; Peace without any paragraphs or headings.  Sure, the information&#8217;s there &#8212; but it&#8217;s realistically inaccessible.</p>

<p>My point being: accessibility is not something a technology offers.  It&#8217;s something that a technology can <em>support</em> (and indeed, Flex supports accessibility just fine) &#8212; but it&#8217;s not something a technology gives you for free.</p>

<p>Unfortunately I believe that Arron has done his damage to the web community and turned thousands away from an amazing technology simply because he doesn&#8217;t personally like it.  Undoubtedly, Arron&#8217;s response will be: &#8220;show me.&#8221;  My response to that is: Why? You&#8217;re persecuting a community without cause.  Give me proof Flex is not accessible.  All in all, I just think it&#8217;s sad &#8212; and I hope that anyone reading this won&#8217;t throw Flex out because it&#8217;s &#8220;inaccessible.&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://warpspire.com/tipsresources/web-production/your-moms-not-accessible/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Understanding javascript effects</title>
		<link>http://warpspire.com/tipsresources/personal/understanding-javascript-effects/</link>
		<comments>http://warpspire.com/tipsresources/personal/understanding-javascript-effects/#comments</comments>
		<pubDate>Wed, 09 Jan 2008 08:18:13 +0000</pubDate>
		<dc:creator>Kyle</dc:creator>
		
		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://warpspire.com/tipsresources/personal/understanding-javascript-effects/</guid>
		<description><![CDATA[Unless you&#8217;ve been living under a rock for the past couple of years, you&#8217;re bound to be familiar with AJAX javascript effects.  With the immense popularity of packages like Scriptaculous and moo.fx, designers everywhere have found easy ways to add animation and interactivity to their applications.  But how do these effects work?  [...]]]></description>
			<content:encoded><![CDATA[<p>Unless you&#8217;ve been living under a rock for the past couple of years, you&#8217;re bound to be familiar with <strike>AJAX</strike> <ins>javascript effects</ins>.  With the immense popularity of packages like <a href="http://script.aculo.us">Scriptaculous</a> and <a href="http://moofx.mad4milk.net/">moo.fx</a>, designers everywhere have found easy ways to add animation and interactivity to their applications.  But how do these effects work?  I&#8217;ll admit that when I first started delving into javascript, I thought that these effects must be some of the most complicated javascript ever written.  It turns out that they&#8217;re fairly simple &#8212; and that once you understand how they work, you can write your very own effects with ease.</p>

<h2>The Basics</h2>

<p>The core of all of these effects is a simple sequence of events:</p>

<ol>
<li>The effect function is called on an element (i.e. <span class="minicode">new Effect.Fade(&#8217;myid&#8217;)</span>)</li>
<li>The effect function sets a number of initial styles on the element</li>
<li>The effect function then defines an update function that modifies CSS properties of the element in reference to a point from 0 to 1</li>
<li>This update function is called repeatedly for a set duration of time passing in the reference point each time</li>
<li>A cleanup function is called to re-set some of the original styles, and do the final dirty work.</li>
</ol>

<div class="figure">
<div id="flash_example">Please Install Flash Player to view this demonstration</div>
</div>

<script type="text/javascript">
   var so = new SWFObject("/images/posts/javascript-effects/javascript_effects.swf", "effects_sample", "554", "300", "8", "#CCCCCC");
   so.write("flash_example");
</script>

<h3>Defining styles</h3>

<p>This step is crucial in any effect.  In order for some visual effects to be pulled off, certain CSS properties must be set on the element before anything can happen.  The most common styles that are modified during this startup time are the <span class="minicode">overflow</span> and <span class="miinicode">position</span> properties.  This allows us to use CSS properties like <span class="minicode">width</span>, <span class="minicode">height</span>, <span class="minicode">left</span> and <span class="minicode">top</span> to make the element expand, contract, and disappear out of bounds.</p>

<h3>Update function</h3>

<p>This function is the most important, and also the simplest part of the javascript effect.  It modifies one or more of the element&#8217;s CSS properties an incremental amount, in relation to an internal reference point (going from 0 to 1).  The easiest example of this is opacity. If we imagine that we are going to repeatedly call this function and pass in the reference value, you could easily change the opacity from 100% to 0% by setting the opacity equal to the reference value multiplied by 100%.</p>

<h3>Calling the update function</h3>

<p>This is the most interesting part of the javascript effects to me.  The update function is called is by setting a timer using <span class="minicode">setTimeout()</span> every so often (40ms is a good interval to start out with).  This update function is called for a set duration of time (500ms, or half a second is a typical duration).  While this is going on, an internal reference point (mentioned above) is set to a new value each time the update function is called.  The javascript uses a formula to generate this reference value much like this: <span class="minicode">time spent / total duration = counter</span>.</p>

<p>&#8230; except there&#8217;s one little catch: linear effects feel very unnatural and robotic to the human eye.  This is where I get all geeky about the relation between math and design and how everything ties back into math sooner or later (yes, I&#8217;m really that big of a nerd).  So - if we can&#8217;t use a simple linear timeline, what do we use? It turns out that a <em>Sinusoidal</em> patterns work beautifully.  This is the equation that the majority of the effects in Scriptaculous and moo.fx use, but they also offer several others: linear, cubic, circular, flicker, wobble, and pulse.</p>

<p>Here are examples of each of these functions using a simple timeline and colored square (to demonstrate the timeline&#8217;s effect on a sample opacity effect) over a 2 second period.</p>

<h3>Sinusodial</h3>

<div class="timeline" id="sinusodial-timeline"><span class="marker"></span> <div class="square"></div></div>

<p class="actions"><a href="#" onclick="Timeline.go('sinusodial'); return false">start sinusodial timeline</a></p>

<h3>Linear</h3>

<div class="timeline" id="linear-timeline"><span class="marker"></span> <div class="square"></div></div>

<p class="actions"><a href="#" onclick="Timeline.go('linear'); return false">Start linear timeline</a></p>

<h3>Cubic</h3>

<div class="timeline" id="cubic-timeline"><span class="marker"></span> <div class="square"></div></div>

<p class="actions"><a href="#" onclick="Timeline.go('cubic'); return false">Start cubic timeline</a></p>

<h3>Circular</h3>

<div class="timeline" id="circular-timeline"><span class="marker"></span> <div class="square"></div></div>

<p class="actions"><a href="#" onclick="Timeline.go('circular'); return false">Start circular timeline</a></p>

<h3>Flicker</h3>

<div class="timeline" id="flicker-timeline"><span class="marker"></span> <div class="square"></div></div>

<p class="actions"><a href="#" onclick="Timeline.go('flicker'); return false">Start flicker</a></p>

<h3>Wobble</h3>

<div class="timeline" id="wobble-timeline"><span class="marker"></span> <div class="square"></div></div>

<p class="actions"><a href="#" onclick="Timeline.go('wobble'); return false">Start wobble timeline</a></p>

<p><strong>Bonus!</strong> <a href="#" onclick="Timeline.go('sinusodial');Timeline.go('linear');Timeline.go('cubic');Timeline.go('circular');Timeline.go('flicker');Timeline.go('wobble'); return false">Start all effects simultaneously</a></p>

<p>Try mixing up these different timelines in your next javascript effects &#8212; it&#8217;s a great (and easy!) way to make your app feel just a little different than everything else out there.</p>

<h3>Cleanup function</h3>

<p>The last part of the process is a very simple step that just cleans up any styles that the effect created that you don&#8217;t want lying around.  If you happen to set a style in the initialization, it&#8217;s usually a good idea to undo that style at the end of the effect.</p>

<p>This is also the time you can apply any finisher properties.  For elements that are fading out, or zooming out of view &#8212; you&#8217;ll probably want to be setting <code>display:none;</code> so they are removed from the layout flow.</p>

<h2>Conclusion</h2>

<p>Once you get a good grip on how Javascript effects work at their core, you&#8217;ll soon realize that they&#8217;re not so nasty and complex.  The hardest part is the math &#8212; and most computer geeks I know are pretty good at math.  Play around with trying to create your own effects.</p>

<h3>Challenge</h3>

<p>If you&#8217;d like to challenge yourself, try and use your framework of choice (Prototype, MooTools, YUI, jQuery) and build a javascript effect that moves an element in an elliptical path.  <em>Hint: You might try absolutely positioning the element inside of a relatively positioned bounding box.</em></p>

<script src="/js/libraries/prototype/stable.js" type="text/javascript" charset="utf-8"></script>
<script src="/js/libraries/moo.fx/moo.fx.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">

  // fx.Position &#038; fx.Horizontal were written by me
  // They're in the moo.fx style, but do require more prototype methods than
  // prototype.lite.js supports

  fx.Position = Class.create();
  fx.Position.prototype = Object.extend(new fx.Base(), {
    initialize: function(el, options) {
        this.el = $(el);
        this.iniX = Position.positionedOffset(this.el)[0]
        this.iniY = Position.positionedOffset(this.el)[1]
        this.setOptions(options);
    }
  });

  fx.Horizontal = Class.create();
  Object.extend(Object.extend(fx.Horizontal.prototype, fx.Position.prototype), {    
    increase: function() {
        this.el.style.left = this.now + &#8220;px&#8221;;
    },

    toggle: function(){
      this.el.leftPos = Position.positionedOffset(this.el)[0];
        if (this.el.leftPos > 0) this.custom(this.el.leftPos, 0);
        else this.custom(0, this.iniX);
    }
  });

  // Taken from script.aculo.us, modified to fit moo.fx coding style
  fx.flicker = function(pos){
    return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
  }
  fx.wobble = function(pos){
    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
  }

  // My own little trigger object
  var Timeline = {
    go: function(type){
      var timeline = $(type + &#8216;-timeline&#8217;);
      var marker = timeline.firstChild;
      var square = timeline.getElementsByTagName(&#8217;div&#8217;)[0];
      switch(type){
        case &#8220;sinusodial&#8221;: 
          var effect = new fx.Horizontal(marker, {transition: fx.sinoidal, duration:2000})
          var opacity = new fx.Opacity(square, {transition: fx.sinoidal, duration:2000})
        break;
        case &#8220;linear&#8221;: 
          var effect = new fx.Horizontal(marker, {transition: fx.linear, duration:2000})
          var opacity = new fx.Opacity(square, {transition: fx.linear, duration:2000})
        break;
        case &#8220;cubic&#8221;: 
          var effect = new fx.Horizontal(marker, {transition: fx.cubic, duration:2000})
          var opacity = new fx.Opacity(square, {transition: fx.cubic, duration:2000})
        break;
        case &#8220;circular&#8221;: 
          var effect = new fx.Horizontal(marker, {transition: fx.circ, duration:2000})
          var opacity = new fx.Opacity(square, {transition: fx.circ, duration:2000})
        break;
        case &#8220;flicker&#8221;: 
          var effect = new fx.Horizontal(marker, {transition: fx.flicker, duration:2000})
          var opacity = new fx.Opacity(square, {transition: fx.flicker, duration:2000})
        break;
        case &#8220;wobble&#8221;: 
          var effect = new fx.Horizontal(marker, {transition: fx.wobble, duration:2000})
          var opacity = new fx.Opacity(square, {transition: fx.wobble, duration:2000})
        break;
      }
      effect.custom(0, 500);
      effect.toggle();
      opacity.toggle();
    }
  }
</script>

<style>
  .main p.actions{
    margin-top:5px;  
  }

  .timeline{
    border:1px solid #eaeaea;
    background:#fefefe;
    height:40px;
    margin:1.5em 0 0 0;
    position:relative;
  }
  .timeline .marker{
    display:block;
    height:40px;
    width:4px;
    background:#666;
    position:absolute;
    top:0;
    left:0;
  }

  .timeline .square{
    width:40px;
    height:40px;
    background:#006699;
    position:absolute;
    top:0;
    right:0;
  }

</style>
]]></content:encoded>
			<wfw:commentRss>http://warpspire.com/tipsresources/personal/understanding-javascript-effects/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.984 seconds -->
