<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Chris Nanney : Journal</title>
	<atom:link href="http://cnanney.com/journal/feed/" rel="self" type="application/rss+xml" />
	<link>http://cnanney.com/journal</link>
	<description>Things you might find useful.</description>
	<lastBuildDate>Mon, 05 Dec 2011 22:33:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.3</generator>
		<item>
		<title>CSS Flip-Counter Experiment</title>
		<link>http://cnanney.com/journal/code/css-flip-counter-experiment/</link>
		<comments>http://cnanney.com/journal/code/css-flip-counter-experiment/#comments</comments>
		<pubDate>Mon, 05 Dec 2011 21:50:39 +0000</pubDate>
		<dc:creator>Chris Nanney</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://cnanney.com/journal/?p=708</guid>
		<description><![CDATA[The biggest shortcoming of my flip-counter script is the difficulty in modifying the appearance of the counter&#8212;any styling changes require altering 70 different sprite states. I am constantly asked for a nice layered template that would make updating the counter easier, but unfortunately none exists. The best way to make the counter&#8217;s appearance easily customizable [...]]]></description>
			<content:encoded><![CDATA[<p>The biggest shortcoming of my <a href="http://cnanney.com/journal/code/apple-style-counter-revisited/">flip-counter script</a> is the difficulty in modifying the appearance of the counter&mdash;any styling changes require altering 70 different sprite states. I am constantly asked for a nice layered template that would make updating the counter easier, but unfortunately none exists. The best way to make the counter&#8217;s appearance easily customizable is to get rid of the images entirely, and that was the goal of this experiment.<span id="more-708"></span></p>
<h2>The promise of CSS</h2>
<p>After seeing a <a href="http://tympanus.net/Tutorials/TypographyEffects/index4.html">demo from Codrops</a>, I realized it was possible to recreate the counter with CSS, and used that demo as a template. The end result is a counter that uses zero images and has buttery smooth digit animations. Because it is styled entirely with CSS you can easily change colors, gradients, shadows, fonts, etc. without having to touch an image editor. Because it is based on my old counter script, it has all the same methods and functionality (add, step, smart increment, etc).</p>
<h2>Limitations</h2>
<p>It sounds great, but there is a major limitation: CSS 3D animations have <a href="http://caniuse.com/#feat=transforms3d">very poor browser support</a>. Currently it only works in Chrome, and curiously has issues in Safari. Non-webkit browsers see a static version. It is just a proof of concept, not ready for prime-time.</p>
<h2>Demo</h2>
<p>You can test it out yourself below. I&#8217;ve included 4 sample styles for the counter: default, light, small, and huge. Switching between them changes a single CSS class name, that&#8217;s it&#8230; Oh the joy of only using CSS.</p>
<p><b><a class="special" href="http://cnanney.com/journal/demo/css-flip-counter/">CSS Flip-Counter Experiment</a></b></p>
<p>This was just for fun, so don&#8217;t use it on a production site unless you really know what you&#8217;re doing.</p>
]]></content:encoded>
			<wfw:commentRss>http://cnanney.com/journal/code/css-flip-counter-experiment/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Logging Disqus Comments with Clicky</title>
		<link>http://cnanney.com/journal/code/logging-disqus-comments-with-clicky/</link>
		<comments>http://cnanney.com/journal/code/logging-disqus-comments-with-clicky/#comments</comments>
		<pubDate>Tue, 05 Apr 2011 23:07:56 +0000</pubDate>
		<dc:creator>Chris Nanney</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://cnanney.com/journal/?p=685</guid>
		<description><![CDATA[When someone makes a comment on my site, I like to see it in the visitor&#8217;s action list on Clicky. If you&#8217;re using Disqus with WordPress, here&#8217;s an easy way to log comments. Inside the Disqus plugin folder, open comments.php. Scroll down to the JavaScript, and look for: var disqus_config = function &#40;&#41; &#123; var [...]]]></description>
			<content:encoded><![CDATA[<p>When someone makes a comment on my site, I like to see it in the visitor&#8217;s action list on Clicky. If you&#8217;re using Disqus with WordPress, here&#8217;s an easy way to log comments.</p>
<p><span id="more-685"></span>Inside the Disqus plugin folder, open <code>comments.php</code>. Scroll down to the JavaScript, and look for:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> disqus_config <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #003366; font-weight: bold;">var</span> config <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// Access to the config object</span></pre></div></div>

<p>Inside this config function, paste this snippet:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">config.<span style="color: #660066;">callbacks</span>.<span style="color: #660066;">onNewComment</span>.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
   clicky.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span>window.<span style="color: #660066;">location</span>.<span style="color: #660066;">pathname</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">'#post-comment'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'Post Comment'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   clicky.<span style="color: #660066;">goal</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'Post Comment'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Here I&#8217;ve added &#8220;#post-comment&#8221; to the end of the current page URL. This is because Clicky only allows one title per URL, and the current URL is already matched with whatever the title of your page is. Since I want this action to show up with the title &#8220;Post Comment&#8221;, I have to make the URL unique. For me, appending &#8220;#post-comment&#8221; makes it unique, but if you use that hash for something else on the page, change it. The point is to make it something unique for the purpose of logging comments.</p>
<p>I also log a dynamic goal named &#8220;Post Comment&#8221;. Since I&#8217;m using <a href="https://chrome.google.com/extensions/detail/nhdlcoplfdhmdbeleincmcnmgdajohig">Clicky Monitor</a>, I get a nice desktop notification when someone leaves a comment.</p>
<p>This concept of adding a callback function for new comments can be applied however you use Disqus, it doesn&#8217;t need to be with WordPress. This example is specific for Disqus + WordPress plugin. If you&#8217;re including the Disqus JavaScript yourself without a plugin, the syntax is <a href="http://docs.disqus.com/help/60/">slightly different</a>.</p>
<p>If you have a question or comment, please leave it below.</p>
]]></content:encoded>
			<wfw:commentRss>http://cnanney.com/journal/code/logging-disqus-comments-with-clicky/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Scrolling Content with jQueryUI Slider</title>
		<link>http://cnanney.com/journal/code/scrolling-content-with-jqueryui-slider/</link>
		<comments>http://cnanney.com/journal/code/scrolling-content-with-jqueryui-slider/#comments</comments>
		<pubDate>Sun, 06 Feb 2011 01:25:49 +0000</pubDate>
		<dc:creator>Chris Nanney</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://cnanney.com/journal/?p=637</guid>
		<description><![CDATA[My first step when thinking of ways to create scrollable content was a Google search that lead me to a good post outlining how to use jQueryUI Slider to scroll a div. This solution required altering the jQueryUI source, which I felt was unnecessary, so I came up with a simple solution. Slider interactions There [...]]]></description>
			<content:encoded><![CDATA[<p>My first step when thinking of ways to create scrollable content was a Google search that lead me to a <a href="http://www.switchonthecode.com/tutorials/using-jquery-slider-to-scroll-a-div">good post</a> outlining how to use jQueryUI Slider to scroll a div. This solution required altering the jQueryUI source, which I felt was unnecessary, so I came up with a simple solution.</p>
<p><span id="more-637"></span></p>
<h2>Slider interactions</h2>
<p>There are two different interactions with the slider: clicking anywhere on the slider, and dragging the slide head. When clicking on the slider you want the slide head and content to smoothly animate to the clicked position. When dragging, you want the content to match the slide head position 1:1. Here&#8217;s an example of both:</p>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/div-slide/div-slide.gif" alt="Scrolling content example." />
<p class="img_caption">Scrolling content example.</p>
</div>
<h2>Simple setup</h2>
<p>The HTML is very simple. Inside a parent container is the scroll content and the slider, and the content is an unordered list:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;scroll-container&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span> 
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;scroll-content&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span> 
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>2<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>3<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>4<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>5<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>6<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>7<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>8<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;scroll-slider&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>The JavaScript for the slider:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Variable to hold scroll type</span>
<span style="color: #003366; font-weight: bold;">var</span> slideDrag<span style="color: #339933;">,</span>
<span style="color: #006600; font-style: italic;">// Width of .scroll-content ul</span>
slideWidth <span style="color: #339933;">=</span> <span style="color: #CC0000;">330</span><span style="color: #339933;">,</span>
<span style="color: #006600; font-style: italic;">// Speed of animation in ms</span>
slideSpeed <span style="color: #339933;">=</span> <span style="color: #CC0000;">400</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// Initialize sliders</span>
$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;.scroll-slider&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">slider</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    animate<span style="color: #339933;">:</span> slideSpeed<span style="color: #339933;">,</span>
    start<span style="color: #339933;">:</span> checkType<span style="color: #339933;">,</span>
    slide<span style="color: #339933;">:</span> doSlide<span style="color: #339933;">,</span>
    max<span style="color: #339933;">:</span> slideWidth 
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
&nbsp;
<span style="color: #003366; font-weight: bold;">function</span> checkType<span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    slideDrag <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">originalEvent</span>.<span style="color: #660066;">target</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">hasClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;ui-slider-handle&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">function</span> doSlide<span style="color: #009900;">&#40;</span>e<span style="color: #339933;">,</span> ui<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> target <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">target</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">prev</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;.scroll-content&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #006600; font-style: italic;">// If sliders were above the content instead of below, we'd use:</span>
    <span style="color: #006600; font-style: italic;">// target = $(e.target).next(&quot;.scroll-content&quot;)</span>
    maxScroll <span style="color: #339933;">=</span> target.<span style="color: #660066;">attr</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;scrollWidth&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> target.<span style="color: #660066;">width</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// Was it a click or drag?</span>
    <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>slideDrag <span style="color: #339933;">==</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// User dragged slider head, match position</span>
        target.<span style="color: #660066;">attr</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>scrollLeft<span style="color: #339933;">:</span> ui.<span style="color: #660066;">value</span> <span style="color: #339933;">*</span> <span style="color: #009900;">&#40;</span>maxScroll <span style="color: #339933;">/</span> slideWidth<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000066; font-weight: bold;">else</span><span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// User clicked on slider itself, animate to position</span>
        target.<span style="color: #000066;">stop</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">animate</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
            scrollLeft<span style="color: #339933;">:</span> ui.<span style="color: #660066;">value</span> <span style="color: #339933;">*</span> <span style="color: #009900;">&#40;</span>maxScroll <span style="color: #339933;">/</span> slideWidth<span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> slideSpeed<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>When the slider is clicked, the function <code>checkType()</code> is executed, which determines if the handle or the slider was clicked. This determines which type of animation to do.</p>
<p>The other benefit of setting the code up like this is that I can have multiple sliders on the page that are all controlled with this single function. The piece that makes that possible is <code>var target = $(e.target).prev(".scroll-content")</code>, which says we&#8217;re going to animate the content directly above the active slider in the DOM.</p>
<h2>Scrollable content demo</h2>
<p>The demo has six scrollable content divs, all controlled by the JavaScript above:</p>
<p><b><a class="special" href="http://cnanney.com/journal/demo/div-slide/">View scrollable content demo</a></b></p>
<p>If you have a question or comment, please leave it below.</p>
]]></content:encoded>
			<wfw:commentRss>http://cnanney.com/journal/code/scrolling-content-with-jqueryui-slider/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Creating Apple&#8217;s New Slide Menu with jQuery</title>
		<link>http://cnanney.com/journal/code/creating-apples-new-slide-menu-with-jquery/</link>
		<comments>http://cnanney.com/journal/code/creating-apples-new-slide-menu-with-jquery/#comments</comments>
		<pubDate>Sun, 30 Jan 2011 07:03:22 +0000</pubDate>
		<dc:creator>Chris Nanney</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://cnanney.com/journal/?p=606</guid>
		<description><![CDATA[Apple's new slide menu looks great, but relies on CSS animations which most browsers don't support. Here's how to create a similar style menu with jQuery that works on every browser.]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t know how long it&#8217;s been there, but I noticed yesterday that Apple has a new product nav menu that replaced their old horizontal scroller with some new animated candy. I was impressed to see that all transitions and animations are CSS-based. Unfortunately, it will take some time before all major browsers even support this cool new CSS wizardry. Never fear&mdash;you can create a similar menu with jQuery that works in every browser, even IE6.</p>
<p><span id="more-606"></span>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/slide-menu/apple-slide2.png" alt="Apple's new slide-menu." />
<p class="img_caption">Apple&#8217;s new slide-menu.</p>
</div>
<h2>Guts of the menu</h2>
<p>At its heart, this isn&#8217;t a very complicated menu. You have a few hidden unordered lists that you scroll into view one item at a time, the animations have a slight easing to give the bouncy appearance, and the direction of the entrance and exit animations depend on the order you navigate through the menu (nice attention to detail).</p>
<h2>How I set it up</h2>
<p>The menu is made up of unordered lists inside the parent container:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;menu-container&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>The lists and list items are positioned absolutely so they pile up on top of one another, and when it&#8217;s time to animate I pull out the appropriate list&#8217;s items one at a time and position them with some simple math. Here&#8217;s what the framework looks like:</p>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/slide-menu/apple-slide-framework.gif" alt="Menu framework." />
<p class="img_caption">Menu framework.</p>
</div>
<p>The controls for the menu are simple as well:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;menu-controls&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">data-target</span>=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>List 1<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">data-target</span>=<span style="color: #ff0000;">&quot;1&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>List 2<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">data-target</span>=<span style="color: #ff0000;">&quot;2&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>List 3<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>The <code>data-target</code> attribute determines which list to animate when clicked. This target refers to the index of the list items. So target 0 refers to list 1, 1 to 2, etc. The script will add <code>class="active"</code> to the selected menu button&#8217;s &lt;a&gt; tag, so you can style accordingly.</p>
<p>Once the basics were down I firmed up the logic, added some <a href="http://gsgd.co.uk/sandbox/jquery/easing/">animation easing</a>, and made every piece of it customizable. The one thing I didn&#8217;t do was add the animated menu indicator (a triangle in Apple&#8217;s menu) that slowly animates to the active menu button. I consider that a flourish that goes along with the entire design of the Apple&#8217;s site. I left my demo on the simple side so the active button just gets bolded on mine.</p>
<h2><a name="demo">Demo time</a></h2>
<p>I created a demo page with a sample menu for four separate categories:</p>
<p><b><a class="special" href="/journal/demo/slide-menu/">Slide Menu Demo</a></b></p>
<p>The HTML is commented enough to explain all the options, and you can get the code <a href="http://bitbucket.org/cnanney/slide-menu/">here at bitbucket</a>.</p>
<h2>Update: 3/10/11</h2>
<ol>
<li>A <code>switchTo(index)</code> method has been added so you can easily manipulate the menu. It takes one parameter, the index of the &lt;ul&gt; you want to switch to. Note: The default controller click handlers won&#8217;t start a new animation until the previous one finishes, so frantic clicking on the menu controls will not mess anything up. There is no such restriction on the <code>switchTo</code> method, so use smartly.</li>
<li>By default, the menu will now wait for all images in the first list to load before animating in. There is also a configuration option <code>preloadAll</code> which will make it load <b>all</b> menu images before starting when set to <i>true</i>.</li>
<li>If you want to use a loading graphic, you can tell the menu where it is so it will hide it for you once all the images are loaded and ready to go.</li>
<li>Updated the easing method used in transitions so looks a little smoother.</li>
</ol>
<p>View demo source for more explanation.</p>
<p>Leave a comment if you have a question or something else to say.</p>
]]></content:encoded>
			<wfw:commentRss>http://cnanney.com/journal/code/creating-apples-new-slide-menu-with-jquery/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Apple-Style Counter Revisited</title>
		<link>http://cnanney.com/journal/code/apple-style-counter-revisited/</link>
		<comments>http://cnanney.com/journal/code/apple-style-counter-revisited/#comments</comments>
		<pubDate>Mon, 15 Nov 2010 07:14:25 +0000</pubDate>
		<dc:creator>Chris Nanney</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://cnanney.com/journal/?p=533</guid>
		<description><![CDATA[My original post detailing how I recreated Apple&#8217;s flip-style counter is a popular one, and I get many questions about how to properly implement it. It didn&#8217;t take long before I saw some shortcomings to the original technique I used, so I thought it was time to revisit my Apple-style counter and make some improvements. [...]]]></description>
			<content:encoded><![CDATA[<p>My <a href="http://cnanney.com/journal/code/apple-style-counter/">original post</a> detailing how I recreated Apple&#8217;s flip-style counter is a popular one, and I get many questions about how to properly implement it. It didn&#8217;t take long before I saw some shortcomings to the original technique I used, so I thought it was time to revisit my Apple-style counter and make some improvements.</p>
<p><span id="more-533"></span><b><a class="special" href="#demo">Skip to demo</a></b></p>
<h2>Linear sucks</h2>
<p>The biggest problem I had with the original counter was that it was restricted to counting in a linear fashion. The background graphic was a massively long image in which we would drop from frame to frame until it hit the bottom and then we&#8217;d start back at the top. You had to animate in numerical order (1 -> 2 -> 3 -> 4) or else the animation would jump around and look bad. All you could do was say what number you want to start at, and how fast you want to count. That&#8217;s it. I found that very limiting&mdash;it needed to be able to animate to and from any digit.</p>
<h2>Non-linear bliss</h2>
<p>In order to animate freely between digits, I needed to break each digit into separate top and bottom pieces, and animate each independently:</p>
<div class="post_img_big_noline"><img src="http://cnanney-files.s3.amazonaws.com/journal/apple-counter-revisited/zeros-top.png" alt="Top zeros" />
<p class="img_caption">Top zero states.</p>
</div>
<div class="post_img_big_noline"><img src="http://cnanney-files.s3.amazonaws.com/journal/apple-counter-revisited/zeros-bottom.png" alt="Bottom zeros" />
<p class="img_caption">Bottom zero states.</p>
</div>
<p>So now instead of one huge 35KB graphic, we have two smaller graphics totaling 23KB at the expense of an added HTTP request. I&#8217;m OK with that trade-off.</p>
<h2>More complicated animation</h2>
<p><img src="http://cnanney-files.s3.amazonaws.com/journal/apple-counter-revisited/digits-bottom-arrows.png" alt="Top animation" class="post_float_right" /><img src="http://cnanney-files.s3.amazonaws.com/journal/apple-counter-revisited/digits-top-arrows.png" alt="Top animation" class="post_float_left" />Naturally, having two separate pieces for each digit makes the background image animations more interesting. For example, lets see how the script animates from <b>0</b> to <b>3</b> (red), and then from <b>3</b> to <b>7</b> (blue).</p>
<p>The left graphic is the top half of the digit, and the animation sequence is fairly simple. The starting position for each digit is the first slot in each row. Once the top of the digit finishes, we animate the bottom half&mdash;which you can see in the graphic on the right.</p>
<p>The bottom animation jumps around a bit more, because I wanted the starting position for each bottom to also be in the first slot of each row. In slot 2 there is a shadow to indicate the top half of the digit is halfway through its fall, perpendicular to the screen and invisible. We then jump to the appropriate slot 3, which is the first you can see of the new digit falling into place, followed by the last two jumps to finish the animation.</p>
<p>So the three red jumps would happen first for the top, followed by the four red jumps for the bottom of the digit. Then it would start over for the blue jumps. It is only more complicated conceptually, but in practice only creates one extra background animation action.</p>
<p>The same effect could also be accomplished if all digits were in one long column like they were in my original script, and just shift it up and down rapidly into the correct position. Or you could just join the top and bottom graphics into one large sprite and handle the offsets accordingly in the animation. However, the logic controlling the background-position animations would be more complicated that way, so I broke it into two separate graphics for simplicity&#8217;s sake.</p>
<h2>Added functionality</h2>
<p>With my original script, there wasn&#8217;t much you could actually <i>do</i> with the counter. Its functionality was limited to a &#8220;set it and forget it&#8221; setup. There was no easy way to manipulate the counter once created. Lets start with that&#8230; creating a new counter:<br />
<a name="options"></a></p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> myCounter <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> flipCounter<span style="color: #009900;">&#40;</span>div<span style="color: #339933;">,</span> options<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<dl>
<dt>div</dt>
<dd>ID of the div that will hold the counter, entered <b>without</b> the &#8216;#&#8217;.</dd>
<dt>options</dt>
<dd>Object with the following properties:</p>
<ol>
<li><b>value [int]: </b>Initial value of the counter. <i>Default: 0</i></li>
<li><b>inc [int]: </b>Increment of the counter. <i>Default: 1</i></li>
<li><b>pace [int]: </b>Pace of the counting in milliseconds. <i>Default: 1000 (1 second)</i></li>
<li><b>auto [bool]: </b>Should the counter auto-increment? <i>Default: TRUE</i></li>
<li><b>tFH [int]: </b>Top frame height. <i>Default: 39</i></li>
<li><b>bFH [int]: </b>Bottom frame height. <i>Default: 64</i></li>
<li><b>fW [int]: </b>Frame width. <i>Default: 53</i></li>
<li><b>bOffset [int]: </b>Bottom sprite offset. As of v0.5.2 I combined the top and bottom digit sprites into one. The sprites didn&#8217;t change at all, I just stacked them to create one long sprite. The script expects the top half sprite to be right on top of the bottom one, and <i>bOffset</i> tells it how many pixels down before the bottom sprite starts. If you want to continue using the two separate sprites, just set this to zero. <i>Default: 390</i></li>
</ol>
</dd>
<dd>If you change any frame dimensions, be sure to update the CSS with correct width and heights.</dd>
</dl>
<div class="post_img_big_noline"><img src="http://cnanney-files.s3.amazonaws.com/journal/apple-counter-revisited/frame-dimensions.png" alt="Frame dimensions guide" />
<p class="img_caption">Frame dimensions guide.</p>
</div>
<p>Sample HTML:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;counter&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;flip-counter&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>That&#8217;s all you need for a counter. The ID can be whatever you&#8217;d like, but every counter needs the class &#8220;flip-counter&#8221;, because that is what the CSS uses to style the counters.</p>
<p>Sample JavaScript:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> myCounter <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> flipCounter<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;counter&quot;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span>inc<span style="color: #339933;">:</span> <span style="color: #CC0000;">23</span><span style="color: #339933;">,</span> pace<span style="color: #339933;">:</span> <span style="color: #CC0000;">500</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The above code creates a counter inside the div with the ID &#8220;counter&#8221;, starting from 0 (default), incrementing by 23, every 500ms, automatically (default). </p>
<h2><a name="methods">Methods</a></h2>
<p>Now that we have an easier way to set up the counter, there needed to be easy ways to manipulate it, so I created the following methods:</p>
<dl>
<dt>setValue(val)</dt>
<dd>Sets the value of the counter and animates the digits to new value. You can change the value of the counter we just created like so: <code>myCounter.setValue(12345);</code></dd>
<dd><b>Parameters</b><br /><b>val [int]:</b> New value for counter.</dd>
<dt>setIncrement(inc)</dt>
<dd>Sets the increment of the counter without animating any digits. Example: <code>myCounter.setIncrement(123);</code></dd>
<dd><b>Parameters</b><br /><b>inc [int]:</b> New increment value.</dd>
<dt>setPace(num)</dt>
<dd>Sets the pace of the counter. Only visibly affects counters with auto-increment set to <i>true</i>. Example: <code>myCounter.setPace(800);</code></dd>
<dd><b>Parameters</b><br /><b>pace [int]:</b> New pace value in milliseconds.</dd>
<dt>setAuto(auto)</dt>
<dd>Sets counter to auto-incrememnt (true) or not (false). Example: <code>myCounter.setAuto(false);</code></dd>
<dd><b>Parameters</b><br /><b>auto [bool]:</b> True or false.</dd>
<dt>step()</dt>
<dd>Manually step through increments when auto-increment is off. Example: <code>myCounter.step();</code></dd>
<dt>add(num)</dt>
<dd>Adds a number to the counter value, not affecting the &#8216;inc&#8217; or &#8216;pace&#8217; of the counter. Example: <code>myCounter.add(456);</code></dd>
<dd><b>Parameters</b><br /><b>num [int]:</b> Number to add to counter.</dd>
<dt>subtract(num)</dt>
<dd>Subtracts a number from the counter value, not affecting the &#8216;inc&#8217; or &#8216;pace&#8217; of the counter. Note: The counter does not handle negative numbers. Any subtraction operation that results in a negative number will return zero. Example: <code>myCounter.subtract(456);</code></dd>
<dd><b>Parameters</b><br /><b>num [int]:</b> Number to subtract from counter.</dd>
<dt>getValue() <i>*new*</i></dt>
<dd>Returns the current value of the counter. Example: <code>var value = myCounter.getValue();</code></dd>
<dd>This method is <b>not chainable.</b></dd>
<dt>stop() <i>*new*</i></dt>
<dd>Stops the counter if it is in the process of incrementing to a value using either <code>incrementTo</code> or <code>smartIncrementTo</code>, which are explained below. Example: <code>myCounter.stop();</code></dd>
<dt><a name="method_incrementTo">incrementTo(num, time, pace) <i>*new*</i></a></dt>
<dd>Increments to a given number either by using the currently set <i>pace</i> and <i>inc</i> values, or by using a &#8220;smart&#8221; increment technique that determines optimal values for you.</dd>
<dd>To use the simple technique, all you need to supply is the target number: <code>myCounter.incrementTo(12345);</code> This will increment to 12,345 using the current <i>pace</i> and <i>inc</i> values.</dd>
<dd>To use the smart method, supply the time in seconds you want the increment process to last, and a desired pace: <code>myCounter.incrementTo(12345, 10, 400);</code> This will increment to 12,345 as well, but the increment process will take 10 seconds to complete. The counter will determine the optimal values to use. In the example I&#8217;ve set a desired pace of 400, which the counter will try and stay as close to as possible when finding the optimal values.</dd>
<dd>This method is <b>not chainable.</b></dd>
<dd><b>Parameters</b><br /><b>num [int]:</b> Number to increment to.<br />
<b>time [int] <i>optional</i>:</b> Duration, <b>in seconds</b>, the increment process should take. When set, the counter will use a smart increment technique to optimize the animation.<br />
<b>pace [int] <i>optional</i>:</b> Desired pace for animation when using the smart increment option. This number may increase as needed for optimal timing.
</dd>
</dl>
<h2>Chaining</h2>
<p>Most methods are chainable, unless specifically mentioned above, so the following example works fine:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">myCounter.<span style="color: #660066;">setIncrement</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">55</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">setPace</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">750</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">setAuto</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><a name="demo"></a></p>
<h2>Demo</h2>
<p>I&#8217;ve created a demo page with the help of jQueryUI that lets you manipulate the counter using all of the built-in methods. Go play with it:</p>
<p><b><a class="special" href="/journal/demo/apple-counter-revisited/">New Apple-Style Flip Counter Demo</a></b></p>
<h2>Get the code</h2>
<p>You can get everything you need <a href="http://bitbucket.org/cnanney/apple-style-flip-counter/">here at Bitbucket</a>, where you will always be able to find the latest version of the script. If you use the script for something cool, I&#8217;d love to hear about it.</p>
<h3>Update: 11/27/10</h3>
<ul>
<li>Added 4 new methods: getValue, stop, incrementTo (thanks <a href="http://www.lijit.com">nerdynick</a>), smartIncrementTo.</li>
<li>Updated <a href="/journal/demo/apple-counter-revisited/">demo page</a> for incrementTo and smartIncrementTo.</li>
<li>Other various bugfixes.</li>
</ul>
<h3>Update: 12/5/10</h3>
<ul>
<li>Combined the incrementTo and smartIncrementTo methods for simplicity&#8217;s sake.</li>
<li><a href="#method_incrementTo">Updated the methods documentation to reflect changes.</a></li>
</ul>
<h3>Update: 2/7/11</h3>
<p>Updated to work with jQuery 1.5, older versions <b>will not</b> work with v1.5. Animation technique changed.</p>
<h3>Update: 4/13/11 &#8211; v0.5</h3>
<p>I finally added a version number to keep track of changes. Major changes:</p>
<ul>
<li>Removed jQuery dependency, the counter runs on plain JavaScript now. I&#8217;m still using jQuery and jQueryUI for the demo controls, but it is no longer required for the counter itself.</li>
<li>Added frame dimensions to <a href="#options">configuration options</a>, which will make it easier to use custom graphics (not sure why I didn&#8217;t have it this way before).</li>
</ul>
<h3>Update: 4/19/11 &#8211; v0.5.2</h3>
<ul>
<li>Combined top and bottom sprites into one long sprite.</li>
<li>Added <code>bOffset</code> parameter, explained in the <a href="#options">configuration options</a>.</li>
</ul>
<h3>Update: 5/7/11 &#8211; v0.5.3</h3>
<ul>
<li>Changed default counter ID to &#8220;flip-counter&#8221;.</li>
<li>All counters now need a class of &#8220;flip-counter&#8221;. This is what the CSS uses for styling, so having multiple counters doesn&#8217;t require adding each new ID to the CSS.</li>
<li><code>idPre</code> parameter removed because was pointless. Each counter needs a unique ID to begin with, so that can be used as the prefix for the digits.</li>
<li>Comma now added to digits sprite, so counter only uses one image.</li>
</ul>
<p>Code is up to date on <a href="http://bitbucket.org/cnanney/apple-style-flip-counter/">Bitbucket</a> and <a href="/journal/demo/apple-counter-revisited/">demo page</a>.</p>
<p>Please note, I <b>do not have</b> a good source template for the digits. All I did was cut and manipulate the original source graphic from Apple. If you want to change digit colors or transparency, you have to create new sprites from scratch. If you do, and would like to include it as a template here for others to use, please email me.</p>
<h2>CSS Experiment</h2>
<p>Here&#8217;s a <a href="http://cnanney.com/journal/code/css-flip-counter-experiment/">peek at my progress</a> with removing images from the counter entirely.</p>
<p>&mdash;</p>
<p>If you have any questions, comments or suggestions; please comment or <a href="http://cnanney.com/me/">email</a> me.</p>
]]></content:encoded>
			<wfw:commentRss>http://cnanney.com/journal/code/apple-style-counter-revisited/feed/</wfw:commentRss>
		<slash:comments>104</slash:comments>
		</item>
		<item>
		<title>Filtering Out the Noise with Regex</title>
		<link>http://cnanney.com/journal/code/filtering-out-the-noise-with-regex/</link>
		<comments>http://cnanney.com/journal/code/filtering-out-the-noise-with-regex/#comments</comments>
		<pubDate>Tue, 13 Jul 2010 05:48:32 +0000</pubDate>
		<dc:creator>Chris Nanney</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Regular Expressions]]></category>

		<guid isPermaLink="false">http://cnanney.com/journal/?p=423</guid>
		<description><![CDATA[I rely heavily on regular expressions when processing old data. Like my post about cleaning phone numbers, I&#8217;ll demonstrate another example of how useful regex can be when dealing with unruly data. The situation I&#8217;ve got hundreds of products that each have unique attributes, e.g. a laptop would have attributes such as: processor, memory, drives, [...]]]></description>
			<content:encoded><![CDATA[<p>I rely heavily on regular expressions when processing old data. Like my post about <a href="http://cnanney.com/journal/code/cleaning-phone-numbers-with-regex/">cleaning phone numbers</a>, I&#8217;ll demonstrate another example of how useful regex can be when dealing with unruly data.</p>
<p><span id="more-423"></span></p>
<h2>The situation</h2>
<p>I&#8217;ve got hundreds of products that each have unique attributes, e.g. a laptop would have attributes such as: processor, memory, drives, ports, etc. In the new database schema, the attributes are normalized so that they can be used to sort and filter the products. You&#8217;re ready to start importing the data but there&#8217;s one big problem&mdash;in the old database, attributes are stored as HTML in one big text field.</p>
<p>After some obligatory cursing, you take a close look at what you have to work with:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;span</span> <span style="color: #000066;">style</span>=<span style="color: #ff0000;">&quot;FONT-SIZE: 8.5pt; FONT-FAMILY: Arial; mso-fareast-font-family: Times New Roman; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Processor:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/span<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;span</span> <span style="color: #000066;">style</span>=<span style="color: #ff0000;">&quot;FONT-SIZE: 8.5pt; FONT-FAMILY: Arial; mso-fareast-font-family: Times New Roman; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span> 2.4Ghz Pentium IV,<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> Memory:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 256MB DDR SDRAM Expandable to 1GB, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Display:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 15&quot; TFT Active Matrix, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Video:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> ATI Mobility Radeon, 16MB VRAM, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Sound:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 16Bit Sound Blaster Pro, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Battery:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> Rechargeable Li-ION 2 Hrs Run, 3 Hrs Charge,<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> Drives:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 3.5&quot; Diskette, 40GB Hard Disk, 8X DVD, 24X CDRW, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Ports:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> PS/2 (1), External VGA (1), S-Video, USB (2), 10/100 LAN, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;font<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/font<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Size:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 12.96&quot; X 10.72&quot; x 1.73&quot; (WxDxH), <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Weight:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>7.69lbs, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Security:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> Kensington<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/span<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Not pretty. It&#8217;s got HTML tags strewn about with an assortment of Microsoft &#8220;mso-&#8221; garbage. We need to take this and turn it into nice <code>key => value</code> associations, like &#8220;Processsor&#8221; => &#8220;2.4Ghz Pentium IV&#8221;. You can just tough it out and do some hardcore copy and paste, which would be the easiest option if you only had a few items to go through. But that isn&#8217;t practical when dealing with hundreds, plus it is more fun to try and solve the problem with regular expressions.</p>
<h2>Plan of attack</h2>
<p>In order to use regex to strip out the attributes and their values, you first need to look for patterns in the data. Notice how each attribute is enclosed in <code>&lt;strong&gt;</code> tags? Using that pattern, we can write some pseudo-regex that will help us later on:</p>
<p><b>Attributes:</b> Always preceded by <code>&lt;strong&gt;</code> and followed by <code>&lt;/strong&gt;</code>.<br />
<b>Values:</b> Always preceded by <code>&lt;/strong&gt;</code> and followed by <code>&lt;strong&gt;</code> <b>or</b> the end of the data.<br />
<a name="step1"></a></p>
<h2>Step 1: Filter</h2>
<p>Since all we need to get our data are the <code>&lt;strong&gt;</code> tags, the first step is to get rid of all other tags:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$fix</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/&lt;(?!strong|\/strong)([^&gt;]*)&gt;/i'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">,</span> <span style="color: #000088;">$original</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>This regular expression says to look for the character <code>&lt;</code>, and then any text that is not &#8220;strong&#8221; or &#8220;/strong&#8221; until it finds <code>&gt;</code>, and replace it all with <code>''</code> (deleting it). <a href="http://cnanney.com/journal/demo/regex-noise/step1.php">Explain regex in detail</a>.</p>
<p>This gets rid of all opening and closing tags that aren&#8217;t <code>&lt;strong&gt;</code> or <code>&lt;/strong&gt;</code>, and saves that new string to the variable <code>$fix</code>. Our data already looks a lot cleaner:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Processor:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 2.4Ghz Pentium IV,<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> Memory:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 256MB DDR SDRAM Expandable to 1GB, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Display:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 15&quot; TFT Active Matrix, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Video:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> ATI Mobility Radeon, 16MB VRAM, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Sound:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 16Bit Sound Blaster Pro, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Battery:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> Rechargeable Li-ION 2 Hrs Run, 3 Hrs Charge,<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> Drives:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 3.5&quot; Diskette, 40GB Hard Disk, 8X DVD, 24X CDRW, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Ports:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> PS/2 (1), External VGA (1), S-Video, USB (2), 10/100 LAN, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Size:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> 12.96&quot; X 10.72&quot; x 1.73&quot; (WxDxH), <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Weight:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>7.69lbs, <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Security:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/strong<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> Kensington</pre></div></div>

<p><a name="step2"></a></p>
<h2>Step 2: Extract</h2>
<p>Now we can extract the individual attribute names and their values. First we&#8217;ll get the attributes:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">preg_match_all</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/&lt;strong&gt;([^&lt;]*)&lt;\/strong&gt;/i'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$fix</span><span style="color: #339933;">,</span> <span style="color: #000088;">$attributes</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Here we look for the string <code>&lt;strong&gt;</code> and then capture everything that isn&#8217;t a <code>&lt;</code>, until we match the string <code>&lt;/strong&gt;</code>. This repeats until the end of the data and sends all matches to an array called <code>$attributes</code>. <a href="http://cnanney.com/journal/demo/regex-noise/step2a.php">Explain regex in detail</a>.</p>
<p>Now we&#8217;ll pull out the attribute values:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">preg_match_all</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/&lt;\/strong&gt;([^&lt;]*)(?:&lt;[^&gt;]*&gt;|$)/i'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$fix</span><span style="color: #339933;">,</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>This looks for a <code>&lt;/strong&gt;</code> tag and captures anything that is not a <code>&lt;</code>, until we match <b>any</b> tag or the end of the string. This repeats until the end of the data and sends all matches to an array called <code>$values</code>. <a href="http://cnanney.com/journal/demo/regex-noise/step2b.php">Explain regex in detail</a>.</p>
<p>We now have our attribute names and their values in seperate arrays, lets see what the array for attribute names looks like:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #009900;">&#40;</span>
    <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">Array</span>
        <span style="color: #009900;">&#40;</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span>Processor<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span> Memory<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span>Display<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">3</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span>Video<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span>Sound<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">5</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span>Battery<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">6</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span> Drives<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">7</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span>Ports<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">8</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span>Size<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">9</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span>Weight<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">10</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">&lt;</span>strong<span style="color: #339933;">&gt;</span>Security<span style="color: #339933;">:&lt;/</span>strong<span style="color: #339933;">&gt;</span> 
        <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">Array</span>
        <span style="color: #009900;">&#40;</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Processor<span style="color: #339933;">:</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span>  Memory<span style="color: #339933;">:</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Display<span style="color: #339933;">:</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">3</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Video<span style="color: #339933;">:</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Sound<span style="color: #339933;">:</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">5</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Battery<span style="color: #339933;">:</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">6</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span>  Drives<span style="color: #339933;">:</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">7</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Ports<span style="color: #339933;">:</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">8</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Size<span style="color: #339933;">:</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">9</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Weight<span style="color: #339933;">:</span>
            <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">10</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Security<span style="color: #339933;">:</span>
        <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#41;</span></pre></div></div>

<p>You can see that <code>preg_match_all</code> creates a multidimensional array, the first sub-array contains the original strings that matched the regular expression, and the second contains the data we told it to extract. So, <code>$attributes[1]</code> and <code>$values[1]</code> has all the information we want.<br />
<a name="step3"></a></p>
<h2>Step 3: Clean</h2>
<p>Or data is riddled with commas, colons and spaces at their beginning and ends, so lets clean them up:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/(^[,:\s]*|[,:\s]*$)/'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">,</span> <span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><a href="http://cnanney.com/journal/demo/regex-noise/step3.php">Explain regex in detail</a>.</p>
<p>Here&#8217;s an example of how to loop through each array, clean the data, and combine it all:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">&lt;</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attributes</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$clean_att</span> <span style="color: #339933;">=</span> clean_me<span style="color: #009900;">&#40;</span><span style="color: #000088;">$attributes</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$clean_val</span> <span style="color: #339933;">=</span> clean_me<span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$all_done</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$clean_att</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$clean_val</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> clean_me<span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/(^[,:\s]*|[,:\s]*$)/'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">,</span> <span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>		
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>We now have the array <code>$all_done</code> that contains all our extracted attributes and their values:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">Array
(
    [Processor] =&gt; 2.4Ghz Pentium IV
    [Memory] =&gt; 256MB DDR SDRAM Expandable to 1GB
    [Display] =&gt; 15&quot; TFT Active Matrix
    [Video] =&gt; ATI Mobility Radeon, 16MB VRAM
    [Sound] =&gt; 16Bit Sound Blaster Pro
    [Battery] =&gt; Rechargeable Li-ION 2 Hrs Run, 3 Hrs Charge
    [Drives] =&gt; 3.5&quot; Diskette, 40GB Hard Disk, 8X DVD, 24X CDRW
    [Ports] =&gt; PS/2 (1), External VGA (1), S-Video, USB (2), 10/100 LAN
    [Size] =&gt; 12.96&quot; X 10.72&quot; x 1.73&quot; (WxDxH)
    [Weight] =&gt; 7.69lbs
    [Security] =&gt; Kensington
)</pre></div></div>

<p>Using a few regular expressions, we&#8217;ve taken some sloppy HTML and extracted all the data we needed for our new database. Regex is one powerful tool to have in your arsenal.</p>
<p>&mdash;</p>
<p>If you have any questions, comments or suggestions; please comment or <a href="http://cnanney.com/me/">email</a> me.</p>
]]></content:encoded>
			<wfw:commentRss>http://cnanney.com/journal/code/filtering-out-the-noise-with-regex/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>YouTube Event Logging</title>
		<link>http://cnanney.com/journal/code/youtube-event-logging/</link>
		<comments>http://cnanney.com/journal/code/youtube-event-logging/#comments</comments>
		<pubDate>Sun, 25 Apr 2010 23:20:30 +0000</pubDate>
		<dc:creator>Chris Nanney</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Utilities]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://cnanney.com/journal/?p=385</guid>
		<description><![CDATA[Using YouTube's Javascript API, log a user's interactions with your embedded YouTube videos.]]></description>
			<content:encoded><![CDATA[<p>A few months ago, a project bid had me looking at YouTube&#8217;s <a href="http://code.google.com/apis/youtube/js_api_reference.html">JavaScript API</a> for ways to manage a video library through a custom interface. Most of the videos were over 30 minutes, and I thought it would be great if I could provide some analytics on how users were interacting with the videos. Were people getting bored and leaving at a certain spot, rewinding interesting parts, or maybe randomly scrubbing through it?</p>
<p><span id="more-385"></span>By monitoring the player&#8217;s state changes, I made some headway with logging user actions. There were still some major problems, which I&#8217;ll go over in a bit, and after the bid fell through I stopped working on it. After revisiting it this week, I can now reliably log the following:</p>
<ul class="short">
<li>Where a user starts watching</li>
<li>Pause and resume times</li>
<li>Start and end times when scrubbing</li>
<li>When a user changes the video quality</li>
<li>When it needs to pause for buffering</li>
<li>If it plays through to the end</li>
<li>Where in the video does someone leave the page</li>
</ul>
<h2>Demo</h2>
<p><b><a class="special" href="/journal/demo/youtube-logging/">YouTube Event Logging Demo</a></b></p>
<p>Interact with the video and watch the log on the right.</p>
<h2>Applications</h2>
<p>I had <a href="http://getclicky.com/125897">Clicky</a> in mind when I started working on this. It already provided detailed information on each visitor action and manual logging for in-page events, so being able to see what people were doing within the video would be voyeuristic delight.</p>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/youtube-logging/youtube_spy.png" alt="YouTube Event Logging" /> </p>
<p class="img_caption">Event logging in Clicky</p>
</div>
<h2>Method</h2>
<p>The key to everything is the <code>onStateChange</code> event, which alerts you to every state change in the player. Possible values are unstarted (-1), ended (0), playing (1), paused (2), buffering (3), and video cued (5). Combined with <code>player.getCurrentTime()</code>, you can figure out what a user is doing, and when they are doing it. Keeping track of what the previous event was lets you determine whether a state of <code>1</code> is the player starting, resuming, or scrubbing.</p>
<h2>Problem</h2>
<p>This was all well and good in theory, but getting the exact time of the actions proved to be very difficult at first. For example, when I scrub a video to some future point in the timeline, the state changes from 1-2-3-1: playing, pause, buffer, play. Capturing the start time of the scrub is simple, but even though the last state will be &#8216;playing&#8217;, the video will not actually play until the browser has downloaded enough to resume the stream. So a state of <code>1</code> ends up meaning &#8216;trying to play&#8217; and not necessarily &#8216;playing&#8217;. Depending on network speeds and video quality, the player might sit on a state of <code>1</code> anywhere from 1 &#8211; 20 seconds before the video really is playing, and the video has to start playing again in order to capture the end scrub time.</p>
<p>I first tried to fix this problem with timers&#8230; Wait 5 seconds after last &#8216;play&#8217; state to grab the time, subtract 2.5, and IF the video was in fact playing by then, I&#8217;d have a time to use that was accurate +/- 2.5 seconds. Yeah, that didn&#8217;t work very well. Higher quality streams and unpredictable network conditions made a timer-based solution terribly undependable.</p>
<h2>Solution</h2>
<p>The only way to reliably capture action timing was to monitor the video quality of the stream, and how much was loaded, via <code>player.getPlaybackQuality()</code> and <code>player.getVideoBytesLoaded()</code>. Playback quality will return either Small, Medium, Large, HD720, or HD1080. Based on quality, I determine when a video is playing based on rules of how much should be loaded. For example: If the stream is &#8216;Large&#8217;, video will play after 300KB is loaded, if &#8216;HD720&#8242;, 800KB. If you seek to a position in the timeline that has already loaded, there is no problem &#8211; video plays immediately. If seeking to a position that had not loaded yet, then &#8216;bytes loaded&#8217; resets and starts loading video at the new position, and once it crosses the threshold, it SHOULD be playing and I capture the time.</p>
<h2>Caveats</h2>
<p>I said SHOULD because it isn&#8217;t always perfect. For one thing, all streams are not created equal. One &#8216;Medium&#8217; video might start playing after 100KB loaded, another might be 300KB. I&#8217;ve done some testing on each quality level, and the limits I&#8217;ve set are on the conservative side. It might start playing at 100KB, but the script will be waiting for 300KB, so the time will be off by a few seconds.</p>
<p>The opposite holds true as well. The video might not start playing at 300KB, but rather 400KB, and misfire the <code>player.getCurrentTime()</code> call. In that instance the start and end times of the scrub will be the same. The conservative limits I&#8217;ve set should prevent this from happening, but you never know. The function that controls this is <code>setByteMeter()</code>, so tweak it if you wish.</p>
<p>This would have been a lot easier if returning a state of &#8216;playing&#8217; really meant that, and not that it was thinking about it.</p>
<h2>Introspection</h2>
<p>Once again I&#8217;ve solved a problem that no longer exists, as I have no practical use for this right now. If anyone has ideas for improving it, please let me know in the comments or via <a href="/me/">email</a>.</p>
<h2>Update</h2>
<p>Clicky ended up using this code as a base for the YouTube portion of their <a href="http://getclicky.com/user/#/blog/224/video-analytics">video analytics service</a>. I&#8217;m happy it was put to real use, not just sitting here as another time-waster idea.</p>
]]></content:encoded>
			<wfw:commentRss>http://cnanney.com/journal/code/youtube-event-logging/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Clicky Monitor, AKA ClickyChrome</title>
		<link>http://cnanney.com/journal/utilities/clickychrome/</link>
		<comments>http://cnanney.com/journal/utilities/clickychrome/#comments</comments>
		<pubDate>Mon, 15 Mar 2010 00:48:51 +0000</pubDate>
		<dc:creator>Chris Nanney</dc:creator>
				<category><![CDATA[Utilities]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://cnanney.com/journal/?p=329</guid>
		<description><![CDATA[Clicky Monitor - A Chrome Extension for Clicky Web Analytics. Formerly known as ClickyChrome.]]></description>
			<content:encoded><![CDATA[<h2>A Chrome Extension for Clicky Web Analytics</h2>
<p><a href="http://getclicky.com/125897">Clicky</a> is an amazing web analytics service. Its killer feature is the ability see data in real-time, allowing you to watch your visitors as they browse your site.</p>
<p>I love Clicky, and I love their API. Because the analytics data is available immediately, I found myself wishing I could have a constant notification of how many visitors were on my site without having to leave a tab or window open all the time.</p>
<p>I also love Google Chrome. As soon as LastPass made an extension for it, Chrome became my default browser. After reading a little about Chrome extensions and how they were just HTML and JavaScript, I knew what my next project would be&#8230; ClickyChrome.</p>
<p><b>Update:</b> A year after releasing ClickyChrome, I&#8217;m changing the name to Clicky Monitor to comply with Google&#8217;s new branding guidelines.</p>
<p><span id="more-329"></span></p>
<h2>Version 2.0.3</h2>
<p>Released: 3/19/2011</p>
<p><b><a class="special" href="https://chrome.google.com/extensions/detail/nhdlcoplfdhmdbeleincmcnmgdajohig">Download Clicky Monitor v2.0.3</a></b></p>
<h2>Changelog</h2>
<p><b>v2.0.3 &#8211; 3/19/2011</b></p>
<ul>
<li>Changed name to Clicky Monitor to make Google happy. I liked the alliteration :(</li>
</ul>
<p><b>v2.0.2 &#8211; 3/8/2011</b></p>
<ul>
<li>Fixed bug where desktop notification links would open inside of notification itself instead of new tab.</li>
</ul>
<p><b>v2.0.1 &#8211; 12/11/2010</b></p>
<ul>
<li>Fix for <a href="http://crbug.com/61370">http://crbug.com/61370</a>.</li>
</ul>
<p><b>v2.0 &#8211; 9/8/2010</b></p>
<ul>
<li>Completely re-written, will be easier to add new features in the future.</li>
<li><a href="#notifications">Added desktop goal notifications.</a></li>
<li><a href="#context">Added context menu integration.</a></li>
<li>Badge text can now display either number of visitors online, visitors today, or goals completed.</li>
<li>Custom visitor names (if defined) appear in visitor list instead of IP.</li>
<li>Visitors who have completed goals are flagged as such in the visitors list.</li>
<li>Sites can now be reordered in the options page, updates site dropdown menu.</li>
<li>Added ability to import all your sites from Clicky automatically.</li>
</ul>
<p><b>v1.3.6 &#8211; 7/13/2010</b></p>
<ul>
<li>Minor update to reflect a change in Clicky&#8217;s API.</li>
</ul>
<p><b>v1.3.5 &#8211; 6/8/2010</b></p>
<ul>
<li>Added pie chart of top browsers over past 30 days.</li>
</ul>
<p><b>v1.3 &#8211; 6/6/2010</b></p>
<ul>
<li>Added Charts tab to display visitors and actions over past 30 days.</li>
</ul>
<p><b>v1.2.1 &#8211; 5/26/2010</b></p>
<ul>
<li>Removed Google Analytics from extension because it was causing crashes for Mac users. See bug <a href="http://crbug.com/43400">43400</a> and <a href="http://crbug.com/44941">44941</a>.</li>
</ul>
<p><b>v1.2 &#8211; 4/16/2010</b></p>
<ul>
<li>Added Visitors tab to display today&#8217;s last 5 visitors.</li>
</ul>
<p><b>v1.1.5 &#8211; 4/1/2010</b></p>
<ul>
<li>On options page, made badge color graphics field labels so clicking on image selects that option.</li>
<li>Added Google Analytics tracking for the extension. This will give me a better idea of how people are using ClickyChrome and will help guide any future development. It doesn&#8217;t log any information about you or the sites you are using with the extension. <a href="#ga">Read more below</a>.</li>
</ul>
<p><b>v1.1.3 &#8211; 3/18/2010</b></p>
<ul>
<li>Restored accidentally-removed validation for Name field.</li>
<li>Fixed potential problems with editing data for the currently active site.</li>
<li>Added links back to Clicky for visitors and actions.</li>
</ul>
<p><b>v1.1 &#8211; 3/17/2010</b></p>
<ul>
<li>Visitors Online counter adjusts refresh rate according to browser&#8217;s idle time to give Clicky&#8217;s API a little relief.</li>
<li>Better form validation to prevent ID and Key entry errors.</li>
<li>Five badge color options.</li>
<li>Added data wipe option if you are having problems and would like to just start fresh.</li>
</ul>
<p><b>v1.0 &#8211; 3/14/2010</b></p>
<ul>
<li>Initial release.</li>
</ul>
<h2>Features</h2>
<dl>
<dt>Easily add all of your Clicky sites</dt>
<dd>You can import all your sites automatically from Clicky, or add them manually if you prefer. Select which one you&#8217;d like to actively monitor from the site dropdown menu in the ClickyChrome popup.</dd>
<dt>Chose a metric you want to monitor</dt>
<dd>The ClickyChrome toolbar icon will display either the number of visitors currently online, total number of visitors today, or total number of completed goals today. The data is refreshed every minute so you&#8217;ll always be up to speed.</dd>
<dt>Quickly browse through stats</dt>
<dd>From within the ClickyChrome popup, you can view basic site stats for various date ranges, see comprehensive information about your site&#8217;s last 5 visitors, and display graphs for visitors, actions and top browsers over the past 30 days.</dd>
<dt><a name="notifications">Be notified on your desktop when a visitor completes a goal</a></dt>
<dd>Using HTML5 desktop notifications, you can chose to be alerted whenever a visitor completes a goal on the site you&#8217;re currently monitoring. You&#8217;ll be notified via a <a href="#notification-image">popup</a> in the corner of your screen with the following information: Which goals the visitor completed, the total value of the completed goals, their geolocation as well as IP or custom username you have assigned, and the start time of their visit.</dd>
<dt><a name="context">One click access to stats from any page of your site</a></dt>
<dd>If you provide domains for your sites, ClickyChrome will add an item to your context menu (right-click) while you are viewing any page within those domains. If you are browsing your site and would like to see the stats for that particular page, just right-click and select &#8220;View page stats&#8221;, and that will take you to the Clicky stats page for the URL you are currently viewing.</dd>
<dt>All your data is local</dt>
<dd>Your site information is stored locally in your Chrome browser and is used to make API requests to Clicky. If you uninstall the extension, that data is deleted. At no time is your data sent anywhere else.</dd>
</dl>
<h2>Screenshots</h2>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/clickychrome/cc_toolbar.png" alt="ClickyChrome on the toolbar" />
<p class="img_caption">ClickyChrome on the toolbar with online notification</p>
</div>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/clickychrome/cc_basics.png" alt="ClickyChrome popup" />
<p class="img_caption">Basic information</p>
</div>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/clickychrome/cc_visitors.png" alt="ClickyChrome on the toolbar" />
<p class="img_caption">Last 5 visitors</p>
</div>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/clickychrome/cc_charts.png" alt="Charts tab" />
<p class="img_caption">Visitors over last 30 days</p>
</div>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/clickychrome/cc_pie_chart.png" alt="Top browsers" />
<p class="img_caption">Top browsers over last 30 days</p>
</div>
<div class="post_img_big"><a name="notification-image"><img src="http://cnanney-files.s3.amazonaws.com/journal/clickychrome/cc_notification.png" alt="Goal notification" /></a>
<p class="img_caption">Desktop goal notification</p>
</div>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/clickychrome/cc_context.png" alt="Context menu" />
<p class="img_caption">One-click access to your analytics</p>
</div>
<h2>Questions</h2>
<dl>
<dt>Why can I see visitors online via Spy, but they aren&#8217;t appearing on ClickyChrome?</dt>
<dd>Spy data is not currently available via the API, and the &#8216;visitors-online&#8217; field that ClickyChrome uses is delayed 1-2 minutes. This is why visitors you see in Spy won&#8217;t be immediately visible on ClickyChrome.</dd>
<dt>Why does it warn me about browsing history and private data when installing ClickyChrome?</dt>
<dd>ClickyChrome has access to Chrome&#8217;s tabs because it needs to open a new tab for the options page on first run and any time you want to edit your sites&mdash;and for this reason you get a warning about browsing history because that would enable the extension to see the names of your open tabs. The warning about private data is telling you that ClickyChrome will be interacting with api.getclicky.com, which is kind of obvious, but sounds scary in the warning.</dd>
<dt><a name="ga">What kind of data are you gathering with Google Analytics (GA)?</a></dt>
<dd><b>Analytics are disabled as of v1.2.1.</b></dd>
<dd>Think of the extension like a mini two-page website, one page is the background process that updates your online count, and the second is the pop-up. With GA, I can see how many people are using ClickyChrome, and how they are using it. For example, these are the event categories that I keep track of:<br />
<b>External Link:</b> How often do people go to Clicky via the extension?<br />
<b>Site Select:</b> How many times do people change the site they are monitoring?<br />
<b>Date Select:</b> Do people change the date range often, and if so what is the most popular range?<br />
<b>Options:</b> How many times do people open the options page?<br />
<b>Tabs:</b> How often do people switch between the Basics and Visitors tab?</dd>
<dd>Keep in mind, all I see are number totals&mdash;I do not ever see the names of your sites. Besides satisfying my own curiosity, the GA reports are proving invaluable when it comes to troubleshooting. For example, I can see that the most popular version of Chrome using my extension is Mac 5.0.342.7 Beta, and when someone with a Mac emails me to say it isn&#8217;t working right, I know that it works fine on a Mac, and that it is probably because they are using the latest Dev release that might be unstable. I don&#8217;t own a Mac to test on, so having this information is a big help.</dd>
<dt>Why isn&#8217;t it working for me?!</dt>
<dd>Email me and tell me your OS and version of Chrome you are running&mdash;we&#8217;ll figure it out.</dd>
</dl>
<h2>Help</h2>
<p>If you run into any problems or have questions/concerns, post a comment or <a href="/me/">email me</a>.</p>
<h2><a name="source">Source code</a></h2>
<p>View source code at <a href="http://bitbucket.org/cnanney/clickychrome/">http://bitbucket.org/cnanney/clickychrome/</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://cnanney.com/journal/utilities/clickychrome/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>Apple-Style Counter</title>
		<link>http://cnanney.com/journal/code/apple-style-counter/</link>
		<comments>http://cnanney.com/journal/code/apple-style-counter/#comments</comments>
		<pubDate>Sat, 13 Feb 2010 00:00:19 +0000</pubDate>
		<dc:creator>Chris Nanney</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://cnanney.com/journal/?p=255</guid>
		<description><![CDATA[When I saw the 10 billion song counter on Apple&#8217;s website yesterday, I immediately right-clicked on it to see if it was flash. No big surprise to see that it wasn&#8217;t, this being Apple, and when I saw it was done using JavaScript I knew how I&#8217;d be wasting the next few hours. Apple&#8217;s 10 [...]]]></description>
			<content:encoded><![CDATA[<p>When I saw the 10 billion song counter on Apple&#8217;s website yesterday, I immediately right-clicked on it to see if it was flash. No big surprise to see that it wasn&#8217;t, this being Apple, and when I saw it was done using JavaScript I knew how I&#8217;d be wasting the next few hours.</p>
<p><span id="more-255"></span>
<div class="post_img_big"><img src="http://cnanney-files.s3.amazonaws.com/journal/apple-counter/apple-counter.png" alt="Counter from apple.com" />
<p class="img_caption">Apple&#8217;s 10 billion song countdown.</p>
</div>
<p><b><a class="special" href="#update5">Update: November 15, 2010: New version available</a></b></p>
<p>My first instinct was to use Chrome&#8217;s developer tools to inspect the page and check out the JavaScript for the counter to get some clues as to how to go about re-creating it. After a few seconds of looking at Apple&#8217;s minified code, I knew I&#8217;d get no help there. After grabbing the digits and comma graphic they used, I set out to avoid the work I was supposed to be doing to create a counter from scratch using these two images and <a href="http://jquery.com/">jQuery</a>.</p>
<h2>Here it is</h2>
<p>I&#8217;ll give a brief overview of the steps taken to reproduce the counter, but for those that want to cut to the chase, here it is. The code is commented enough so that anyone interested can view the source and see what&#8217;s going on.</p>
<p><b><a class="special" href="/journal/demo/apple-counter/">View my Apple-style counter</a></b></p>
<p><b>Note:</b> This counter did not actually track the number of iTunes downloads, but is an example of <i>how</i> to create a similar counter for your own purposes.</p>
<p>Be sure to read all the way down for <b><a href="#update1">more demos</a></b>.</p>
<h2>Basics</h2>
<p><a href="http://cnanney-files.s3.amazonaws.com/journal/apple-counter/spacing.png">Looking at the image closely</a>, we can see that each frame is 103px in height, with five frames of animation between digits, leaving 618px of space between each digit. So, digit zero would have a background position of <code>'0 0'</code>, one would be <code>'0 -608px'</code>, two would be <code>'0 -1236px'</code>, etc. My plan was to use an unordered list to hold the digits and use jQuery to animate the background position of each list item.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;d9&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;seperator&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;d8&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;d7&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;d6&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;seperator&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;d5&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;d4&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;d3&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;seperator&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;d2&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;d1&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;d0&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>And the CSS:</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;"><span style="color: #00AA00;">*</span><span style="color: #00AA00;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span><span style="color: #cc66cc;">0</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">padding</span><span style="color: #00AA00;">:</span><span style="color: #cc66cc;">0</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span>
ul<span style="color: #00AA00;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">list-style-type</span><span style="color: #00AA00;">:</span><span style="color: #993333;">none</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span><span style="color: #933;">566px</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span><span style="color: #933;">50px</span> <span style="color: #993333;">auto</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span>
li<span style="color: #00AA00;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">float</span><span style="color: #00AA00;">:</span><span style="color: #000000; font-weight: bold;">left</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">background</span><span style="color: #00AA00;">:</span><span style="color: #993333;">url</span><span style="color: #00AA00;">&#40;</span><span style="color: #ff0000; font-style: italic;">filmstrip.png</span><span style="color: #00AA00;">&#41;</span> <span style="color: #cc66cc;">0</span> <span style="color: #cc66cc;">0</span> <span style="color: #993333;">no-repeat</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span><span style="color: #933;">53px</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">height</span><span style="color: #00AA00;">:</span><span style="color: #933;">103px</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span>
li.seperator<span style="color: #00AA00;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">background</span><span style="color: #00AA00;">:</span><span style="color: #993333;">url</span><span style="color: #00AA00;">&#40;</span><span style="color: #ff0000; font-style: italic;">comma.png</span><span style="color: #00AA00;">&#41;</span> <span style="color: #933;">2px</span> <span style="color: #933;">75px</span> <span style="color: #993333;">no-repeat</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span><span style="color: #933;">12px</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

<p>That&#8217;s it for HTML and CSS, the rest is JavaScript.</p>
<h2>Making it work</h2>
<p>It took no time to get a simple counter running, but the hairy part was triggering a five-frame animation for each digit that needed to change. Because I wanted to mimic the functionality of the counter on Apple&#8217;s site, it needed to look like it was counting at a very fast increment, with variable animation speeds depending on the digit.</p>
<p>After incrementing the value, the first step is to see which digits need to be animated:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> digitCheck<span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span>y<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> digitsOld <span style="color: #339933;">=</span> splitToArray<span style="color: #009900;">&#40;</span>x<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    digitsNew <span style="color: #339933;">=</span> splitToArray<span style="color: #009900;">&#40;</span>y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> c <span style="color: #339933;">=</span> digitsNew.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> c<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>digitsNew<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">!=</span> digitsOld<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            animateDigit<span style="color: #009900;">&#40;</span>i<span style="color: #339933;">,</span> digitsOld<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> digitsNew<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>This takes inputs <code>x</code> (pre-increment value) and <code>y</code> (post-increment value), and sends them to a helper function I wrote called <code>splitToArray</code>, which breaks each value into an array of individual digits. It then compares each digit, and if there is a change, passes the info on to <code>animateDigit</code>.</p>
<p>Inside <code>animateDigit</code>, the most difficult part was getting the animations for each digit cued up correctly. Inside the loop that controls the animation, I needed to slide the background position down five times with a specific delay, and my first solution was using <code>setTimeout</code>, and the statement:
</pre>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">setTimeout<span style="color: #009900;">&#40;</span>doAnimate<span style="color: #339933;">,</span> timeOut<span style="color: #339933;">,</span> n<span style="color: #339933;">,</span> pos<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>This worked great in Chrome and FF, and I thought I was done... until I checked it in IE. I had forgotten you can't pass parameters to functions with setTimeout in this way, so you need to use a closure:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">setTimeout<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>doAnimate<span style="color: #009900;">&#40;</span>n<span style="color: #339933;">,</span>pos<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> timeOut<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Simple enough, I thought, but that made the animation choke up in every browser. No good.</p>
<p>I slept on it, then this morning thought about using jQuery's new <a href="http://api.jquery.com/delay/">delay method</a> added in version 1.4. Boom! I was able to do away with the <code>doAnimate</code> function all together, and kill it all with one pass:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#d&quot;</span> <span style="color: #339933;">+</span> n<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">delay</span><span style="color: #009900;">&#40;</span>speed<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">animate</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">'background-position'</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'0 '</span> <span style="color: #339933;">+</span> pos <span style="color: #339933;">+</span> <span style="color: #3366CC;">'px'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>I now had cross-browser harmony, and had once again spent time away from paying projects to build something I have absolutely no use for :)</p>
<h2>Customizing</h2>
<p>When making this demo, I chose to use the same Apple graphics so when it was finished, I could look at the two side-by-side and see if I got the functionality correct. This post is just me sharing my learning process with you, so if in the future you ever have the need for a count down/up graphic, maybe this will help. The impression shouldn't be "how to rip-off Apple's look", but rather "how to have the same functionality in my own projects."</p>
<p>Customizing this to your own graphics is <b>very</b> easy. All you need is a consistent spacing between your animation frames, and be able to add. You can see a hastily-made custom example <a href="http://cnanney.com/journal/demo/apple-counter/custom.php">here</a>. In it, my frames are 50 x 80px and I too have 5 animation frames between digits. Most of the customization happens at the beginning of the JavaScript:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Array to hold each digit's starting background-position Y value</span>
<span style="color: #003366; font-weight: bold;">var</span> initialPos <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">480</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">960</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1440</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1920</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">2400</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">2880</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">3360</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">3840</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">4320</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #006600; font-style: italic;">// Amination frames</span>
<span style="color: #003366; font-weight: bold;">var</span> animationFrames <span style="color: #339933;">=</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">;</span>
<span style="color: #006600; font-style: italic;">// Frame shift</span>
<span style="color: #003366; font-weight: bold;">var</span> frameShift <span style="color: #339933;">=</span> <span style="color: #CC0000;">80</span><span style="color: #339933;">;</span></pre></div></div>

<p>The <code>initialPos</code> array holds the starting Y value of each digit, in increments of 480 (80px per frame x 6 frames per digit). <code>animationFrames</code> says there are 5 animation frames between digits, and <code>frameShift</code> is the frame height. Those are the only changes needed to make it function properly (besides updating the CSS), and further animation tweaking can be done in the function <code>animateDigit</code>.</p>
<p><a name="update1"></a></p>
<h2>Update 1</h2>
<p>Here is another example demonstrating how to <a href="/journal/demo/apple-counter/time.php">make a clock</a> using the same animation technique.</p>
<p><a name="update2"></a></p>
<h2>Update 2</h2>
<p>My original demo was based on counting to 10 billion, so had a strict number of digits. I realize that is not the most practical application, so I made a <a href="/journal/demo/apple-counter/dynamic.php?n=99800">dynamic counter example</a> where the JavaScript takes care of HTML for each digit, as well as commas when necessary. You can set whatever number you want via the URL query string (set n = number), or view the page <a href="/journal/demo/apple-counter/dynamic.php">by itself</a> to just generate a random number. View the source to see different ways of setting a start number for the counter to use.<br />
<a name="update3"></a></p>
<h2>Update 3</h2>
<p>Example with <a href="/journal/demo/apple-counter/pad.php?n=98999">zero-filled</a> numbers.</p>
<p><a name="update4"></a></p>
<h2>Update 4</h2>
<p>As per many requests, and the help of a visitor who made three new digit graphics, I have yet another example of this animation technique in action. This time it is not counting up, but rather down&mdash;to any date in the future, in 'days : hours : minutes : seconds' format. It handles all HTML and formatting itself, all you need to do is plug in a date.</p>
<p><b><a href="/journal/demo/apple-counter/countdown.php">View countdown demo</a></b></p>
<p><b>Warning: </b>Don't use the countdown script in a live site, because the jQuery animation technique used will not work properly in Chrome, <a href="http://code.google.com/p/chromium/issues/detail?id=80639">see bug here</a>.</p>
<p>It's set to countdown to Christmas of this year, but you can quickly test different dates by adding a date to the URL in this format: '?date=M/D/YY', e.g. '<a href="/journal/demo/apple-counter/countdown.php?date=6/1/11">?date=6/1/11</a>'. It uses the @font-face font kit BD Cartoon Shout from <a href="http://www.fontsquirrel.com" title="Pure awesomeness.">Font Squirrel</a>. As usual, code is commented if you're curious. Here is everything for the countdown in a <a href="http://cnanney-files.s3.amazonaws.com/journal/apple-counter/countdown.zip">zip file</a>.</p>
<p><a name="update5"></a></p>
<h2>Update: November 15, 2010</h2>
<p>I've rewritten entire script and added lots of new functionality:</p>
<p><b><a class="special" href="http://cnanney.com/journal/code/apple-style-counter-revisited/">View revisited counter</a></b></p>
<h2>Update: February 7, 2011</h2>
<p>This script will not work properly with jQuery 1.5, and will no longer be maintained. Think of this post as a first draft of me trying to get the animation working; the code is outdated. If you want to use this type of counter please use the newer version of the script, which will be maintained:</p>
<p><b><a class="special" href="http://cnanney.com/journal/code/apple-style-counter-revisited/">View revisited counter</a></b></p>
<p><b>Warning: </b>Don't use the countdown script in a live site, because the jQuery animation technique used will not work properly in Chrome, <a href="http://code.google.com/p/chromium/issues/detail?id=80639">see bug here</a>.</p>
<p>&mdash;</p>
<p>If you have any questions, comments or suggestions; please comment or <a href="http://cnanney.com/me/">email</a> me.</p>
]]></content:encoded>
			<wfw:commentRss>http://cnanney.com/journal/code/apple-style-counter/feed/</wfw:commentRss>
		<slash:comments>127</slash:comments>
		</item>
		<item>
		<title>IMDB Episode Scraper</title>
		<link>http://cnanney.com/journal/code/imdb-episode-scraper/</link>
		<comments>http://cnanney.com/journal/code/imdb-episode-scraper/#comments</comments>
		<pubDate>Mon, 19 Oct 2009 01:10:18 +0000</pubDate>
		<dc:creator>Chris Nanney</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Regular Expressions]]></category>

		<guid isPermaLink="false">http://cnanney.com/journal/?p=241</guid>
		<description><![CDATA[I like to keep my TV rips well-organized, and labeled with the correct episode title. I&#8217;ve been using the excellent Bulk Rename Utility to quickly rename with proper series title, season and episode numbers&#8212;but the individual episode titles were always a pain. Begrudgingly, I&#8217;d just copy-paste the titles from Wikipedia, always wanting a way to [...]]]></description>
			<content:encoded><![CDATA[<p>I like to keep my TV rips well-organized, and labeled with the correct episode title. I&#8217;ve been using the excellent <a href="http://www.bulkrenameutility.co.uk/Main_Intro.php">Bulk Rename Utility</a> to quickly rename with proper series title, season and episode numbers&mdash;but the individual episode titles were always a pain. Begrudgingly, I&#8217;d just copy-paste the titles from Wikipedia, always wanting a way to automate that process.</p>
<p><span id="more-241"></span>If you search for &#8220;TV episode renamer&#8221;, you&#8217;ll find many utilities that can take care of this in some shape or form, butI didn&#8217;t want to install anything, and I knew it would be more fun to write it myself. I wanted something that would scan the video files, determine the season and episode number of each file, retrieve the title from IMDB and rename accordingly.</p>
<p>After a few hours, I had a script running on my local server that took three inputs:</p>
<ol>
<li>Path to files on my PC</li>
<li>Desired series title for the files (i.e. &#8220;The Office&#8221;)</li>
<li>IMDB series code (i.e. tt0386676)</li>
</ol>
<p>And produced clean file names, such as &#8220;The Office &#8211; S02E04 &#8211; The Fire.avi&#8221;</p>
<p>This post has to do with the first part of the solution&mdash;retrieving episode info from IMDB. After looking at the source for their episode list pages, I saw the pattern to which they display each episode&#8217;s information, so it only required a few lines of PHP and Regex to strip out the stuff I wanted and create an array with all seasons and episode titles for a given series.</p>
<p><b><a class="special" href="http://cnanney.com/journal/demo/imdb-regex/">View demo</a></b></p>
<p><b><a class="special" href="http://cnanney.com/journal/demo/imdb-regex/imdb.phps">View source</a></b></p>
<p>Perhaps I&#8217;ll write another post dealing with the processing and renaming of the files locally. If you find this script useful, I&#8217;d like to hear about it!</p>
]]></content:encoded>
			<wfw:commentRss>http://cnanney.com/journal/code/imdb-episode-scraper/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

