<?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/"
	xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"
>

<channel>
	<title>Aral Balkan &#187; Development</title>
	<atom:link href="http://aralbalkan.com/category/development/feed" rel="self" type="application/rss+xml" />
	<link>http://aralbalkan.com</link>
	<description>Passionate geekisms.</description>
	<lastBuildDate>Wed, 01 Feb 2012 18:53:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
		<item>
		<title>Installing Octopress (and Ruby via RVM) on a Lion box that has Xcode 4.2</title>
		<link>http://aralbalkan.com/3963</link>
		<comments>http://aralbalkan.com/3963#comments</comments>
		<pubDate>Tue, 22 Nov 2011 15:03:40 +0000</pubDate>
		<dc:creator>Aral</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[1.9.3]]></category>
		<category><![CDATA[1.9.3-p0]]></category>
		<category><![CDATA[github pages]]></category>
		<category><![CDATA[guide]]></category>
		<category><![CDATA[install]]></category>
		<category><![CDATA[instructions]]></category>
		<category><![CDATA[jekyll]]></category>
		<category><![CDATA[lion]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[octopress]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[setup]]></category>

		<guid isPermaLink="false">http://aralbalkan.com/?p=3963</guid>
		<description><![CDATA[In my quest to move away from WordPress (and PHP/MySQL, which reminds me far too much of 1999 for my comfort), I'm evaluating several static site blog solutions to migrate this blog to and to use for a couple of other blogs that I want to set up for next year. As part of the [...]]]></description>
			<content:encoded><![CDATA[<p id="top" />In my quest to move away from WordPress (and PHP/MySQL, which reminds me far too much of 1999 for my comfort), I'm evaluating several static site blog solutions to migrate this blog to and to use for a couple of other blogs that I want to set up for next year. As part of the process, I wanted to give <a href="http://octopress.org/">Octopress</a> a shot. Octopress is a static site blogging solution built on <a href="https://github.com/mojombo/jekyll">mojombo/jekyll</a> – the solution that powers <a href="http://pages.github.com/">GitHub Pages</a>. The beauty of it is that you can simply deploy your blog to GitHub Pages, and even use a custom domain, simply by pushing to your repository (GitHub will pass your repository through Jekyll automatically–simples!) </p>
<p>The problem is that there are apparently <a href="http://stackoverflow.com/questions/8032824/cant-install-ruby-under-lion-with-rvm-gcc-issues">issues with installing the dependencies on a box running Lion with Xcode 4.2</a>. The following solution worked for me. I hacked it together from that StackOverflow thread as well as the <a href="http://octopress.org/docs/setup/">Octopress Setup Guide</a>:</p>
<p><span id="more-3963"></span></p>
<ol>
<li>Install RVM:
<pre>bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)</pre>
</li>
<li>Add RVM to your shell as a function:
<pre>echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile
source ~/.bash_profile</pre>
</li>
<li>Use RVM to install the latest Ruby:
<pre>rvm install 1.9.3 --with-gcc=clang</pre>
</li>
<li>…and use it:
<pre>rvm use 1.9.3</pre>
<p> (This also resulted in the latest ruby gems (1.8.10 at the time of writing) being installed for me </li>
<li>Download Octopress:
<pre>git clone git://github.com/imathis/octopress.git octopress</pre>
</li>
<li>Change your current working directory to the octopress folder:
<pre>cd octopress</pre>
</li>
<li>You should get an alert from RVM, asking you if you want to trust the <code>.rvmrc</code> file in the folder.  Respond with (y)es, and you should get an error:
<pre>WARN: ruby ruby-1.9.2-p290 is not installed.
To install do: 'rvm install ruby-1.9.2-p290'</pre>
<p>Resolved this by editing the <code>.rvmrc</code> file and changing its contents to read <code>rvm 1.9.3</code> instead of <code>rvm 1.9.2</code> (RVM will ask you to re-confirm that you want to trust the file after you've updated it.)</li>
<li>Check the Ruby version
<pre>ruby --version</pre>
<p>. You should see <code>ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.2.0]</code></li>
<li>Install dependencies:
<pre>gem install bundler
bundle install</pre>
</li>
<li>Install the default theme:
<pre>rake install</pre>
</li>
<li>To test your new blog:
<pre>rake preview</pre>
<p> then hit it in the browser at <code>http://localhost:4000</code></li>
<li>To learn how to deploy your site, etc., follow the links in the "Next steps" section of <a href="http://octopress.org/docs/setup/">The Octopress Setup Guide</a> (by the way, why have people stopped adding anchors or ids to their headings? One small id for you, one big deep link for everyone else.) :)</li>
</ol>
<p>That's it, that should get you up and running with Octopress (and the latest Ruby–as of this writing, 1.9.3-p0), on a box running OS X Lion and Xcode 4.2.x.</p>
]]></content:encoded>
			<wfw:commentRss>http://aralbalkan.com/3963/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
	</item>
		<item>
		<title>A simple CoffeeScript to JSON shell script for Macs</title>
		<link>http://aralbalkan.com/3950</link>
		<comments>http://aralbalkan.com/3950#comments</comments>
		<pubDate>Sun, 13 Nov 2011 17:06:46 +0000</pubDate>
		<dc:creator>Aral</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[coffeescript]]></category>
		<category><![CDATA[converter]]></category>
		<category><![CDATA[convertor]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[script]]></category>

		<guid isPermaLink="false">http://aralbalkan.com/?p=3950</guid>
		<description><![CDATA[I was working through a tutorial on Bogart and CouchDB and decided to implement the examples in CoffeeScript instead of JavaScript as I've been meaning to play with CoffeeScript for a while now. One of the files in the tutorial is the package.json file for managing dependencies in the (absolutely lovely) package manager npm. When [...]]]></description>
			<content:encoded><![CDATA[<p id="top" />I was working through <a href="http://howtonode.org/bogart-couchdb">a tutorial on Bogart and CouchDB</a> and decided to implement the examples in <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> instead of JavaScript as I've been meaning to play with CoffeeScript for a while now. </p>
<p>One of the files in the tutorial is the <code>package.json</code> file for managing dependencies in the (absolutely lovely) package manager <a href="http://npmjs.org/">npm</a>. When I wrote the data structure out in CoffeeScript, however, the compiled data structure wasn't valid JSON according to <a href="http://jsonlint.com/">JSONLint</a> (it was nested between parentheses, had unquoted keys, and a trailing semi-colon, as you can see in the code snippet.)<span id="more-3950"></span></p>
<pre>({
  name: "blog",
  …
});</pre>
<p>(The CoffeeScript compiler generated the surrounding parentheses even when I used the <code>--bare</code> compiler flag.) </p>
<p>The resulting file also had a <code>.js</code> extension, instead of a <code>.json</code> extension and I  couldn't find a way to change that (although there is a compiler flag to change the <em>folder</em> the file gets created in).</p>
<p>So, to cut a long story short, I just whipped up <a href="https://gist.github.com/1362273">a little shell script to convert my original CoffeeScript data structure into valid JSON</a> simply by removing the extra characters the compiler had thrown in and adding quotes around the keys. Here's the (pardon the pun) gist of it:</p>
<div id="gist-1362273" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'>coffee --print --compile <span class="nv">$1</span>.coffee | sed <span class="s1">&#39;1s/^.//&#39;</span> | sed <span class="s1">&#39;s/  });/}/&#39;</span> | sed <span class="s2">&quot;s/\([^ &#39;\&quot;].*[^ &#39;\&quot;]\):/\&quot;\1\&quot;:/&quot;</span> &gt; <span class="nv">$1</span>.json</div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1362273/06258672342494227e2b7008b1b467257fbdc176/coffeetojson.sh" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1362273#file_coffeetojson.sh" style="float:right;margin-right:10px;color:#666">coffeetojson.sh</a>
            <a href="https://gist.github.com/1362273">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>(<ins>Update:</ins> Thanks to <a href="http://blog.brokenfunction.com/">Max</a>'s comment, I was able to boil down the script to a single line and get rid of the temporary files – thanks, Max!)</p>
<p>Not rocket science and I'm not a <code>sed</code> wizard so it may not be the most efficient way of doing things but it works. </p>
<p>So, if you want to write your static data structures in CoffeeScript and have them compile into valid JSON:</p>
<ol>
<li><a href="https://gist.github.com/1362273">check out the gist</a></li>
<li>Save it in a file called <code>coffeetojson</code></li>
<li>Don't forget to <code>chmod +x coffeetojson</code> to make it executable</li>
<li>Then, assuming that the <code>coffeetojson</code> script is in the same folder as your <code>.coffee</code> script containing your data structure (let's assume it's in a file called <code>mydata.coffee</code>), enter the following:</li>
</ol>
<pre>./coffeetojson mydata</pre>
<p>That will create a file called <code>mydata.json</code> with the valid JSON version of your data structure. (I haven't tested this exhaustively at all so there's a big chance it might fail – if it does, I'll be very happy to receive your patches.) :) </p>
<p>Why go to all this trouble, instead of authoring JSON by hand initially? Well, because as easy as JSON is to author by hand, CoffeeScript – with its barer syntax – is simpler still. And I'm lazy! :-)</p>
<p>Here's hoping this helps someone out there who is as lazy as I am!</p>
]]></content:encoded>
			<wfw:commentRss>http://aralbalkan.com/3950/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
	</item>
		<item>
		<title>Google Dart, or ‘how we lost the ECMAScript 4 battle so we decided to create our own language instead’.</title>
		<link>http://aralbalkan.com/3931</link>
		<comments>http://aralbalkan.com/3931#comments</comments>
		<pubDate>Tue, 11 Oct 2011 19:02:14 +0000</pubDate>
		<dc:creator>Aral</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[dart]]></category>
		<category><![CDATA[ecmascript]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[wtf]]></category>

		<guid isPermaLink="false">http://aralbalkan.com/?p=3931</guid>
		<description><![CDATA[So what do you do if you lose a public battle to change the face of JavaScript? If you're Google, you decide to go it alone, implement what you want to anyway, and then tell the world that it is going to replace JavaScript. What's the problem with Dart? Apart from the fact that it [...]]]></description>
			<content:encoded><![CDATA[<p id="top" />So what do you do if you <a href="http://ejohn.org/blog/ecmascript-harmony/">lose a public battle to change the face of JavaScript</a>? </p>
<p>If you're Google, you decide to go it alone, <a href="http://www.dartlang.org/">implement what you want to anyway</a>, and then tell the world that it is going to replace JavaScript. </p>
<p><span id="more-3931"></span></p>
<p>What's the problem with <a href="http://www.dartlang.org/">Dart</a>? Apart from the fact that it looks like a Java developer's wet dream and will possibly mean the existence of two client-side programming languages for the web, thereby confusing the heck out of anyone just coming into web programming, it's a solution for problems that mostly Google has. How many folks out there are creating Gmail or Google Docs? And what are the costs of the additional complexity of a language like Dart for people who aren't creating Gmail and Google Docs (in other words, the majority of the web?) And, instead of throwing your toys, flashing the middle finger at the rest of the web community, and going it alone, maybe the thing to do–if you believe in an open and standards-based web–is to play nice with the other kids.</p>
<p>Heck, can you imagine what the fallout would be if Microsoft declared, ‘you know what, we've decided that C# should be the language of the web. Today we're declaring that it's going to replace JavaScript and that every browser should implement it. We're going to start with IE10.’</p>
<p>Remember a time when you thought Google was good? Because it's beginning to look like the playground bully to me. Personally, I hope that no one apart from Google gives Dart–that convoluted and unnecessary ECMAScript 4++ of a language–any notice whatsoever. And here's hoping Google realize their folly before they bloat my favorite browser (Chrome) with <a href="https://gist.github.com/1277224">that shite</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://aralbalkan.com/3931/feed</wfw:commentRss>
		<slash:comments>17</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
	</item>
		<item>
		<title>Update site update</title>
		<link>http://aralbalkan.com/3892</link>
		<comments>http://aralbalkan.com/3892#comments</comments>
		<pubDate>Sun, 24 Jul 2011 23:18:44 +0000</pubDate>
		<dc:creator>Aral</dc:creator>
				<category><![CDATA[blog]]></category>
		<category><![CDATA[Conferences]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[User Experience]]></category>
		<category><![CDATA[conference]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[iteration]]></category>
		<category><![CDATA[update]]></category>
		<category><![CDATA[web site]]></category>

		<guid isPermaLink="false">http://aralbalkan.com/?p=3892</guid>
		<description><![CDATA[I just put a new iteration of the Update conference web site live, inspired by and in collaboration with designer Clare Sutcliffe. About a week or so ago, Clare – quite out of the blue – sent me an iteration on the Update site design that I absolutely adored. In organizing Update I'm wearing lots [...]]]></description>
			<content:encoded><![CDATA[<p id="top" /><a href="http://updateconf.com"><img src="http://dl.dropbox.com/u/5269427/blog-posts/update-site-comparison.jpg" alt="Update web site: before and after."/></a></p>
<p>I just put a new iteration of the <a href="http://updateconf.com">Update conference web site</a> live, inspired by and in collaboration with designer <a href="http://cargocollective.com/claresutcliffe">Clare Sutcliffe</a>. About a week or so ago, Clare – quite out of the blue – sent me an iteration on the Update site design that I absolutely adored. In organizing Update I'm wearing lots of hats at once and I couldn't do it all without the frankly humbling support and help I've been receiving from my friends. </p>
<p><span id="more-3892"></span></p>
<p>For the past few days, I've been incorporating much of Clare's input into the site. Any implementation issues you may encounter, of course, are entirely my doing. </p>
<p>Here are the main points that Clare helped me evolve with the design:</p>
<ul>
<li><strong>Panel overlays.</strong> Collecting all interface elements in the panels into a horizontal panel at the left. This has helped to create a much stronger grid and makes it easier to skim the site. It also leaves more space for copy and creates contrast for the section titles. </li>
<li><strong>Cleaned up the header.</strong> The old header used an image that I love and use in my presentations – the look of wonder in the little boy's face reflects the sort of magical experiences I know we – as designers and developers – can create. However, as Clare pointed out, it said nothing about the conference. The new image says mobile – which is what the conference is about. Adding the white overlay under the title helps contrast it against the photo. To this I also added a blur to the photo itself under the overlay to increase the legibility of the title and draw attention to it.</li>
<li><strong>Tidied up the ticket bar.</strong> I don't know what I was thinking when I created the ticket bar but, in hindsight, it definitely wasn't aesthetics. Clare's design cleaned that up and added another little mobile touch.</li>
<li><strong>Workshop panel backgrounds.</strong>Clare mentioned that the background on the Workshop panels just wasn't working. So I recreated them. They're much more vibrant and representative now.</li>
<li><strong>Half-size panels</strong> for the Brighton Digital Festival and Twitter visually distinguish them from the horizontally-scrollable full-size panels.</li>
<li><strong>Whitespace.</strong> The panels now have room to breathe and the whole design benefits from that.</li>
</ul>
<p>When working on the first iteration of the Update web site I was concentrating mostly on getting the interactions working well (and across desktop, iPhone-tier, and iPad-tier devices). The second iteration brings with it a much needed visual overhaul. The third iteration will bring additional content and hopefully a few more usability enhancements. I only wish I had more time to work on the site in addition to actually organizing the conference itself.</p>
<p>I hope I'll get some time to go into detail on the changes between the first two iterations in a future post. </p>
<p>And, here's a huge thank-you to <a href="http://cargocollective.com/claresutcliffe">Clare</a> – without her initiative, this update would not have been possible. I'm hugely enjoying collaborating with her on the site. </p>
]]></content:encoded>
			<wfw:commentRss>http://aralbalkan.com/3892/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
	</item>
		<item>
		<title>Adobe ExtendScript File object gotcha under OS X Lion</title>
		<link>http://aralbalkan.com/3872</link>
		<comments>http://aralbalkan.com/3872#comments</comments>
		<pubDate>Sat, 25 Jun 2011 19:53:14 +0000</pubDate>
		<dc:creator>Aral</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[BUG]]></category>
		<category><![CDATA[copy]]></category>
		<category><![CDATA[extendscript]]></category>
		<category><![CDATA[file]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[lion]]></category>
		<category><![CDATA[workaround]]></category>

		<guid isPermaLink="false">http://aralbalkan.com/?p=3872</guid>
		<description><![CDATA[File this under Ultra-Niche. If you happen to be one of the three people in the world using Adobe's easy-to-use and powerful ExtendScript to script the CS*-series of tools (e.g., Photoshop) and you're using the FIle object to write out files manually, read on. Under Snow Leopard, the following code would work (you'll find variants [...]]]></description>
			<content:encoded><![CDATA[<p id="top" />File this under Ultra-Niche. If you happen to be one of the three people in the world using Adobe's easy-to-use and powerful ExtendScript to script the CS*-series of tools (e.g., Photoshop) and you're using the FIle object to write out files manually, read on.</p>
<p>Under Snow Leopard, the following code would work (you'll find variants of this code floating around the Internets):</p>
<p><span id="more-3872"></span></p>
<pre class="javascript"><span style="color: #003366; font-weight: bold;">var</span> cssFile = <span style="color: #003366; font-weight: bold;">new</span> File<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
cssFile.<span style="color: #000066;">open</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'w'</span><span style="color: #66cc66;">&#41;</span>;
cssFile.<span style="color: #000066; font-weight: bold;">write</span><span style="color: #66cc66;">&#40;</span>css<span style="color: #66cc66;">&#41;</span>;
cssFile.<span style="color: #006600;">copy</span><span style="color: #66cc66;">&#40;</span>cssFilePath<span style="color: #66cc66;">&#41;</span>;</pre>
<p>In OS X Lion, it doesn't. Instead use:</p>
<pre class="javascript"><span style="color: #003366; font-weight: bold;">var</span> cssFile = <span style="color: #003366; font-weight: bold;">new</span> File<span style="color: #66cc66;">&#40;</span>cssFilePath<span style="color: #66cc66;">&#41;</span>;
cssFile.<span style="color: #000066;">open</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'w'</span><span style="color: #66cc66;">&#41;</span>;
cssFile.<span style="color: #000066; font-weight: bold;">write</span><span style="color: #66cc66;">&#40;</span>css<span style="color: #66cc66;">&#41;</span>;
cssFile.<span style="color: #000066;">close</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;</pre>
<p>Hope this helps the one dudette in Sweden who runs across the issue in 2013 :)</p>
]]></content:encoded>
			<wfw:commentRss>http://aralbalkan.com/3872/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
	</item>
		<item>
		<title>Optinal arguments that aren&#8217;t really optional (or thank-you, again, FireFox)</title>
		<link>http://aralbalkan.com/3860</link>
		<comments>http://aralbalkan.com/3860#comments</comments>
		<pubDate>Mon, 06 Jun 2011 09:50:00 +0000</pubDate>
		<dc:creator>Aral</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[addEventListener]]></category>
		<category><![CDATA[argument]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[Not enough arguments]]></category>
		<category><![CDATA[NS_ERROR_XPC_NOT_ENOUGH_ARGS]]></category>
		<category><![CDATA[optional]]></category>
		<category><![CDATA[required]]></category>

		<guid isPermaLink="false">http://aralbalkan.com/?p=3860</guid>
		<description><![CDATA[The error: "uncaught exception: [Exception... "Not enough arguments" nsresult: "0x80570001 (NS_ERROR_XPC_NOT_ENOUGH_ARGS)" location: "JS frame" The cause: Not providing the supposedly-optional-but-not-always-optional-for-every-browser-third-argument to the addEventListener method in JavaScript. I had: document.body.addEventListener('touchmove', function(e){ e.preventDefault(); }); I should have written: document.body.addEventListener('touchmove', function(e){ e.preventDefault(); }, false); Firefox, I hate you. Love, Aral (who hasn't slept yet and it's almost 11AM) [...]]]></description>
			<content:encoded><![CDATA[<p id="top" />The error: "uncaught exception: [Exception... "Not enough arguments" nsresult: "0x80570001 (NS_ERROR_XPC_NOT_ENOUGH_ARGS)" location: "JS frame"</p>
<p>The cause: Not providing the supposedly-optional-but-not-always-optional-for-every-browser-third-argument to the <code>addEventListener</code> method in JavaScript.</p>
<p><span id="more-3860"></span></p>
<p>I had:</p>
<pre>document.body.addEventListener('touchmove', function(e){ e.preventDefault(); });</pre>
<p>I should have written:</p>
<pre>document.body.addEventListener('touchmove', function(e){ e.preventDefault(); }, false);</pre>
<p>Firefox, I hate you. Love, Aral (who hasn't slept yet and it's almost 11AM) xxx</p>
]]></content:encoded>
			<wfw:commentRss>http://aralbalkan.com/3860/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
	</item>
		<item>
		<title>Multi-resolution images, Photoshop, and ExtendScript</title>
		<link>http://aralbalkan.com/3852</link>
		<comments>http://aralbalkan.com/3852#comments</comments>
		<pubDate>Sat, 04 Jun 2011 21:41:33 +0000</pubDate>
		<dc:creator>Aral</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[extendscript]]></category>
		<category><![CDATA[ipad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Photoshop]]></category>
		<category><![CDATA[ps]]></category>
		<category><![CDATA[resolution independence]]></category>
		<category><![CDATA[retina]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://aralbalkan.com/?p=3852</guid>
		<description><![CDATA[In the initial version of the upcoming Update conference web site, I'm optimizing for desktop, iPad, and iPhone-tier phones. This means that I have to create five different versions of nearly every image. One for the desktop size, one for 320px wide screens, one for 480px wide screens, and two for the Retina (@2X) resolutions. [...]]]></description>
			<content:encoded><![CDATA[<p id="top" /><img src="http://dl.dropbox.com/u/5269427/blog-posts/extendscript.png" alt="Extendscript editor" /><br />
In the initial version of the upcoming <a href="http://updateconf.com">Update conference web site</a>, I'm optimizing for desktop, iPad, and iPhone-tier phones. This means that I have to create five different versions of nearly every image. One for the desktop size, one for 320px wide screens, one for 480px wide screens, and two for the Retina (@2X) resolutions. Of course, saving all those images by hand would suck. And it's not enough just to resize the images and export them for web since, when resized, I need to unsharp mask them to make sure they're not blurry. </p>
<p>I initially thought I could record an action to do this, but the Photoshop file I have for the graphics has dozens of layers. I thought I could use the <em>Layer comps to files…</em> script that ships with Photoshop but – while it let me export layer comps to files – it wouldn't let me add custom actions in the middle of the process (in this case to unsharp mask the image once it was resized). </p>
<p><span id="more-3852"></span></p>
<p>So, I thought I'd bite the bullet and write my own script. The process was surprisingly painless. Adobe have done a rather awesome job with ExtendScript. Using JavaScript, and the <a href="http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/photoshop/pdfs/photoshop_cs5_javascript_ref.pdf">Adobe Photoshop CS5 JavaScript Reference (PDF)</a>, I was able to whip up a quick script that cycles through the range of image sizes I need to support, unsharp masks all the layers, then activates each layer comp in turn and saves it out to its own file. </p>
<p>Here's the script:</p>
<div id="gist-1008359" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cm">/* </span></div><div class='line' id='LC2'><span class="cm">    The original files are 960x319.</span></div><div class='line' id='LC3'><span class="cm">    </span></div><div class='line' id='LC4'><span class="cm">    Image sizes to save:</span></div><div class='line' id='LC5'><span class="cm">    </span></div><div class='line' id='LC6'><span class="cm">    * 800x266 - Retina for 480x320 resolution (400 logical pixel wide panel areas)</span></div><div class='line' id='LC7'><span class="cm">    * 740x246 - Desktop and iPad</span></div><div class='line' id='LC8'><span class="cm">    * 616x205 - Retina for 320x480 resolution (308 logical pixel wide panel areas)</span></div><div class='line' id='LC9'><span class="cm">    * 400x133 - 480x320 resolution</span></div><div class='line' id='LC10'><span class="cm">    * 308x102 - 320x480 resolution</span></div><div class='line' id='LC11'><span class="cm">    </span></div><div class='line' id='LC12'><span class="cm">    The various states (each image) is in a layer comp.</span></div><div class='line' id='LC13'><span class="cm">    </span></div><div class='line' id='LC14'><span class="cm">    Process:</span></div><div class='line' id='LC15'><span class="cm">   </span></div><div class='line' id='LC16'><span class="cm">    1. Loop through the image sizes.</span></div><div class='line' id='LC17'><span class="cm">    -- 2. Save history state.</span></div><div class='line' id='LC18'><span class="cm">    -- 3. Resize to the current image size.</span></div><div class='line' id='LC19'><span class="cm">    -- 4. Loop through layers</span></div><div class='line' id='LC20'><span class="cm">    ---- 5. Apply unsharp mask</span></div><div class='line' id='LC21'><span class="cm">    -- 6. Loop through layer comps</span></div><div class='line' id='LC22'><span class="cm">    ---- 7. Save image</span></div><div class='line' id='LC23'><span class="cm">    -- 8. Restore the history state to return to the full-sized image.</span></div><div class='line' id='LC24'><span class="cm">        </span></div><div class='line' id='LC25'><span class="cm">*/</span></div><div class='line' id='LC26'><br/></div><div class='line' id='LC27'><span class="kd">var</span> <span class="nx">docRef</span> <span class="o">=</span> <span class="nx">app</span><span class="p">.</span><span class="nx">activeDocument</span><span class="p">;</span></div><div class='line' id='LC28'><br/></div><div class='line' id='LC29'><span class="kd">var</span> <span class="nx">layerComps</span> <span class="o">=</span> <span class="nx">docRef</span><span class="p">.</span><span class="nx">layerComps</span><span class="p">;</span></div><div class='line' id='LC30'><span class="kd">var</span> <span class="nx">numLayerComps</span> <span class="o">=</span> <span class="nx">layerComps</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span></div><div class='line' id='LC31'><span class="kd">var</span> <span class="nx">layers</span> <span class="o">=</span> <span class="nx">docRef</span><span class="p">.</span><span class="nx">layers</span><span class="p">;</span></div><div class='line' id='LC32'><span class="kd">var</span> <span class="nx">numLayers</span> <span class="o">=</span> <span class="nx">layers</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span></div><div class='line' id='LC33'><br/></div><div class='line' id='LC34'><span class="kd">var</span> <span class="nx">imageSizes</span> <span class="o">=</span> <span class="p">[</span></div><div class='line' id='LC35'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">[</span><span class="s2">&quot;800px&quot;</span><span class="p">,</span> <span class="s2">&quot;266px&quot;</span><span class="p">],</span></div><div class='line' id='LC36'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">[</span><span class="s2">&quot;740px&quot;</span><span class="p">,</span> <span class="s2">&quot;246px&quot;</span><span class="p">],</span></div><div class='line' id='LC37'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">[</span><span class="s2">&quot;616px&quot;</span><span class="p">,</span> <span class="s2">&quot;205px&quot;</span><span class="p">],</span></div><div class='line' id='LC38'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">[</span><span class="s2">&quot;400px&quot;</span><span class="p">,</span> <span class="s2">&quot;133px&quot;</span><span class="p">],</span></div><div class='line' id='LC39'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">[</span><span class="s2">&quot;308px&quot;</span><span class="p">,</span> <span class="s2">&quot;102px&quot;</span><span class="p">]</span></div><div class='line' id='LC40'><span class="p">];</span></div><div class='line' id='LC41'><br/></div><div class='line' id='LC42'><span class="kd">var</span> <span class="nx">exportOptionsSaveForWeb</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ExportOptionsSaveForWeb</span><span class="p">();</span></div><div class='line' id='LC43'><span class="nx">exportOptionsSaveForWeb</span><span class="p">.</span><span class="nx">format</span> <span class="o">=</span> <span class="nx">SaveDocumentType</span><span class="p">.</span><span class="nx">JPEG</span><span class="p">;</span></div><div class='line' id='LC44'><span class="nx">exportOptionsSaveForWeb</span><span class="p">.</span><span class="nx">includeProfile</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span></div><div class='line' id='LC45'><span class="nx">exportOptionsSaveForWeb</span><span class="p">.</span><span class="nx">quality</span> <span class="o">=</span> <span class="mi">70</span><span class="p">;</span></div><div class='line' id='LC46'><br/></div><div class='line' id='LC47'><span class="nx">parentFolderPath</span> <span class="o">=</span> <span class="nx">Folder</span><span class="p">(</span><span class="nx">app</span><span class="p">.</span><span class="nx">activeDocument</span><span class="p">.</span><span class="nx">fullName</span><span class="p">.</span><span class="nx">parent</span><span class="p">).</span><span class="nx">fsName</span><span class="p">;</span></div><div class='line' id='LC48'><br/></div><div class='line' id='LC49'><span class="c1">// 1. Loop through the image sizes.</span></div><div class='line' id='LC50'><span class="kd">var</span> <span class="nx">numImageSizes</span> <span class="o">=</span> <span class="nx">imageSizes</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span></div><div class='line' id='LC51'><span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">numImageSizes</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC52'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">currentImageSize</span> <span class="o">=</span> <span class="nx">imageSizes</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span></div><div class='line' id='LC53'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">currentImageWidth</span> <span class="o">=</span> <span class="nx">currentImageSize</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span></div><div class='line' id='LC54'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">currentImageHeight</span> <span class="o">=</span> <span class="nx">currentImageSize</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span></div><div class='line' id='LC55'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC56'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// 2. Save the history state.</span></div><div class='line' id='LC57'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">savedState</span> <span class="o">=</span> <span class="nx">docRef</span><span class="p">.</span><span class="nx">activeHistoryState</span><span class="p">;</span></div><div class='line' id='LC58'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC59'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// 3. Resize to the current image size.</span></div><div class='line' id='LC60'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">docRef</span><span class="p">.</span><span class="nx">resizeImage</span><span class="p">(</span><span class="nx">currentImageWidth</span><span class="p">,</span> <span class="nx">currentImageHeight</span><span class="p">);</span></div><div class='line' id='LC61'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC62'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// 4. Loop through layers</span></div><div class='line' id='LC63'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">j</span> <span class="o">&lt;</span> <span class="nx">numLayers</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC64'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">currentLayer</span> <span class="o">=</span> <span class="nx">layers</span><span class="p">[</span><span class="nx">j</span><span class="p">];</span></div><div class='line' id='LC65'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC66'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="nx">currentLayer</span><span class="p">.</span><span class="nx">name</span> <span class="o">==</span> <span class="s2">&quot;Overlay&quot;</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC67'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$</span><span class="p">.</span><span class="nx">writeln</span><span class="p">(</span><span class="s2">&quot;Not going to unsharp mask the overlay.&quot;</span><span class="p">);</span></div><div class='line' id='LC68'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">continue</span><span class="p">;</span></div><div class='line' id='LC69'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC70'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC71'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">//  5. Apply unsharp mask</span></div><div class='line' id='LC72'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">currentLayer</span><span class="p">.</span><span class="nx">visible</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span></div><div class='line' id='LC73'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// $.writeln(&quot;About to unsharp mask: &quot; + currentLayer.name);</span></div><div class='line' id='LC74'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">currentLayer</span><span class="p">.</span><span class="nx">applyUnSharpMask</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="mf">1.1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span></div><div class='line' id='LC75'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC76'><br/></div><div class='line' id='LC77'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// 6. Loop through layer comps</span></div><div class='line' id='LC78'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">k</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">k</span> <span class="o">&lt;</span> <span class="nx">numLayerComps</span><span class="p">;</span> <span class="nx">k</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC79'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">currentLayerComp</span> <span class="o">=</span> <span class="nx">layerComps</span><span class="p">[</span><span class="nx">k</span><span class="p">];</span></div><div class='line' id='LC80'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">currentLayerComp</span><span class="p">.</span><span class="nx">apply</span><span class="p">();</span></div><div class='line' id='LC81'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC82'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">documentPath</span> <span class="o">=</span> <span class="nx">parentFolderPath</span> <span class="o">+</span> <span class="s2">&quot;/images/&quot;</span> <span class="o">+</span> <span class="nx">docRef</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">docRef</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">4</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;-&quot;</span> <span class="o">+</span> <span class="nx">currentLayerComp</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="s2">&quot;-&quot;</span> <span class="o">+</span> <span class="nx">currentImageWidth</span> <span class="o">+</span> <span class="s2">&quot;.jpg&quot;</span><span class="p">;</span></div><div class='line' id='LC83'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">file</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">File</span><span class="p">(</span><span class="nx">documentPath</span><span class="p">);</span></div><div class='line' id='LC84'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC85'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// $.writeln(&quot;About to save: &quot; + documentPath);</span></div><div class='line' id='LC86'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC87'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// 7. Save image</span></div><div class='line' id='LC88'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">docRef</span><span class="p">.</span><span class="nx">exportDocument</span> <span class="p">(</span><span class="nx">file</span><span class="p">,</span> <span class="nx">ExportType</span><span class="p">.</span><span class="nx">SAVEFORWEB</span><span class="p">,</span> <span class="nx">exportOptionsSaveForWeb</span><span class="p">)</span></div><div class='line' id='LC89'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC90'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC91'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// 8. Restore the history state to return to the full-sized image.</span></div><div class='line' id='LC92'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">docRef</span><span class="p">.</span><span class="nx">activeHistoryState</span> <span class="o">=</span> <span class="nx">savedState</span><span class="p">;</span></div><div class='line' id='LC93'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC94'><span class="p">}</span></div><div class='line' id='LC95'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1008359/b908dd28ec2112c257f0224c60cf252d733cb842/psextendscriptexample.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1008359#file_psextendscriptexample.js" style="float:right;margin-right:10px;color:#666">psextendscriptexample.js</a>
            <a href="https://gist.github.com/1008359">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>It probably won't be too much use to you in exactly its current form but you can easily modify it to suit your needs and it might just get you to start playing with ExtendScript – it's like Actions on steroids. Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://aralbalkan.com/3852/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
	</item>
		<item>
		<title>Scrolling in a whole other dimension</title>
		<link>http://aralbalkan.com/3840</link>
		<comments>http://aralbalkan.com/3840#comments</comments>
		<pubDate>Fri, 13 May 2011 22:07:56 +0000</pubDate>
		<dc:creator>Aral</dc:creator>
				<category><![CDATA[Commentary]]></category>
		<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://aralbalkan.com/?p=3840</guid>
		<description><![CDATA[Take your favorite content slider and try this: on a Mac notebook, two-finger scroll. I'll bet my hat (easy to do when you don't wear hats) that the component will go nuts. For one thing, it will most likely be mapping your vertical scroll gesture to a horizontal scroll. I don't know who first decided [...]]]></description>
			<content:encoded><![CDATA[<p id="top" /><a href="/mousewheel-test" target="_blank"><img src="http://dl.dropbox.com/u/5269427/blog-posts/scrolling/compass-for-blog.jpg" width="400" height="402" alt="Compass" style="margin-left:2.75em;" class="transparent"/></a></p>
<p>Take your favorite content slider and try this: on a Mac notebook, two-finger scroll. I'll bet my hat (easy to do when you don't wear hats) that the component will go nuts. For one thing, it will most likely be mapping your vertical scroll gesture to a horizontal scroll. I don't know who first decided that was a good idea but I think we can safely agree that it doesn't make any sense. And <em>every</em> content slider out there that I've encountered does this! So much so that I actually thought that you simply couldn't get horizontal scroll information from the "mousewheel". </p>
<p><span id="more-3840"></span></p>
<p>But you can.</p>
<p><a href="/mousewheel-test" target="_blank">Here's a little example</a> I just hacked together that demonstrates it.</p>
<p>It uses the <a href="Brandon Aaron">jQuery Mousewheel</a> plugin by Brandon Aaron which gives you a neat callback with the deltaX and deltaY of the mousewheel/trackpad two-finger scroll. </p>
<p>I've only tested this on Firefox and Chrome on my Mac and it worked on both.</p>
<p>So, dear content-scroller-makers-of-the-web, let's use that lovely little deltaX property to actually map horizontal scroll gestures to horizontal scrolls and leave the vertical scroll alone so that the web page can, y'know, scroll like it should.</p>
<p><em><strong>Update:</strong> I improved the example with a nifty little compass. Nicer to look at. Not sure why I had to do that at almost 1AM but hey, enjoy!</em></p>
]]></content:encoded>
			<wfw:commentRss>http://aralbalkan.com/3840/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
	</item>
		<item>
		<title>How to add pinch-to-zoom to a text view on iOS</title>
		<link>http://aralbalkan.com/3831</link>
		<comments>http://aralbalkan.com/3831#comments</comments>
		<pubDate>Wed, 11 May 2011 10:51:30 +0000</pubDate>
		<dc:creator>Aral</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Accessibility]]></category>
		<category><![CDATA[cocoa touch]]></category>
		<category><![CDATA[font size]]></category>
		<category><![CDATA[ios]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[pinch-to-zoom]]></category>
		<category><![CDATA[scaling]]></category>
		<category><![CDATA[text]]></category>
		<category><![CDATA[text size]]></category>
		<category><![CDATA[uitextview]]></category>
		<category><![CDATA[visual impairments]]></category>
		<category><![CDATA[zoom]]></category>

		<guid isPermaLink="false">http://aralbalkan.com/?p=3831</guid>
		<description><![CDATA[I'm up to my neck in work trying to get the site for Update Conference up and running but I saw a tweet in my stream from Mark Ford that I couldn't ignore. Mark had written a blog post about how his wife finds it difficult to use some iOS apps because they do not [...]]]></description>
			<content:encoded><![CDATA[<p id="top" />I'm up to my neck in work trying to get the site for <a href="http://updateconf.com">Update Conference</a> up and running but I saw <a href="https://twitter.com/fordie/status/68228350283485185">a tweet in my stream from Mark Ford</a> that I couldn't ignore.</p>
<p>Mark had written <a href="http://fordie.co.uk/2011/05/10/iphone-app-developers-lend-me-your-ears/">a blog post</a> about how his wife finds it difficult to use some iOS apps because they do not implement a means to increase text size:<span id="more-3831"></span></p>
<blockquote><p>I have a particular bee in my bonnet when it comes to accessibility, my wife is registered blind and I am constantly frustrated when she is unable see things (like text on a screen) especially when I know that this is avoidable… What I don’t understand is why there is no way to change font size system wide, or why app developers don’t provide that facility. Yes I know that you can switch on zooming, but honestly – have you tried using zooming on a phone?</p></blockquote>
<p>So I dutifully retweeted Mark's tweet – as you do – and went on battling with cross-browser issues for the site (you really get to appreciate how wonderful an experience it is to develop for a single platform when you go back to battling with cross-platform development). I also told Mark that in <a href="http://feathersapp.com">Feathers</a>, you can pinch-to-zoom the tweet text in the main text view. (Goodness knows, having as custom UI as it has, Feathers has a long way to go in terms of accessibility itself.) Mark responded with: "ha! so text scaling is doable. Thanks @aral! care to explain how so others can follow suite?"</p>
<p>OK, Mark (and other iOS devs), here goes: it's actually <em>really</em> easy. </p>
<p>You simply create a pinch gesture recognizer and attach it to a text view. Then you adjust the font size (and hopefully persist it for next time so the user doesn't have to keep doing it every time she uses your app).</p>
<p>It's about as much code as it is to explain in English, so here's a snippet from Feathers:</p>
<div id="gist-966260" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'>// Create a pinch gesture recognizer instance.</div><div class='line' id='LC2'>self.pinchGestureRecognizer = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGesture:)] autorelease];</div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'>// And add it to your text view.</div><div class='line' id='LC5'>[self.myTextView addGestureRecognizer:self.pinchGestureRecognizer];</div><div class='line' id='LC6'><br/></div><div class='line' id='LC7'>// ... </div><div class='line' id='LC8'><br/></div><div class='line' id='LC9'>- (void)pinchGesture:(UIPinchGestureRecognizer *)gestureRecognizer</div><div class='line' id='LC10'>{</div><div class='line' id='LC11'>	NSLog(@&quot;*** Pinch: Scale: %f Velocity: %f&quot;, gestureRecognizer.scale, gestureRecognizer.velocity);</div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'>	UIFont *font = self.myTextView.font;</div><div class='line' id='LC14'>	CGFloat pointSize = font.pointSize;</div><div class='line' id='LC15'>	NSString *fontName = font.fontName;</div><div class='line' id='LC16'><br/></div><div class='line' id='LC17'>	pointSize = ((gestureRecognizer.velocity &gt; 0) ? 1 : -1) * 1 + pointSize;</div><div class='line' id='LC18'><br/></div><div class='line' id='LC19'>	if (pointSize &lt; 13) pointSize = 13;</div><div class='line' id='LC20'>	if (pointSize &gt; 42) pointSize = 42; </div><div class='line' id='LC21'><br/></div><div class='line' id='LC22'>	self.myTextView.font = [UIFont fontWithName:fontName size:pointSize];</div><div class='line' id='LC23'><br/></div><div class='line' id='LC24'>	// Save the new font size in the user defaults.</div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// (UserDefaults is my own wrapper around NSUserDefaults.)</div><div class='line' id='LC26'>	[[UserDefaults sharedUserDefaults] setFontSize:pointSize];</div><div class='line' id='LC27'>}</div><div class='line' id='LC28'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/966260/9a269e51e75a0ab5efc06de918d44722018f693a/TextViewPinchToZoom" style="float:right;">view raw</a>
            <a href="https://gist.github.com/966260#file_text_view_pinch_to_zoom" style="float:right;margin-right:10px;color:#666">TextViewPinchToZoom</a>
            <a href="https://gist.github.com/966260">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>I hope this helps and I hope seeing how simple it is to implement will mean that more developers will implement this in their apps. Thanks for bringing it to my attention, Mark. </p>
]]></content:encoded>
			<wfw:commentRss>http://aralbalkan.com/3831/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
	</item>
		<item>
		<title>READY? FIGHT! Don&#8217;t miss the first Geek Ninja Battle Night!</title>
		<link>http://aralbalkan.com/3729</link>
		<comments>http://aralbalkan.com/3729#comments</comments>
		<pubDate>Mon, 24 Jan 2011 18:54:30 +0000</pubDate>
		<dc:creator>Aral</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Conferences]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[2011]]></category>
		<category><![CDATA[andy clarke]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Aral Balkan]]></category>
		<category><![CDATA[Brighton]]></category>
		<category><![CDATA[cocoa touch]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[css3]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[geek ninja battle night]]></category>
		<category><![CDATA[gnbn]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[ios]]></category>
		<category><![CDATA[ios sdk]]></category>
		<category><![CDATA[ipad]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[march]]></category>
		<category><![CDATA[native]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[remy sharp]]></category>
		<category><![CDATA[sarah parmenter]]></category>
		<category><![CDATA[social]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://aralbalkan.com/?p=3729</guid>
		<description><![CDATA[Update: sorry everyone, the event sold out in under 24 hours but there is a waiting list you can sign up to in case anyone drops out. Thank-you all for your overwhelming interest and here's looking forward to seeing a bunch of you there in March! Watch as Sarah Parmenter and yours truly pummel Andy [...]]]></description>
			<content:encoded><![CDATA[<p id="top" /><a href="http://thelink.is/geekninjafactorybattlenight"><img src="http://dl.dropbox.com/u/5269427/geekninjafactory/geek-ninja-battle-night-blog-main.jpg" alt="Geek Ninja Factory Battle night"></a></p>
<p><strong>Update:</strong> sorry everyone, the event sold out in under 24 hours but there is a <a href="http://thelink.is/geekninjafactorybattlenight">waiting list</a> you can sign up to in case anyone drops out. Thank-you all for your overwhelming interest and here's looking forward to seeing a bunch of you there in March!</p>
<p><span id="more-3729"></span></p>
<p>Watch as <a href="http://sazzy.co.uk">Sarah Parmenter</a> and yours truly pummel <a href="http://www.stuffandnonsense.co.uk/">Andy Clarke</a> and <a href="http://remysharp.com/">Remy Sharp</a> in the first <a href="http://thelink.is/geekninjafactorybattlenight">Geek Ninja Battle Night</a> in Brighton this March. </p>
<p>It's Web vs. Native, as we explore the myriad of options open to digital creatives designing and developing for mobile devices.</p>
<p>Come join us for an evening of talks, debate, and drinks at the first community event organized by <a href="http://geekninjafactory.com">Geek Ninja Factory</a>. Tickets are just £10 and already selling like hotcakes.</p>
<p>(Actually, they're selling like hotcakes would sell if they were tickets to this awesome event.) </p>
<p><a href="http://thelink.is/geekninjafactorybattlenight">Reserve your place today</a> to avoid disappointment and possible exposure to Hungarian Hairy Hamster disease.*</p>
<p><em>* We would like to take this opportunity to inform you that you won't really catch Hungarian Hairy Hamster disease if you don't attend this event. In fact, Hungarian Hairy Hamster disease is no laughing matter and we profusely apologise for even mentioning it in the previous paragraph. We promise never to mention Hungarian Hairy Hamster disease on this blog ever again (or at least until the next post, whichever is sooner).</em></p>
]]></content:encoded>
			<wfw:commentRss>http://aralbalkan.com/3729/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc/2.0/uk/</creativeCommons:license>
	</item>
	</channel>
</rss>

