<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>pseudofish</title><link href="https://pseudofish.com/" rel="alternate"></link><link href="https://pseudofish.com/atom.xml" rel="self"></link><id>https://pseudofish.com/</id><updated>2023-11-27T00:00:00+01:00</updated><entry><title>Timeless Recommendations</title><link href="https://pseudofish.com/timeless-recommendations.html" rel="alternate"></link><published>2023-11-27T00:00:00+01:00</published><updated>2023-11-27T00:00:00+01:00</updated><author><name>Geoff</name></author><id>tag:pseudofish.com,2023-11-27:/timeless-recommendations.html</id><summary type="html">&lt;div id="table-of-contents" role="doc-toc"&gt;
&lt;h2&gt;Table of&amp;nbsp;Contents&lt;/h2&gt;
&lt;div id="text-table-of-contents" role="doc-toc"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#org0d1a67b"&gt;1.&amp;nbsp;Books&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#org61d9389"&gt;2.&amp;nbsp;Podcasts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
So much of what we consume has a shelf life, which, when turned around, means
we can use time as a filter for quality. Anything that survives a certain
number of years, has utility beyond&amp;nbsp;now.
&lt;/p&gt;

&lt;p&gt;
For me, I try and avoid &lt;a href="https://www.goodreads.com/user/show/50188044-geoff"&gt;reading …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;div id="table-of-contents" role="doc-toc"&gt;
&lt;h2&gt;Table of&amp;nbsp;Contents&lt;/h2&gt;
&lt;div id="text-table-of-contents" role="doc-toc"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#org0d1a67b"&gt;1.&amp;nbsp;Books&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#org61d9389"&gt;2.&amp;nbsp;Podcasts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
So much of what we consume has a shelf life, which, when turned around, means
we can use time as a filter for quality. Anything that survives a certain
number of years, has utility beyond&amp;nbsp;now.
&lt;/p&gt;

&lt;p&gt;
For me, I try and avoid &lt;a href="https://www.goodreads.com/user/show/50188044-geoff"&gt;reading&lt;/a&gt; too many recent books (inspired by &lt;a href="https://tim.blog/2020/01/20/one-decision-that-removes-100-decisions/"&gt;Tim&lt;/a&gt;). I
also avoid recommending anything too new, and have found my recommendations
settling into a few key books and podcasts. Rather than write them out many
times, I&amp;#8217;m publishing them here&amp;nbsp;instead.
&lt;/p&gt;

&lt;div id="outline-container-org0d1a67b" class="outline-2"&gt;
&lt;h2 id="org0d1a67b"&gt;&lt;span class="section-number-2"&gt;1.&lt;/span&gt;&amp;nbsp;Books&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-1"&gt;
&lt;ul class="org-ul"&gt;
&lt;li&gt;&lt;a href="https://amzn.to/40U7Ore"&gt;The Effective Executive&lt;/a&gt; &lt;i&gt;(Peter Drucker)&lt;/i&gt; &amp;#x2013; This has been my most referred to
book in my professional career. The subtitle of &lt;i&gt;&amp;#8220;getting the right things&lt;/i&gt;
done&amp;#8221; captures the essence of the&amp;nbsp;book.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/47CaSeg"&gt;7 Powers&lt;/a&gt; &lt;i&gt;(Hamilton Helmer)&lt;/i&gt; &amp;#x2013; A highly effective famework for identifying
strategic power for an organization. At Spotify we made use of this
framework, which is also used by Netflix leadership. The Acquired podcast
uses it to analyze various companies and has interviewed Hamilton&amp;nbsp;too.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3sThvtj"&gt;Creativity Inc&lt;/a&gt; &lt;i&gt;(Ed Catmull)&lt;/i&gt; &amp;#x2013; Creativity is rarely repeatable, let alone in
a large organization. Pixar is one of the few that has sustained creativity
over a long period of time, and this is an inside account of how they
retained&amp;nbsp;inspiration.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/489wxKH"&gt;Mr China&lt;/a&gt; &lt;i&gt;(Tim Clissold)&lt;/i&gt; &amp;#x2013; An insiders account to doing business with and
in China over many years. While the examples are from a while ago, they
highlight the historical perspective and&amp;nbsp;complexities.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3SZwqNb"&gt;The Evolution of Co-operation&lt;/a&gt; &lt;i&gt;(Robert Axelrod)&lt;/i&gt; &amp;#x2013; My math mind loves the
idea that the incentives of co-operation can be captured algorithmically.
The idea that &lt;a href="https://en.wikipedia.org/wiki/Prisoner%27s_dilemma#The_iterated_prisoner's_dilemma"&gt;repeated&lt;/a&gt; application of &lt;a href="https://en.wikipedia.org/wiki/Prisoner%27s_dilemma"&gt;Prisoner&amp;#8217;s Dilemma&lt;/a&gt; explains much human
interaction also appeals. &lt;a href="https://amzn.to/49W94Oq"&gt;Finite and Infinite Games&lt;/a&gt; is also a good read&amp;nbsp;here.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/49V6Z5n"&gt;High Output Management&lt;/a&gt; &lt;i&gt;(Andy Grove)&lt;/i&gt; &amp;#x2013; Much of the &lt;i&gt;why&lt;/i&gt; behind how
Silicon Valley tech companies work comes from this book. As with most
things, it is worth going back to source to understand&amp;nbsp;today.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3SCZCaY"&gt;On Writing Well&lt;/a&gt; &lt;i&gt;(William Zinsser)&lt;/i&gt; &amp;#x2013; the best guide to writing
non-fiction. Communicating effectively is critical to sharing your ideas, so
do it&amp;nbsp;well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Absent from my book list are biographies, one of the key ways of learning
about the history of any industry or human endeavour. The timeless advice is
to read widely and deeply about the people who came before. However, it will
depend a bit on your own interests as to which ones to&amp;nbsp;recommend.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id="outline-container-org61d9389" class="outline-2"&gt;
&lt;h2 id="org61d9389"&gt;&lt;span class="section-number-2"&gt;2.&lt;/span&gt;&amp;nbsp;Podcasts&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-2"&gt;
&lt;ul class="org-ul"&gt;
&lt;li&gt;&lt;a href="https://manager-tools.com/manager-tools-podcasts"&gt;Manager Tools&lt;/a&gt; &amp;#x2013; Thanks to a recommendation from a great friend when I
started my management career early in the 2000&amp;#8217;s, Mark and Mike have
provided weekly council on how to be a great manager. If you are in an
organization and in any way responsible for other people, add this to your
podcast player of&amp;nbsp;choice.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.founderspodcast.com/"&gt;Founders&lt;/a&gt; &amp;#x2013; Reviews of biographies of founders. No matter how much you read,
you are unlikely to keep pace with David Senra. He will help you learn
directly from history&amp;#8217;s greatest entrepreneurs. While the podcast is
amazing, you will get so much more from it if you read some of the books.
The episodes will help you figure out your own interests and where you can
go&amp;nbsp;deeper.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.acquired.fm/"&gt;Acquired&lt;/a&gt; &amp;#x2013; The stories behind the formation of great companies. If you are
in the business of building anything new for the world, this will help you
understand how it has been done before. Amazing research and compelling
storytelling make it a fun listen&amp;nbsp;too.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="musings"></category></entry><entry><title>Org-mode for everything</title><link href="https://pseudofish.com/org-mode-for-everything.html" rel="alternate"></link><published>2016-08-20T00:00:00+02:00</published><updated>2016-08-20T00:00:00+02:00</updated><author><name>Geoff</name></author><id>tag:pseudofish.com,2016-08-20:/org-mode-for-everything.html</id><summary type="html">&lt;p&gt;
&lt;a href="http://orgmode.org"&gt;Org-mode&lt;/a&gt; is a useful emacs mode for &lt;a href="http://pseudofish.com/using-deft-mode-for-notes-in-emacs.html"&gt;note taking&lt;/a&gt;. Recently, I have been
extending my use of it to include blogging and my emacs&amp;nbsp;config.
&lt;/p&gt;

&lt;p&gt;
Blogging with org-mode can be done using the &lt;a href="https://github.com/getpelican/pelican-plugins/tree/master/org_reader"&gt;org&lt;sub&gt;reader&lt;/sub&gt;&lt;/a&gt; plugin for &lt;a href="http://blog.getpelican.com"&gt;pelican&lt;/a&gt;.
There are other blog platforms that integrate org-mode, however this is the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;
&lt;a href="http://orgmode.org"&gt;Org-mode&lt;/a&gt; is a useful emacs mode for &lt;a href="http://pseudofish.com/using-deft-mode-for-notes-in-emacs.html"&gt;note taking&lt;/a&gt;. Recently, I have been
extending my use of it to include blogging and my emacs&amp;nbsp;config.
&lt;/p&gt;

&lt;p&gt;
Blogging with org-mode can be done using the &lt;a href="https://github.com/getpelican/pelican-plugins/tree/master/org_reader"&gt;org&lt;sub&gt;reader&lt;/sub&gt;&lt;/a&gt; plugin for &lt;a href="http://blog.getpelican.com"&gt;pelican&lt;/a&gt;.
There are other blog platforms that integrate org-mode, however this is the
one I&amp;#8217;m using. This means I can write an org-mode &lt;a href="https://github.com/gmwils/pseudofish/blob/master/content/musings/org-mode-for-everything.org"&gt;file&lt;/a&gt; that is generated into
the&amp;nbsp;blog.
&lt;/p&gt;

&lt;p&gt;
Using org-mode for emacs config is a good example of &lt;a href="https://en.wikipedia.org/wiki/Literate_programming"&gt;literate programming&lt;/a&gt;. It
is both easy to modify and self documenting. Github provides support for org
docs, so my emacs config is viewable &lt;a href="https://github.com/gmwils/dotfiles/blob/master/emacs.d/gmwils.org"&gt;here&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
By using org mode for config, it becomes normal to document why you have
particular configuration settings. Given how complex configuring emacs usually
is, this makes it more sane. The other win is that you can group settings by
using org&amp;nbsp;headings.
&lt;/p&gt;

&lt;p&gt;
I use &lt;a href="https://www.emacswiki.org/emacs/Yasnippet"&gt;yasnippet&lt;/a&gt; to automate creating most documents, such as a &lt;a href="https://github.com/gmwils/dotfiles/blob/master/emacs.d/snippets/org-mode/blog"&gt;blog&lt;/a&gt; entry.
This helps with not having to remember specific formatting or metadata for
different document types. This is useful for conducting interviews. I have
created org templates for each role with criteria I want to assess and
a range of questions. Then I just create a new doc, add the template, and&amp;nbsp;go.
&lt;/p&gt;
</content><category term="musings"></category></entry><entry><title>Choosing a Chinese name</title><link href="https://pseudofish.com/choosing-a-chinese-name.html" rel="alternate"></link><published>2015-01-06T00:00:00+01:00</published><updated>2015-01-06T00:00:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2015-01-06:/choosing-a-chinese-name.html</id><summary type="html">&lt;p&gt;The process I went through to pick a Chinese&amp;nbsp;name.&lt;/p&gt;</summary><content type="html">&lt;p&gt;My Chinese name is 周浩轩 (Zhōu hào&amp;nbsp;xuān).&lt;/p&gt;
&lt;p&gt;&lt;a href="http://eastasiastudent.net/china/how-to-get-a-chinese-name"&gt;Choosing a name&lt;/a&gt;
is hard. I had early Chinese names, but they were accidental. One from
Chinese class, where our teacher randomly gave us names, and one from my
translated Chinese business card ( 威尔森 - wēi ěr sēn -&amp;nbsp;Wilson).&lt;/p&gt;
&lt;p&gt;For the last &lt;a href="http://pseudofish.com/update-on-learning-chinese.html"&gt;year&lt;/a&gt;, I
have been working with the same tutor, and I asked her to help. Chinese names
are typically associated with meaning. To start, I listed out the sorts of
traits I valued in a name. From here, she came up with a list of around ten&amp;nbsp;suggestions.&lt;/p&gt;
&lt;p&gt;The challenge was which&amp;nbsp;one?&lt;/p&gt;
&lt;p&gt;I started by putting them all into a
&lt;a href="https://docs.google.com/spreadsheets/d/1Q_DtQpFfO_42wRcsqd6fYoflZOd7gzTSdEbLvtY9ha8/edit#gid=0"&gt;spreadsheet&lt;/a&gt;,
and expanding out pinyin, as I didn&amp;#8217;t know all the characters. I found that
you could check names on RenRen (&lt;a href="http://name.renren.com/"&gt;人人&lt;/a&gt;). This let me
figure out a rough popularity, and gender balance. For a final sanity check, I
also searched for the name on &lt;a href="http://image.baidu.com/"&gt;Baidu&lt;/a&gt; images to see
if there were any bad&amp;nbsp;associations.&lt;/p&gt;
&lt;p&gt;After gathering the data, I was down to two candidates, and picked the one
that I liked the characters&amp;nbsp;of.&lt;/p&gt;
&lt;p&gt;I decided on Zhou &lt;a href="http://en.m.wikipedia.org/wiki/Zhou_(surname)"&gt;周&lt;/a&gt; as a
surname by a more random approach. I looked through
&lt;a href="http://en.wikipedia.org/wiki/List_of_common_Chinese_surnames"&gt;two&lt;/a&gt;
&lt;a href="http://en.wikipedia.org/wiki/Chinese_surname"&gt;lists&lt;/a&gt; of popular Chinese
surnames. After avoiding names of friends, some musing, reading up on
history and famous people with particular names, I&amp;nbsp;picked.&lt;/p&gt;
&lt;p&gt;After I had picked, it was pointed out to me that the two characters in my
name reference two &lt;a href="https://en.wikipedia.org/wiki/Chengyu"&gt;chengyu&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浩如烟海 &amp;#8212; vast as the open&amp;nbsp;sea&lt;/li&gt;
&lt;li&gt;器宇轩昂 &amp;#8212; having a dignified&amp;nbsp;appearance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This adds a nice extra dimension to my&amp;nbsp;name.&lt;/p&gt;
&lt;p&gt;&amp;#8212;&amp;nbsp; 周浩轩&lt;/p&gt;</content><category term="chinese"></category></entry><entry><title>Triangle Heatmaps in R using ggplot</title><link href="https://pseudofish.com/triangle-heatmaps-in-r-using-ggplot.html" rel="alternate"></link><published>2014-10-25T00:00:00+02:00</published><updated>2014-10-25T00:00:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2014-10-25:/triangle-heatmaps-in-r-using-ggplot.html</id><summary type="html">&lt;p&gt;Using R to build triangle heatmaps to explore retention of multiple&amp;nbsp;cohorts.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently watched &lt;a href="https://twitter.com/alexschultz"&gt;Alex Schultz&amp;#8217;s&lt;/a&gt; lecture on
&lt;a href="http://startupclass.samaltman.com/courses/lec06/"&gt;Growth&lt;/a&gt;, and I was curious as
to how &lt;a href="https://www.facebook.com/video.php?v=3707283286197"&gt;triangle heatmaps&lt;/a&gt;
would look with our own cohort&amp;nbsp;data.&lt;/p&gt;
&lt;p&gt;Fortunately, ggplot and R make it very easy to build
&lt;a href="http://learnr.wordpress.com/2010/01/26/ggplot2-quick-heatmap-plotting/"&gt;heatmaps&lt;/a&gt;. The
tricky bit turned out to be creating some fake data to show how they&amp;nbsp;look.&lt;/p&gt;
&lt;p&gt;First import (and install if needed) the key&amp;nbsp;libraries.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ggplot2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, generate some test data, or load existing cohort data for your&amp;nbsp;company.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Generate decending values from 100 to 1 to simulate retention over time&lt;/span&gt;
&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;replicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;runif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;T&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# Make a triangle&lt;/span&gt;
&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;lower.tri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;NA&lt;/span&gt;

&lt;span class="c1"&gt;# Convert to a data frame, and add tenure labels&lt;/span&gt;
&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;as.data.frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;tenure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Reshape to suit ggplot, remove NAs, and sort the labels&lt;/span&gt;
&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;na.omit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;melt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;tenure&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;cohort&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;cohort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;cohort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;levels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;rev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;levels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;cohort&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The data shows a particular value for a given cohort across a number of&amp;nbsp;weeks.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;##    tenure cohort    value
## 1       0     V1 95.11190
## 16      0     V2 99.80269
## 17      1     V2 97.54479
## 31      0     V3 97.10274
## 32      1     V3 93.49820
## 33      2     V3 77.72841
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using ggplot&amp;#8217;s &lt;a href="http://docs.ggplot2.org/0.9.2.1/geom_tile.html"&gt;&lt;code&gt;geom_tile&lt;/code&gt;&lt;/a&gt;,
it is possible to generate a heatmap based on the&amp;nbsp;cohorts.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Triangle heatmap to compare cohorts&lt;/span&gt;
&lt;span class="nf"&gt;ggplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;aes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cohort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tenure&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ggtitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Retention by cohort&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;theme_bw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;xlab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Cohort&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;ylab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Tenure (weeks)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;geom_tile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;aes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;white&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;scale_fill_gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;white&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;darkblue&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;space&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Lab&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis.text.x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;element_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;axis.ticks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;element_blank&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;axis.line&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;element_blank&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;panel.border&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;element_blank&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;panel.grid.major&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;element_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;#eeeeee&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="plot of chunk heatmap" src="https://pseudofish.com/images/heatmap-1.png"&gt;&lt;/p&gt;
&lt;p&gt;With real data, it is easy to spot anomolies, leading to areas for
further investigation. For example, why did users who signed up in a
particular week retain better than other&amp;nbsp;weeks.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.facebook.com/photo.php?v=3707283286197"&gt;Danny Ferante&lt;/a&gt; explains
further ways of reading the heatmap in the
&lt;a href="https://www.facebook.com/photo.php?v=3707283286197"&gt;video&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I find the heatmap much easier to read than just plotting the&amp;nbsp;cohorts:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;ggplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rcohorts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;aes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;theme_bw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;geom_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;aes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cohort&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="plot of chunk plot" src="https://pseudofish.com/images/plot-1.png"&gt;&lt;/p&gt;</content><category term="data"></category></entry><entry><title>Downloading Google Analytics data from a Python script</title><link href="https://pseudofish.com/downloading-google-analytics-data-from-a-python-script.html" rel="alternate"></link><published>2014-09-22T00:00:00+02:00</published><updated>2014-09-22T00:00:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2014-09-22:/downloading-google-analytics-data-from-a-python-script.html</id><summary type="html">&lt;p&gt;Making use of Python to extract data from Google Analytics for further&amp;nbsp;analysis&lt;/p&gt;</summary><content type="html">&lt;p&gt;If you want to regularly extract data from Google Analytics, it is worthwhile
scripting the process. However, it was more complex than I&amp;nbsp;expected.&lt;/p&gt;
&lt;p&gt;I started with jaco&amp;#8217;s
&lt;a href="http://www.jaco.it/blog/2013/05/31/google-api-oauth-2-dot-0-the-short-way"&gt;post&lt;/a&gt;,
and then added some detail from&amp;nbsp;there.&lt;/p&gt;
&lt;h2&gt;Setting up your Google&amp;nbsp;account&lt;/h2&gt;
&lt;p&gt;Since Google has moved to OAuth2, you need a
&lt;a href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount"&gt;service account&lt;/a&gt;
to get a script to&amp;nbsp;work.&lt;/p&gt;
&lt;p&gt;There are a few steps to do from the
&lt;a href="https://console.developers.google.com/project"&gt;Google Developers Console&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a project (eg. GAStatistics). This step may take a minute or&amp;nbsp;two.&lt;/li&gt;
&lt;li&gt;From the project page, go to &lt;em&gt;APIs &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; auth -&amp;gt; APIs&lt;/em&gt;, and add permissions for
   the Analytics &lt;span class="caps"&gt;API&lt;/span&gt; (accepting the&amp;nbsp;T&amp;amp;Cs)&lt;/li&gt;
&lt;li&gt;From the Credentials section of &lt;em&gt;APIs &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; auth&lt;/em&gt;, create a new client &lt;span class="caps"&gt;ID&lt;/span&gt;, and pick
   Service Account when prompted. You should now automatically download a .p12
   file that includes your client ids and secret&amp;nbsp;keys.&lt;/li&gt;
&lt;li&gt;For your service account, save the email address that is generated. You&amp;#8217;ll
   use in a few&amp;nbsp;places.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Next you need grant your service account access to your Google Analytics&amp;nbsp;account.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;From &lt;a href="https://www.google.com/analytics/web"&gt;Google Analytics&lt;/a&gt;, pick the web
   property you want to gather data&amp;nbsp;from.&lt;/li&gt;
&lt;li&gt;Navigate to the Admin tab at the top, and then to the User Management
   section (you need to have permissions, otherwise ask your site&amp;nbsp;admin)&lt;/li&gt;
&lt;li&gt;Add your service account email to &lt;em&gt;Add permissions for:&lt;/em&gt;, and choose the
   type of permissions. I usually pick &lt;em&gt;Read &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Analyze&lt;/em&gt;, as I&amp;#8217;m paranoid about
   messing data up with a malformed&amp;nbsp;script.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From Google&amp;#8217;s side of things, you&amp;#8217;re ready to&amp;nbsp;go.&lt;/p&gt;
&lt;h2&gt;Starting a Python&amp;nbsp;project&lt;/h2&gt;
&lt;p&gt;First, you need to install the
&lt;a href="https://developers.google.com/api-client-library/python/"&gt;Google &lt;span class="caps"&gt;API&lt;/span&gt; Python client&lt;/a&gt;. I
use &lt;a href="http://docs.python-guide.org/en/latest/dev/virtualenvs/"&gt;virtualenv&lt;/a&gt;
for scripts so I can package dependencies, so my requirements.txt looks&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pyopenssl
google-api-python-client
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For service accounts, you need to use SignedJwtAssertionCredentials, which
needs pyopenssl to work. For details, see
&lt;a href="http://stackoverflow.com/questions/14063124/importerror-cannot-import-name-signedjwtassertioncredentials"&gt;this&lt;/a&gt;,
or just include&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;My script isn&amp;#8217;t too different from jaco&amp;#8217;s example, however I added a few
more things to get you&amp;nbsp;started.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class="c1"&gt;# -*- coding: utf-8; mode: python -*-&lt;/span&gt;
&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;Extract a snapshot of Google Analytics data.&lt;/span&gt;
&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;apiclient.discovery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;oauth2client.client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SignedJwtAssertionCredentials&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;oauth2client.file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;httplib2&lt;/span&gt;

&lt;span class="n"&gt;PRIVATE_KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;...&amp;gt;.p12&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# where you store your private key&lt;/span&gt;
&lt;span class="n"&gt;GSERVICE_EMAIL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;...&amp;gt;@developer.gserviceaccount.com&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;SITE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ga:&amp;lt;...&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# eg. ga:1234&lt;/span&gt;

&lt;span class="n"&gt;SCOPE_FEEDS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://www.google.com/analytics/feeds/&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;CREDENTIALS_STORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;credentials.dat&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# credentials cache file&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;private_key_filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="n"&gt;service_email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="n"&gt;credentials_store&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CREDENTIALS_STORE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;Authorise a service account against Google APIs&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;httplib2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Http&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credentials_store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;invalid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;private_key_filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SignedJwtAssertionCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service_email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                                        &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                                        &lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;print_data_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;Given the results from a query, print to screen.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;format_str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%25.24s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;format_str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%25s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rows&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# Print headers.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;columnHeaders&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format_str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# Print rows.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rows&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format_str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;No Results Found&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;print_top_pages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;Print out top X pages for a given site.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ga&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;start_date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;start_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;end_date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;end_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;dimensions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ga:hostname,ga:pagePath&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ga:pageviews&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-ga:pageviews&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ga:hostname!=localhost&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print_data_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PRIVATE_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GSERVICE_EMAIL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCOPE_FEEDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serviceName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;analytics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;v3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# TODO(gmwils): check if service is valid before continuing&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;31daysAgo&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;yesterday&amp;#39;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Top 10 pages&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print_top_pages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This structure gives a good starting point for playing around with different&amp;nbsp;queries.&lt;/p&gt;
&lt;p&gt;I did run into an issue where credentials wouldn&amp;#8217;t refresh from the
cache. This has been
&lt;a href="https://code.google.com/p/google-api-python-client/issues/detail?id=328"&gt;fixed&lt;/a&gt;,
but may need to patch&amp;nbsp;manually.&lt;/p&gt;
&lt;h2&gt;Calling Google Analytics from the &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;There is a lot of different things you can extract from &lt;span class="caps"&gt;GA&lt;/span&gt; &lt;a href="https://developers.google.com/analytics/devguides/reporting/core/v3/"&gt;Core Reporting &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;. I found it
very helpful to start with the
&lt;a href="https://developers.google.com/analytics/devguides/reporting/core/v3/common-queries"&gt;common queries&lt;/a&gt;
provided as&amp;nbsp;examples.&lt;/p&gt;
&lt;p&gt;There are also some
&lt;a href="https://developers.google.com/apis-explorer/#p/analytics/v3/"&gt;&lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;
&lt;a href="http://ga-dev-tools.appspot.com/explorer/"&gt;explorers&lt;/a&gt; that help with trying
queries&amp;nbsp;out.&lt;/p&gt;
&lt;p&gt;For extracting data out of the results, there is &lt;a href="https://developers.google.com/analytics/devguides/reporting/core/v3/coreDevguide#working"&gt;example code&lt;/a&gt;,
and details on the &lt;a href="https://developers.google.com/analytics/devguides/reporting/core/v3/reference#response_fields"&gt;response fields&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I found that I was often using filters to get at the data I wanted, and the
filter syntax is &lt;a href="https://developers.google.com/analytics/devguides/reporting/core/v3/reference#filters"&gt;documented&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some examples I found&amp;nbsp;useful:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ga:hostname!=localhost&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;exclude&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;development&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;data&lt;/span&gt;
&lt;span class="nt"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ga:source=~email&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;only&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;campaigns&lt;/span&gt;
&lt;span class="nt"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ga:source=~email;ga:campaign=~^\w&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;campaigns&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;non-blank&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;campaign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tag&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To avoid date arithmetic in Python, the &lt;span class="caps"&gt;API&lt;/span&gt; also allows
&lt;a href="https://developers.google.com/analytics/devguides/reporting/core/v3/reference#q_details"&gt;relative dates&lt;/a&gt;,
so you can write things&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;31daysAgo&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;yesterday&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can use the dimensions tag to split by additional fields, such as
&lt;code&gt;ga:campaign&lt;/code&gt; or &lt;code&gt;ga:date&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There are various selectors that can be used in queries, including ones for
custom variables, goals and dimensions. Our conversion team has several custom
goals setup, so I can query for the results&amp;nbsp;using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;metrics=&amp;#39;ga:goal07Completions,ga:goal07Starts,ga:goal07ConversionRate&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I feel like I&amp;#8217;m only scratching the surface with Google Analytics every time I
use it. Figuring out scripting allows me to dig into further integrations for
our normal&amp;nbsp;workflows.&lt;/p&gt;</content><category term="python"></category></entry><entry><title>The design of work teams</title><link href="https://pseudofish.com/the-design-of-work-teams.html" rel="alternate"></link><published>2014-09-07T00:00:00+02:00</published><updated>2014-09-07T00:00:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2014-09-07:/the-design-of-work-teams.html</id><summary type="html">&lt;p&gt;Research from J. Richard Hackman on the design of work teams helps inform the why behind much of&amp;nbsp;agile.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Modern work is all about teams. They are at the core of agile&amp;nbsp;development.&lt;/p&gt;
&lt;p&gt;To help better understand how design effective work teams, it is worth reading
through J. Richard Hackman&amp;#8217;s 1987 research paper:
&lt;a href="http://groupbrain.wjh.harvard.edu/jrh/pub/JRH1987_1.pdf"&gt;The design of work teams&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The paper is dense reading, so I extracted some relevant sections for future&amp;nbsp;reference.&lt;/p&gt;
&lt;h2&gt;Background&amp;nbsp;research&lt;/h2&gt;
&lt;p&gt;From the summary of earlier research, I found this&amp;nbsp;interesting:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In sum, research findings regarding process interventions suggest that
structured techniques that minimize process losses (or reduce their effects)
can be helpful. On the other hand, interventions that attempt to improve the
quality of interpersonal relations among members to promote synergistic
&amp;#8220;process gains&amp;#8221; appear not to yield reliable improvements in group task&amp;nbsp;effectiveness.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is, there is more improvements to gain from the lean approach to reducing
waste, and less from the common soft approaches to improving team&amp;nbsp;interactions.&lt;/p&gt;
&lt;h2&gt;A Normative Model of Group&amp;nbsp;Effectiveness&lt;/h2&gt;
&lt;p&gt;The goal of the paper is to create a model of group effectiveness, based on
research, such&amp;nbsp;that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The variables used in the model make non-trivial difference to group&amp;nbsp;performance&lt;/li&gt;
&lt;li&gt;It is feasible to change them in an&amp;nbsp;organization&lt;/li&gt;
&lt;li&gt;People can understand and use&amp;nbsp;them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To be effective, the model is restricted to work groups in
organizations. Fortunately, this is the circumstances most of us find
ourselves&amp;nbsp;in.&lt;/p&gt;
&lt;p&gt;Hackman goes on to propose that the overall effectiveness of work groups in
organizations is a joint function&amp;nbsp;of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The level of &lt;em&gt;effort&lt;/em&gt; group members collectively expend carrying out task&amp;nbsp;work,&lt;/li&gt;
&lt;li&gt;The amount of &lt;em&gt;knowledge and skill&lt;/em&gt; members bring to bear on the group task,&amp;nbsp;and&lt;/li&gt;
&lt;li&gt;The appropriateness to the task of the &lt;em&gt;performance strategies&lt;/em&gt; used by the
  group in its&amp;nbsp;work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are the hurdles a group must surmount to be effective, however don&amp;#8217;t
provide clear ways of modifying group behaviour. Instead, he goes on to
examine the impact of the following classes of&amp;nbsp;variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;em&gt;design of the group&lt;/em&gt; as a performing unit: the structure of the group
  task, the composition of the group, and the group norms that regulate member&amp;nbsp;behaviour&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;organizational context&lt;/em&gt; of the group: the reward, education, and
  information systems that influence the group, and the material resources
  that are put at the group&amp;#8217;s&amp;nbsp;disposal&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Group synergy&lt;/em&gt; resulting from members&amp;#8217; interactions as they carry out the&amp;nbsp;task&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Conditions that support&amp;nbsp;effort&lt;/h3&gt;
&lt;p&gt;To expect a group to work hard on the group task, the following should be&amp;nbsp;met:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The group task requires members to use a variety of relatively &lt;em&gt;high-level
  skills&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The group task is a &lt;em&gt;whole and meaningful&lt;/em&gt; piece of work, with a &lt;em&gt;visible
  outcome&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The outcomes of the group&amp;#8217;s work on the task have &lt;em&gt;significant consequences&lt;/em&gt;
  for other people (eg. other organisation members or external&amp;nbsp;clients)&lt;/li&gt;
&lt;li&gt;The task provides group members with &lt;em&gt;substantial autonomy&lt;/em&gt; for deciding about
  hwo they do the work &amp;#8212; in effect, the group &amp;#8220;owns&amp;#8221; the task and is
  responsible for the work&amp;nbsp;outcomes.&lt;/li&gt;
&lt;li&gt;Work on the task generates &lt;em&gt;regular, trustworthy feedback&lt;/em&gt; about how well the
  group is&amp;nbsp;performing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If a group task meets these criteria, it is likely that members will
experience their work as meaningful and feel collectively
responsible. Improving the design of a group&amp;#8217;s work is usually a better way to
foster high collective effort than directly addressing group norms about&amp;nbsp;productivity.&lt;/p&gt;
&lt;h3&gt;Organisational&amp;nbsp;context&lt;/h3&gt;
&lt;p&gt;Providing a supportive environment for teams becomes the key responsibility of
an&amp;nbsp;organisation.&lt;/p&gt;
&lt;p&gt;Reward systems that support high effort by teams tend to have the following
three&amp;nbsp;features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Challenging, specific performance&amp;nbsp;objectives&lt;/li&gt;
&lt;li&gt;Positive consequences for excellent&amp;nbsp;performance&lt;/li&gt;
&lt;li&gt;Rewards and objectives that focus on group, not individual,&amp;nbsp;behaviour&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The destructive effects of rewarding individual rather than team performance
can be&amp;nbsp;considerable.&lt;/p&gt;
&lt;h3&gt;Group&amp;nbsp;synergy&lt;/h3&gt;
&lt;p&gt;Group synergy can contribute in two ways, either by avoiding process losses or
by finding ways to create new internal resources that can be used in their
work &amp;#8212; capabilities that did not exist before the group created&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;It is not clear that building a great &amp;#8220;spirit&amp;#8221; in the team is sustainable or
if that commitment is sustainable if performance conditions remain&amp;nbsp;poor.&lt;/p&gt;
&lt;p&gt;Some other&amp;nbsp;considerations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minimise inappropriate weighting of member&amp;nbsp;contributions&lt;/li&gt;
&lt;li&gt;Foster collective&amp;nbsp;learning&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Design of the&amp;nbsp;group&lt;/h3&gt;
&lt;p&gt;A group&amp;#8217;s composition is the most important condition. Well-composed groups
have the following&amp;nbsp;characteristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Individual members have high task-relevant&amp;nbsp;expertise&lt;/li&gt;
&lt;li&gt;The group is large enough to do the work (but no&amp;nbsp;bigger)&lt;/li&gt;
&lt;li&gt;Members have interpersonal as well as task&amp;nbsp;skills&lt;/li&gt;
&lt;li&gt;Membership is moderately diverse (enough diversity to cover needed talent,
  yet similar enough to allow understanding and&amp;nbsp;co-ordination)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Task appropriate&amp;nbsp;performance&lt;/h2&gt;
&lt;p&gt;To support a task appropriate performance strategy, some other factors to&amp;nbsp;consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Design of the group&lt;ul&gt;
&lt;li&gt;Group norms support&amp;nbsp;self-regulation&lt;/li&gt;
&lt;li&gt;Group norms suport situational scanning and strategic&amp;nbsp;planning&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Organisational context&lt;ul&gt;
&lt;li&gt;Clarity about the parameters of the performance&amp;nbsp;situation&lt;/li&gt;
&lt;li&gt;Access to data about likely consequences of alternative&amp;nbsp;strategies&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Group synergy&lt;ul&gt;
&lt;li&gt;Minimizing slippage in strategy implementation (eg. get to value&amp;nbsp;quickly)&lt;/li&gt;
&lt;li&gt;Creating innovative strategic&amp;nbsp;plans&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Excellent group performance requires &lt;em&gt;both&lt;/em&gt; a good design for the team and a
supportive organisation. Group synergy then acts as an amplifier to tune the
impact of design and&amp;nbsp;context.&lt;/p&gt;
&lt;h2&gt;An Action Model for Improving Group&amp;nbsp;Effectiveness&lt;/h2&gt;
&lt;p&gt;The normative model (above) helps understand what conditions should be
present. The next step is a theory of action as to how to create teams that
fit the&amp;nbsp;model.&lt;/p&gt;
&lt;h3&gt;Diagnosis of existing&amp;nbsp;teams&lt;/h3&gt;
&lt;p&gt;The approach to diagnosis depends on the organisational structure,
particularly the distribution of authority, and the tasks assigned
to the&amp;nbsp;team.&lt;/p&gt;
&lt;p&gt;Most agile teams are self-managing work groups, where the team members
themselves are responsible for monitoring and managing their own processes as
well as executing on the&amp;nbsp;task.&lt;/p&gt;
&lt;p&gt;Their performance depends on the quality of team design, the organisational
context, &lt;em&gt;and&lt;/em&gt; on the competence of teh group in managing and executing its&amp;nbsp;work.&lt;/p&gt;
&lt;p&gt;Some teams are self-designing, where management&amp;#8217;s role is limited to the
team&amp;#8217;s organisational&amp;nbsp;context.&lt;/p&gt;
&lt;h3&gt;Creating new&amp;nbsp;teams&lt;/h3&gt;
&lt;p&gt;The short version is that you should create teams that rank high on each of
the variables in the model. There is much more detail in the article, broken
down into four&amp;nbsp;stages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Prework&lt;/li&gt;
&lt;li&gt;Creating performance&amp;nbsp;conditions&lt;/li&gt;
&lt;li&gt;Forming and building the&amp;nbsp;team&lt;/li&gt;
&lt;li&gt;Providing on-going&amp;nbsp;assistance&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once a group is functioning as a social system, it will largely control its
own destiny. Managers can assist the group by making it easy for members to
re-negotiate situations that impede performance, by ensuring members get
on-going assistance to operate as a team, and by helping the group learn from
its&amp;nbsp;experiences.&lt;/p&gt;
&lt;h2&gt;Management of&amp;nbsp;teams&lt;/h2&gt;
&lt;h3&gt;On&amp;nbsp;leadership&lt;/h3&gt;
&lt;p&gt;Most research has focused on what leaders do within groups, however in this
context, leadership has the most influence in how to frame the groups task,
structure the group, its context, and to help get the group up and&amp;nbsp;running.&lt;/p&gt;
&lt;p&gt;It is not required to have an explicit leader within the group, although this
may make sense if substantial co-ordination is required. This is something
that should arise from within the group rather than be decided in&amp;nbsp;advance.&lt;/p&gt;
&lt;h3&gt;On Creating Redundant&amp;nbsp;Conditions&lt;/h3&gt;
&lt;p&gt;There are many ways for a group to be effective, and even more for it to be
ineffective. Thus, it is impossible to specify in detail specific behaviours
managers should adopt to help groups perform&amp;nbsp;effectively.&lt;/p&gt;
&lt;p&gt;Based on the model and research, the key to effective group management may be
to create redundant conditions that support good performance, leaving groups
room to develop and enact their own ways of operating within those&amp;nbsp;conditions.&lt;/p&gt;
&lt;p&gt;Group performance does not have clean, unitary causes. To help a group improve
its effectiveness involves doing whatever is possible to create multiple,
redundant conditions that together may nudge the group toward more competent
task behaviour and, eventually, better&amp;nbsp;performance.&lt;/p&gt;
&lt;h3&gt;On Managerial&amp;nbsp;Authority&lt;/h3&gt;
&lt;p&gt;Given the increase in autonomy and empowerment of teams, this suggests that
management attention be re-directed towards improving organisational
conditions that foster and support effective group&amp;nbsp;behaviour.&lt;/p&gt;
&lt;p&gt;Managerial authority should also be used to establish and enforce standards of
group behaviour and acceptable performance. Being vague can be as bad to a
group as traditional hands-on supervision. To enable groups to use their
authority well, managers must not be afraid to exercise their&amp;nbsp;own.&lt;/p&gt;
&lt;h3&gt;On Knowing Some&amp;nbsp;Things&lt;/h3&gt;
&lt;p&gt;This approach to managing effective teams may require unfamiliar and seemingly
awkard management behaviours. To manage teams well, one needs to know some
things, have some skills and have opportunities to&amp;nbsp;practice.&lt;/p&gt;
&lt;p&gt;Investment in training, mentoring and coaching of managagers will result in
those who are expert in creating work teams, developing them, and harvesting
the considerable contributions they have to make to organisational&amp;nbsp;effectiveness.&lt;/p&gt;
&lt;h2&gt;Further&amp;nbsp;reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="http://www.amazon.com/Leading-Teams-Setting-Stage-Performances/dp/1578513332/pseudofish-20"&gt;Leading Teams&lt;/a&gt;
    &amp;#8212; Hackman&amp;#8217;s continued refinement of his model, including&amp;nbsp;examples.&lt;/p&gt;
&lt;p&gt;The book distills the enabling conditions down to: A Real
Team, Compelling Direction, Enabling Structure, Supportive Context, Expert&amp;nbsp;Coaching&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="http://www.estherderby.com/2011/11/miss-the-start-miss-the-end.html"&gt;Building Effective Teams: Miss the Start, Miss the&amp;nbsp;End&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;60% of the variation in team effectiveness is attributable to the design
of the team, 30% to the way the team is launched, and 10% to leader
coaching once the team is&amp;nbsp;underway.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="http://blogs.hbr.org/2011/06/six-common-misperceptions-abou/"&gt;Six Common Misperceptions about Teamwork&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you to &lt;a href="http://blog.crisp.se/author/peterantman"&gt;Peter Antman&lt;/a&gt; for the
recommendation to look into Hackman&amp;#8217;s&amp;nbsp;work.&lt;/p&gt;</content><category term="agile"></category></entry><entry><title>Analysing Skritter time series data with R</title><link href="https://pseudofish.com/analysing-skritter-time-series-data-with-r.html" rel="alternate"></link><published>2014-05-31T00:00:00+02:00</published><updated>2014-05-31T00:00:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2014-05-31:/analysing-skritter-time-series-data-with-r.html</id><summary type="html">&lt;p&gt;Using the great time series functions in R, analyse learning data from Skritter&amp;nbsp;usage.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.skritter.com/home"&gt;Skritter&lt;/a&gt; tracks data on my Chinese study while
I use it. With their new &lt;a href="http://www.skritter.com/api/v0/docs"&gt;&lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;, I can make use of
&lt;a href="http://www.r-project.org/"&gt;R&lt;/a&gt; to try and spot some&amp;nbsp;trends.&lt;/p&gt;
&lt;p&gt;With emacs, try out
&lt;a href="http://stats.blogoverflow.com/2011/08/using-emacs-to-work-with-r/"&gt;&lt;span class="caps"&gt;ESS&lt;/span&gt; mode&lt;/a&gt;. &lt;code&gt;C-c
C-l&lt;/code&gt; loads the current buffer into an &lt;span class="caps"&gt;ESS&lt;/span&gt; buffer running&amp;nbsp;R.&lt;/p&gt;
&lt;h2&gt;Downloading the&amp;nbsp;data&lt;/h2&gt;
&lt;p&gt;Using a &lt;a href="https://github.com/gmwils/skritter"&gt;client&lt;/a&gt; for the Skritter &lt;span class="caps"&gt;API&lt;/span&gt;,
you can download either
&lt;a href="http://www.skritter.com/api/v0/docs/endpoints/progress_stats"&gt;progress stats&lt;/a&gt;
or every &lt;a href="http://www.skritter.com/api/v0/docs/endpoints/items"&gt;item&lt;/a&gt; you&amp;#8217;ve
ever studied. I chose to start with progress&amp;nbsp;statistics.&lt;/p&gt;
&lt;p&gt;The script I used is available
&lt;a href="https://github.com/gmwils/skritter/blob/master/examples/progress_stats.py"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is a lot of data returned across three&amp;nbsp;dimensions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;word and character level&amp;nbsp;stats&lt;/li&gt;
&lt;li&gt;definition, reading, writing (rune), and&amp;nbsp;tone&lt;/li&gt;
&lt;li&gt;learned, learning, remembered, and studied&amp;nbsp;items&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition, there is the number of days studied, and the time studied in
seconds. You can request by day, week or month, with different&amp;nbsp;limits.&lt;/p&gt;
&lt;p&gt;I wanted as long a timespan as possible, so downloaded two years of data at
month granularity. I then dumped it all into a &lt;span class="caps"&gt;CSV&lt;/span&gt; file, with a header&amp;nbsp;row.&lt;/p&gt;
&lt;p&gt;For&amp;nbsp;example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;date,client,days studied,time studied,word defn learned,...
2012-05-01,,0,0.0,0,...
2012-06-01,,18,25669.0,...
2012-07-01,,48,57054.0,...
2012-08-01,,79,96913.0,...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Loading into&amp;nbsp;R&lt;/h2&gt;
&lt;p&gt;Loading the data into R is&amp;nbsp;straightforward.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;skritter.raw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;read.csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;data/skritter_stats.csv&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The data is now all in one&amp;nbsp;place:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;colnames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skritter.raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;##  [1] &amp;quot;date&amp;quot;                    &amp;quot;client&amp;quot;                 
##  [3] &amp;quot;days.studied&amp;quot;            &amp;quot;time.studied&amp;quot;           
##  [5] &amp;quot;word.defn.learned&amp;quot;       &amp;quot;word.defn.learning&amp;quot;     
##  [7] &amp;quot;word.defn.remembered&amp;quot;    &amp;quot;word.defn.studied&amp;quot;      
##  [9] &amp;quot;word.reading.learned&amp;quot;    &amp;quot;word.reading.learning&amp;quot;  
## [11] &amp;quot;word.reading.remembered&amp;quot; &amp;quot;word.reading.studied&amp;quot;   
## [13] &amp;quot;word.rune.learned&amp;quot;       &amp;quot;word.rune.learning&amp;quot;     
## [15] &amp;quot;word.rune.remembered&amp;quot;    &amp;quot;word.rune.studied&amp;quot;      
## [17] &amp;quot;word.tone.learned&amp;quot;       &amp;quot;word.tone.learning&amp;quot;     
## [19] &amp;quot;word.tone.remembered&amp;quot;    &amp;quot;word.tone.studied&amp;quot;      
## [21] &amp;quot;char.defn.learned&amp;quot;       &amp;quot;char.defn.learning&amp;quot;     
## [23] &amp;quot;char.defn.remembered&amp;quot;    &amp;quot;char.defn.studied&amp;quot;      
## [25] &amp;quot;char.reading.learned&amp;quot;    &amp;quot;char.reading.learning&amp;quot;  
## [27] &amp;quot;char.reading.remembered&amp;quot; &amp;quot;char.reading.studied&amp;quot;   
## [29] &amp;quot;char.rune.learned&amp;quot;       &amp;quot;char.rune.learning&amp;quot;     
## [31] &amp;quot;char.rune.remembered&amp;quot;    &amp;quot;char.rune.studied&amp;quot;      
## [33] &amp;quot;char.tone.learned&amp;quot;       &amp;quot;char.tone.learning&amp;quot;     
## [35] &amp;quot;char.tone.remembered&amp;quot;    &amp;quot;char.tone.studied&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Cleaning up the&amp;nbsp;data&lt;/h2&gt;
&lt;p&gt;Given that this is a time series, that is the first transformation to&amp;nbsp;make:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;skritter.cumulative&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skritter.raw&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2012&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frequency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;ts&lt;/code&gt; function converts the data frame into a time series object. I strip
out the first column (&lt;code&gt;skritter.raw[,-1]&lt;/code&gt;), as the time information is now in
the time&amp;nbsp;series.&lt;/p&gt;
&lt;p&gt;Examining a column shows that the data is&amp;nbsp;cumulative:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;skritter.cumulative&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;word.tone.remembered&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;##        Jan   Feb   Mar   Apr   May   Jun   Jul   Aug   Sep   Oct   Nov
## 2012                             0   269   776  1368  2322  3357  4161
## 2013  5838  6480  7136  8455  9490 10844 12310 13954 16252 18175 20265
## 2014 23703 25574 27319 28972 30694                                    
##        Dec
## 2012  5226
## 2013 22002
## 2014
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To get the increment per month, we can subtract the time series from itself
with a lag introduced. Time series in R use different functions than data
frames, so double check you still have a time series (eg. &lt;code&gt;is.ts(...)&lt;/code&gt;).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skritter.cumulative&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;difference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;word.tone.remembered&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;##       Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec
## 2012                           269  507  592  954 1035  804 1065
## 2013  612  642  656 1319 1035 1354 1466 1644 2298 1923 2090 1737
## 2014 1701 1871 1745 1653 1722
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;is.ts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;## [1] TRUE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now all the columns show the increase (or decrease) per month, while remaining
a time&amp;nbsp;series.&lt;/p&gt;
&lt;h2&gt;Visualising&amp;nbsp;trends&lt;/h2&gt;
&lt;p&gt;The actual numbers aren&amp;#8217;t so interesting, as they correlate to the amount of
time&amp;nbsp;spent.&lt;/p&gt;
&lt;p&gt;To see the relationship between two series,&amp;nbsp;try:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days.studied&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;word.rune.remembered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="plot of chunk days_studied" src="https://pseudofish.com/images/days_studied.png"&gt;&lt;/p&gt;
&lt;p&gt;However, the number of days isn&amp;#8217;t as useful as the actual time&amp;nbsp;spent:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time.studied&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;word.rune.remembered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="plot of chunk time_studied" src="https://pseudofish.com/images/time_studied.png"&gt;&lt;/p&gt;
&lt;p&gt;The next thing is to compare the ratios between time spent and aspects of
studying. To simplify, I used a function to extract parts of the&amp;nbsp;data:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;extractsummary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aspect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;remembered&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;word&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ts.union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;paste&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;reading&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aspect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;tone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;paste&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tone&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aspect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rune&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;paste&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rune&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aspect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;paste&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;defn&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aspect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;paste&lt;/code&gt; is used to construct the column&amp;nbsp;names:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;paste&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;word&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;reading&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;remembered&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;## [1] &amp;quot;word.reading.remembered&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And grabbed data for both words and characters&amp;nbsp;remembered:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;word.remembered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;extractsummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;char.remembered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;extractsummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;char&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;R can operate across all the columns at the same time. This
makes it easy to plot the number of character aspects remembered
per hour of&amp;nbsp;study.&lt;/p&gt;
&lt;p&gt;The column names need to be re-added, so they show as plot&amp;nbsp;labels.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;char.remembered.per.hour&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char.remembered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;time.studied&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;colnames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char.remembered.per.hour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;colnames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char.remembered&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char.remembered.per.hour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Character aspects remembered per hour&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="plot of characters remembered per hour" src="https://pseudofish.com/images/chars_per_hour.png"&gt;&lt;/p&gt;
&lt;p&gt;Looking at the plot, I seem to be improving the number of tones that I
learn per hour, and slightly improving on how fast I learn new writings. Definitions
and reading seem to have taken about the same time across two&amp;nbsp;years.&lt;/p&gt;
&lt;p&gt;Repeating for&amp;nbsp;words:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;word.remembered.per.hour&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word.remembered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;time.studied&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;colnames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word.remembered.per.hour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;colnames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word.remembered&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word.remembered.per.hour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Word aspects remembered per hour&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="plot of words rememberd per hour" src="https://pseudofish.com/images/word_per_hour.png"&gt;&lt;/p&gt;
&lt;p&gt;There are a few other plots that are&amp;nbsp;useful.&lt;/p&gt;
&lt;p&gt;For example, looking at the words learned by&amp;nbsp;season:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;seasonplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;word.tone.learned&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="seasonplot of word tones learned" src="https://pseudofish.com/images/seasonal1.png"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;monthplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skritter&lt;/span&gt;&lt;span class="p"&gt;[,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;word.tone.learned&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="monthplot of word tones learned" src="https://pseudofish.com/images/seasonal2.png"&gt;&lt;/p&gt;
&lt;p&gt;Looking at these, I seem to put more time into Chinese study during August,
September and&amp;nbsp;October.&lt;/p&gt;
&lt;h2&gt;Further&amp;nbsp;reading&lt;/h2&gt;
&lt;p&gt;These articles and PDFs helped me understand how and why time series in R are&amp;nbsp;useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.otexts.org/fpp"&gt;Forecasting: principles and practice&lt;/a&gt; &amp;#8212; there
  is so much in this free online&amp;nbsp;book.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.otexts.org/fpp/using-r"&gt;Fpp - Using R&lt;/a&gt; &amp;#8212; crash course in time
  series for&amp;nbsp;R.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://people.su.se/~lundh/reproduce/introduction_ts.pdf"&gt;Introduction to R&amp;#8217;s time series facilities&lt;/a&gt;
  &amp;#8212; an ebook, helpful for converting mathematical functions to R time&amp;nbsp;series.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To generate this post, I used &lt;a href="http://kbroman.github.io/knitr_knutshell/pages/Rmarkdown.html"&gt;RMarkdown&lt;/a&gt;.&lt;/p&gt;</content><category term="data"></category></entry><entry><title>Update on learning Chinese</title><link href="https://pseudofish.com/update-on-learning-chinese.html" rel="alternate"></link><published>2014-01-26T00:00:00+01:00</published><updated>2014-01-26T00:00:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2014-01-26:/update-on-learning-chinese.html</id><summary type="html">&lt;p&gt;New approaches, and refining how I&amp;nbsp;study&lt;/p&gt;</summary><content type="html">&lt;p&gt;This year I started online Chinese lessons and continue with reading,
listening &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; learning&amp;nbsp;vocabulary.&lt;/p&gt;
&lt;p&gt;My goal is to be able to read &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; write, however I should also be comfortable
chatting in Chinese. I am not good at listening and replying in a reasonable
time, making conversation&amp;nbsp;stilted.&lt;/p&gt;
&lt;h2&gt;Online&amp;nbsp;Lessons&lt;/h2&gt;
&lt;p&gt;My wife challenged me this year to start lessons, sending me links to a few
services. After
&lt;a href="http://yago.sg/blog/learning-chinese-online-a-comparison-of-3-services/"&gt;some&lt;/a&gt; &lt;a href="http://learn-chinese-review.toptenreviews.com/"&gt;research&lt;/a&gt;, I picked two to&amp;nbsp;try.&lt;/p&gt;
&lt;p&gt;The first
&lt;a href="http://www.digmandarin.com/learning-mandarin-online-teacher-vs-school.html"&gt;choice&lt;/a&gt;
was between an independent teacher or an online school. An independent teacher
will be cheaper and more flexible, and the school is more&amp;nbsp;reliable.&lt;/p&gt;
&lt;p&gt;I chose to start with a&amp;nbsp;school.&lt;/p&gt;
&lt;p&gt;I then did trial lessons with
&lt;a href="http://www.echineselearning.com/price.html"&gt;eChineseLearning&lt;/a&gt; and
&lt;a href="http://www.chinesehour.com/accounts/payment/prices/"&gt;Chinese Hour&lt;/a&gt;. Each
trial lesson went for around 30 minutes followed by a sales person trying to
get me to sign-up. I chose to go with Chinese Hour. They have few features,
good teachers and flexible&amp;nbsp;pricing.&lt;/p&gt;
&lt;p&gt;I have class via Skype once a week for an hour. After general conversation, we
go over particular lessons, such as reading a joke in Chinese and then
answering questions about it. Early results are positive. I am more confident
speaking, and my grammar is&amp;nbsp;improving.&lt;/p&gt;
&lt;p&gt;Make sure you know what your goals are, and use them to guide the type of
service you&amp;nbsp;choose.&lt;/p&gt;
&lt;p&gt;Other services to look&amp;nbsp;into:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://popupchinese.com/help/university"&gt;Popup&amp;nbsp;Chinese&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://chinesepod.com/store/classes"&gt;ChinesePod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.italki.com/teachers/tutoring"&gt;iTalki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.chinesehorizon.com/"&gt;Chinese&amp;nbsp;Horizon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Reading&lt;/h2&gt;
&lt;p&gt;I finished three books last year: a book of Chinese stories for children, Alice in Wonderland (&lt;a href="http://www.amazon.cn/gp/product/B008LQ30HU"&gt;爱丽丝漫游奇境记&lt;/a&gt;) and Around
the World in 80 Days (80 天环游地球 ). Now, I&amp;#8217;m reading Treasure Island
(&lt;a href="http://www.amazon.cn/gp/product/B008LQ3ACU"&gt;金银岛&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been reading children&amp;#8217;s books that include both characters and
pinyin. My challenge for later this year is to switch to reading novels without&amp;nbsp;pinyin.&lt;/p&gt;
&lt;p&gt;I find that the first part of the book can be slow going. After a while, I
learn the author&amp;#8217;s style, key vocabulary, and it becomes faster and more&amp;nbsp;fun.&lt;/p&gt;
&lt;h3&gt;Finding&amp;nbsp;books&lt;/h3&gt;
&lt;p&gt;When I started, I found it a challenge to get copies of things to read in
Chinese. Now, I&amp;#8217;ve moved to using e-books&amp;nbsp;( 电子书 ).&lt;/p&gt;
&lt;p&gt;Amazon has a good range, but has limited catalogue if you are
outside of China. &lt;a href="http://wandoujia.com/"&gt;Wandoujia&lt;/a&gt; seems to have lots of
books that are free, although I&amp;#8217;m not sure of their quality, and you&amp;#8217;ll need
an Android device to download them. Sina also has a book store,
&lt;a href="http://book.sina.com.cn/"&gt;新浪读书&lt;/a&gt;, that includes both iOS and Android&amp;nbsp;apps.&lt;/p&gt;
&lt;p&gt;HackingChinese is focused on reading during January and has some
&lt;a href="http://www.hackingchinese.com/easing-yourself-into-reading-novels-in-chinese/"&gt;suggestions&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Vocabulary&lt;/h2&gt;
&lt;p&gt;I doubled my vocabulary across the last year, and I owe that achievement to
&lt;a href="http://www.skritter.com/"&gt;Skritter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Skritter stats" src="https://pseudofish.com/images/2013-SkritterUsage.png"&gt;&lt;/p&gt;
&lt;p&gt;Skritter fits nicely into my day. Small bits of time while commuting, or between meetings
or just before sleep, and I end up with around 12 hours a&amp;nbsp;month.&lt;/p&gt;
&lt;p&gt;As I read or hear new words, I add them into my dictionary and then export
them across into Skritter word lists. I find that writing the characters helps
with learning the structure and improving my reading&amp;nbsp;speed.&lt;/p&gt;
&lt;h2&gt;Listening&lt;/h2&gt;
&lt;p&gt;I increased the amount of Chinese listening in my day through
&lt;a href="http://www.chinesepod.com"&gt;podcasts&lt;/a&gt; and&amp;nbsp;music.&lt;/p&gt;
&lt;p&gt;I started with a rather open approach to exploring any music that happened to be
in Mandarin, and then narrowed down to music that I enjoy. Spotify has reasonable
coverage of Mandarin language music due to our launches in Taiwan, Singapore
and&amp;nbsp;Malaysia.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re interested, check out this
&lt;a href="http://open.spotify.com/user/gmwils/playlist/1hTM6JEJFoFwn1rzMjOLBS"&gt;playlist&lt;/a&gt;,
and
&lt;a href="http://www.hackingchinese.com/why-learning-chinese-through-music-is-underrated/"&gt;these&lt;/a&gt;
&lt;a href="http://www.hackingchinese.com/14-extra-songs-to-learn-chinese-and-expand-your-horizons/"&gt;articles&lt;/a&gt;
on Hacking Chinese. I also started using &lt;a href="http://www.xiami.com/"&gt;Xiami&lt;/a&gt; and
Sina Weibo (&lt;a href="http://music.weibo.com/"&gt;微博&lt;/a&gt;) to discover and follow mainland&amp;nbsp;artists.&lt;/p&gt;</content><category term="chinese"></category></entry><entry><title>Changing Names</title><link href="https://pseudofish.com/changing-names.html" rel="alternate"></link><published>2013-12-15T00:00:00+01:00</published><updated>2013-12-15T00:00:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2013-12-15:/changing-names.html</id><summary type="html">&lt;p&gt;Changing my name to van der&amp;nbsp;Meer.&lt;/p&gt;</summary><content type="html">&lt;p&gt;After filling in many forms, I am now Geoff van der&amp;nbsp;Meer.&lt;/p&gt;
&lt;p&gt;The paperwork part of the story is long, uninteresting, and never
ending. Changing ones name as an Australian while living in Sweden just isn&amp;#8217;t&amp;nbsp;simple.&lt;/p&gt;
&lt;p&gt;The why is shorter. My wife and I chose to use van der Meer, my
mother-in-law&amp;#8217;s maiden name, as the family name for our future children. van
der Meer is a Dutch surname, and translates to English as &amp;#8220;of the&amp;nbsp;lake&amp;#8221;.&lt;/p&gt;
&lt;p&gt;My wife changed her name earlier this year.  This left me with a few choices:
either keep my current name and be different from my family, hyphenate things,
or change my&amp;nbsp;name.&lt;/p&gt;
&lt;p&gt;The idea of having &amp;#8220;Wilson-van der Meer&amp;#8221; as a name didn&amp;#8217;t resonate. Neither
did having a different name from my immediate&amp;nbsp;family.&lt;/p&gt;
&lt;p&gt;So, a bunch of bureaucracy later, I have a new&amp;nbsp;name.&lt;/p&gt;
&lt;p&gt;I will still keep &lt;em&gt;gmwils&lt;/em&gt;. That was allocated to me at university,
and has been my username, email address, Twitter name and many other
identifiers for more years than I care to&amp;nbsp;count.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>A History of Modern China</title><link href="https://pseudofish.com/a-history-of-modern-china.html" rel="alternate"></link><published>2013-09-15T00:00:00+02:00</published><updated>2013-09-15T00:00:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2013-09-15:/a-history-of-modern-china.html</id><summary type="html">&lt;p&gt;Three books that provide insight into modern Chinese&amp;nbsp;history&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Wealth and Power ( 富强 ): China&amp;#8217;s Long March to the Twenty-first&amp;nbsp;Century&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.amazon.com/gp/product/0679643478/ref=as_li_ss_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0679643478&amp;amp;linkCode=as2&amp;amp;tag=pseudofish-20"&gt;Wealth and Power&lt;/a&gt;
is a fascinating book, covering the philosophies of 11 leading thinkers and
spanning from the Opium Wars in the 1800s through to modern&amp;nbsp;times.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As the dramatis personae of this book abundantly illustrate, China’s modern
thinkers and leaders, smarting from the humiliation of precipitous decline and
foreign incursion, had their own more immediate and urgent goal, namely, the
restoration of national wealth, power and&amp;nbsp;greatness.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This book requires that you have a reasonable knowledge of
&lt;a href="http://chinahistorypodcast.com/"&gt;Chinese history&lt;/a&gt;, and is stronger for
assuming&amp;nbsp;familiarity.&lt;/p&gt;
&lt;p&gt;The people covered&amp;nbsp;include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wei Yuan (born in 1794, died in&amp;nbsp;1857)&lt;/li&gt;
&lt;li&gt;Feng Guifen&amp;nbsp;(1809-1874)&lt;/li&gt;
&lt;li&gt;the Empress Dowager Cixi&amp;nbsp;(1835-1908)&lt;/li&gt;
&lt;li&gt;Liang Qichao&amp;nbsp;(1873-1929)&lt;/li&gt;
&lt;li&gt;Sun Yat-Sen&amp;nbsp;(1866-1925)&lt;/li&gt;
&lt;li&gt;Chen Duxiu&amp;nbsp;(1879-1942)&lt;/li&gt;
&lt;li&gt;Chiang Kai-Shek&amp;nbsp;(1887-1975)&lt;/li&gt;
&lt;li&gt;Mao Zedong&amp;nbsp;(1893-1976)&lt;/li&gt;
&lt;li&gt;Deng Xiaoping&amp;nbsp;(1904-1997)&lt;/li&gt;
&lt;li&gt;Zhu Rongji&amp;nbsp;(1928-)&lt;/li&gt;
&lt;li&gt;Liu Xiaobo&amp;nbsp;(1955-)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;For a people possessed of such an abiding sense of pride and face, China’s
fall in the nineteenth century from a place of such centrality and dominance
was a special ignominy, and it engendered a very strong and enduring&amp;nbsp;counterreaction.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Many of the ideas were brought in from tours of either Japan or the West, as
well as being informed by China&amp;#8217;s long history. By taking a long view, you
also get to see how people&amp;#8217;s ideas shift over time. I found the two chapters
on Deng particularly&amp;nbsp;interesting.&lt;/p&gt;
&lt;p&gt;If you are looking for a deeper understanding of how China thinks about the
world, and where their trajectory is taking them, this is a great&amp;nbsp;book.&lt;/p&gt;
&lt;p&gt;Highly&amp;nbsp;recommended.&lt;/p&gt;
&lt;h2&gt;The Party: The Secret World of China&amp;#8217;s Communist&amp;nbsp;Rulers&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.amazon.com/gp/product/0061708763/ref=as_li_ss_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0061708763&amp;amp;linkCode=as2&amp;amp;tag=pseudofish-20"&gt;The Party&lt;/a&gt;
provides a comprehensive look at how the party maintains influence and control
across all levels of Chinese&amp;nbsp;society.&lt;/p&gt;
&lt;p&gt;Comprised of distinct articles, covering various areas of the Party, it can be
a bit tiring to read. That said, each chapter contains numerous insights into
modern China. It is left to the reader to pick them out of the&amp;nbsp;interviews.&lt;/p&gt;
&lt;p&gt;The author, Richard McGregor, spent many years living in China as a
correspondant for the Financial&amp;nbsp;Times.&lt;/p&gt;
&lt;p&gt;Recommended.&lt;/p&gt;
&lt;h2&gt;Country&amp;nbsp;Driving&lt;/h2&gt;
&lt;p&gt;Peter Hessler is not likely to be a new name to you, if you are interested in&amp;nbsp;China.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.amazon.com/gp/product/0061804096/ref=as_li_ss_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0061804096&amp;amp;linkCode=as2&amp;amp;tag=pseudofish-20"&gt;Country Driving&lt;/a&gt;
continues his brilliant narratives on modern China with three stories. The
first covers driving along remote parts of the Great Wall, the second a story
of life of a single family in a small town near Beijing, and the third is in a
development zone and covers the rise of a new&amp;nbsp;factory.&lt;/p&gt;
&lt;p&gt;Each story is beautiful by itself. Combined, you get the feeling of living
through different aspects of China&amp;#8217;s recent&amp;nbsp;modernisation.&lt;/p&gt;
&lt;p&gt;Highly&amp;nbsp;recommended.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>Learning iOS programming</title><link href="https://pseudofish.com/learning-ios-programming.html" rel="alternate"></link><published>2013-08-12T00:00:00+02:00</published><updated>2013-08-12T00:00:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2013-08-12:/learning-ios-programming.html</id><summary type="html">&lt;p&gt;Some notes from learning about iOS&amp;nbsp;programming&lt;/p&gt;</summary><content type="html">&lt;p&gt;I am attempting to get into
&lt;a href="http://en.wikipedia.org/wiki/Shoshin"&gt;beginner&amp;#8217;s mind&lt;/a&gt; as I dive into
learning iOS&amp;nbsp;programming.&lt;/p&gt;
&lt;p&gt;This post includes some of the resources that I&amp;#8217;ve found useful so&amp;nbsp;far.&lt;/p&gt;
&lt;h2&gt;Books&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/iOS-Programming-Ranch-Guides-ebook/dp/B007OWBAB0/ref=nosim/pseudofish-20"&gt;iOS Programming&lt;/a&gt;
  &amp;#8212; start here. This is &lt;em&gt;the&lt;/em&gt; book to get you going with iOS programming. The
  remaining resources aren&amp;#8217;t helpful without understanding the&amp;nbsp;fundamentals.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/Test-Driven-Development-Developers-Library-ebook/dp/B007RNK0W6/ref=nosim/pseudofish-20"&gt;Test-Driven iOS Development&lt;/a&gt;
  &amp;#8212; my next book to&amp;nbsp;read.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/Developers-Cookbook-Edition-Library-ebook/dp/B00AFXID2E/ref=nosim/pseudofish-20"&gt;The Core iOS 6 Developer&amp;#8217;s Cookbook&lt;/a&gt;.
  &amp;#8212; yet to read, with code samples &lt;a href="https://github.com/erica/iOS-6-Cookbook"&gt;online&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/Advanced-Developers-Cookbook-Edition-ebook/dp/B00BMQOGLU/ref=nosim/pseudofish-20"&gt;The Advanced iOS 6 Developer&amp;#8217;s Cookbook&lt;/a&gt;
  &amp;#8212; yet to read, with code samples &lt;a href="https://github.com/erica/iOS-6-Advanced-Cookbook"&gt;online&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#8217;m now fully sold on tech books on Kindle, as I can read on multiple devices
and have available on my Mac for searching when&amp;nbsp;needed.&lt;/p&gt;
&lt;h2&gt;Blogs&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.objc.io/"&gt;objc.io&lt;/a&gt; &amp;#8212; advanced topics, in magazine/&lt;span class="caps"&gt;RSS&lt;/span&gt;&amp;nbsp;format.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nshipster.com"&gt;NSHipster&lt;/a&gt; &amp;#8212; deep dives on a range of&amp;nbsp;topics.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.cocoawithlove.com/"&gt;Cocoa with Love&lt;/a&gt; &amp;#8212; lots of great content in
  the&amp;nbsp;archives.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nsscreencast.com"&gt;NSScreencasts&lt;/a&gt; &amp;#8212; some free and some subscription&amp;nbsp;screencasts.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Podcasts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphreaksshow.com/"&gt;iPhreaks&lt;/a&gt; &amp;#8212; great introductary podcast. Their
  &lt;a href="http://iphreaksshow.com/getting-started-with-ios-development/"&gt;first episode&lt;/a&gt;
  includes lots of things to get&amp;nbsp;going.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nsbrief.com/"&gt;NSBrief&lt;/a&gt; &amp;#8212; in depth on a range of topics with
  guests. A mix of iOS &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Mac&amp;nbsp;themes.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://identicalcousins.net/"&gt;Identical Cousins&lt;/a&gt; &amp;#8212; general chat on a range
  of&amp;nbsp;topics.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://edgecasesshow.com/"&gt;Edge Cases&lt;/a&gt; &amp;#8212; two iOS experts chatting. What&amp;#8217;s
  not to&amp;nbsp;like.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Other&amp;nbsp;tactics&lt;/h2&gt;
&lt;p&gt;I am making a point of trying to read as much iOS code as I can. I find this
helpful in seeing how other programmers have solved problems. I&amp;#8217;m using a mix
of &lt;a href="https://github.com/nothingmagical/cheddar-ios"&gt;production&lt;/a&gt; and example
code, as well as examining particular commits that look&amp;nbsp;interesting.&lt;/p&gt;
&lt;p&gt;I am attempting to fill my Twitter feed with useful iOS content, and randomly
following people relating to iOS programming. (eg.
@&lt;a href="https://twitter.com/mattt"&gt;mattt&lt;/a&gt;,
@&lt;a href="https://twitter.com/drance"&gt;drance&lt;/a&gt;,
@&lt;a href="https://twitter.com/chockenberry"&gt;chockenberry&lt;/a&gt;,
@&lt;a href="https://twitter.com/mattjgalloway"&gt;mattjgalloway&lt;/a&gt;,
@&lt;a href="https://twitter.com/rwenderlich"&gt;rwenderlich&lt;/a&gt;, &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;
@&lt;a href="https://twitter.com/secboffin"&gt;secboffin&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;The other thing I&amp;#8217;m doing is to have a hobby iOS project. This gives me
specific challenges to try and solve in a real app. So far, I have this
deployable through &lt;a href="https://testflightapp.com/"&gt;TestFlight&lt;/a&gt; to try out on a
few phones around the&amp;nbsp;house.&lt;/p&gt;
&lt;p&gt;Still so much to dig into and learn. I&amp;#8217;m not yet comfortable with unit
testing for iOS, and this is the next big thing on my list. Things like
&lt;a href="http://cocoapods.org/"&gt;CocoaPods&lt;/a&gt;,
&lt;a href="https://github.com/AFNetworking/AFNetworking"&gt;AFNetworking&lt;/a&gt;,
&lt;a href="https://github.com/rentzsch/mogenerator"&gt;mogenerator&lt;/a&gt;, and
&lt;a href="https://github.com/allending/Kiwi"&gt;Kiwi&lt;/a&gt; are likely to&amp;nbsp;follow.&lt;/p&gt;</content><category term="programming"></category></entry><entry><title>Rethinking how I handle email</title><link href="https://pseudofish.com/rethinking-how-i-handle-email.html" rel="alternate"></link><published>2013-05-12T00:00:00+02:00</published><updated>2013-05-12T00:00:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2013-05-12:/rethinking-how-i-handle-email.html</id><summary type="html">&lt;p&gt;After being swamped with 3x previous email, looking at how to&amp;nbsp;cope.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Email started to take too long, so I recently changed my&amp;nbsp;approach.&lt;/p&gt;
&lt;p&gt;At work, we try to avoid unbounded queues. In a distributed service
architecture, they can be toxic and swamp otherwise well behaving&amp;nbsp;services.&lt;/p&gt;
&lt;p&gt;Email had become an unbounded queue. It kept piling up and swamping my
day. Time for a&amp;nbsp;change.&lt;/p&gt;
&lt;h3&gt;My new&amp;nbsp;process&lt;/h3&gt;
&lt;p&gt;I adapted
&lt;a href="http://www.manager-tools.com/2013/03/email-three-times-a-day-part-1"&gt;the&lt;/a&gt;
&lt;a href="http://www.manager-tools.com/2013/03/email-three-times-a-day-part-2"&gt;recommendations&lt;/a&gt;
from Manager Tools, and I now follow these&amp;nbsp;guidelines:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Schedule 30mins in the morning for&amp;nbsp;email.&lt;/li&gt;
&lt;li&gt;No more than three time periods of up to 30mins during a day for&amp;nbsp;email.&lt;/li&gt;
&lt;li&gt;If I start processing email, I must finish (empty &lt;span class="caps"&gt;INBOX&lt;/span&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key for me has been pushing myself to finish if I start. This means that a
spare five minutes cannot be spent &lt;em&gt;doing email&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For things that I need to do, either I book time in my calendar or put an
entry in my &lt;a href="http://culturedcode.com/things/"&gt;task list&lt;/a&gt;, possibly with a&amp;nbsp;reminder.&lt;/p&gt;
&lt;p&gt;When I end up with something that I want to come back to later, I&amp;#8217;ll create a
task to refer back to it, and park the email in a &amp;#8220;Follow-up&amp;#8221;&amp;nbsp;folder.&lt;/p&gt;
&lt;p&gt;For random notes to self, I now add a task. Previously, I was cluttering
my inbox and compounding my mail&amp;nbsp;problem.&lt;/p&gt;
&lt;p&gt;I also switched to using &lt;a href="http://www.instapaper.com/"&gt;Instapaper&lt;/a&gt; for saving
articles from Twitter, also reducing emails to&amp;nbsp;myself.&lt;/p&gt;
&lt;h3&gt;Results&lt;/h3&gt;
&lt;p&gt;The last two weeks were a big&amp;nbsp;improvement.&lt;/p&gt;
&lt;p&gt;I am feeling less stressed by email, and more focused on important
activites. I also feel like I have more time to handle unexpected events and
to chat with&amp;nbsp;colleagues.&lt;/p&gt;
&lt;p&gt;I still catch myself checking email on occasion, however often my inbox is
empty, so I&amp;#8217;m slowly weaning myself of the&amp;nbsp;habit.&lt;/p&gt;
&lt;p&gt;For personal email accounts, I&amp;#8217;m using a similar approach, although with a
lower frequency of&amp;nbsp;checking.&lt;/p&gt;
&lt;p&gt;For my phone, I will occasionally check email there, and am a bit more relaxed
about the process. I also set all mail applications to only check mail when
manually&amp;nbsp;asked.&lt;/p&gt;
&lt;h3&gt;Measuring email&amp;nbsp;volume&lt;/h3&gt;
&lt;p&gt;Below is a chart of the email volume over the last two years for my work
account. I was curious how much email I was receiving, and how much I&amp;nbsp;sent.&lt;/p&gt;
&lt;p&gt;For the last few months, I received around 3 times the number of emails as the
same period last year. This is a factor of being involved in more projects,
and the growth of the company. November last year was during a major project,
and spiked in the number of emails I&amp;nbsp;received.&lt;/p&gt;
&lt;p&gt;I was surprised to find that I still send the same number of emails (~10-15
per&amp;nbsp;day).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Email volume" src="https://pseudofish.com/images/email-volume.png"&gt;&lt;/p&gt;
&lt;p&gt;The chart was generated via the &lt;span class="caps"&gt;IMAP&lt;/span&gt; interface to Gmail, and this Python&amp;nbsp;script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;imaplib&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;count_of_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mailbox&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;INBOX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mailbox_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;search&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(X-GM-RAW &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;quot;)&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_ids&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;mailbox_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;[Gmail]/All Mail&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;passwd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;user@example.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;secret&amp;#39;&lt;/span&gt;

&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imaplib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IMAP4_SSL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;imap.gmail.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;993&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;passwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Date,All Mail,Sent,Received&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2012&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2013&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;date_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;after: &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s1"&gt;/1 before:&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s1"&gt;/31&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;all_mail_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count_of_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;date_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mailbox_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;sent_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt; from:&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sent_mail_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count_of_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sent_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mailbox_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;received_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt; to:&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;received_mail_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count_of_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;received_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mailbox_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;/1, &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="n"&gt;all_mail_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="n"&gt;sent_mail_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="n"&gt;received_mail_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The tricky part was finding a way to pass the X-&lt;span class="caps"&gt;GM&lt;/span&gt;-&lt;span class="caps"&gt;RAW&lt;/span&gt; parameter through to
&lt;span class="caps"&gt;IMAP&lt;/span&gt; to enable Gmail
&lt;a href="https://developers.google.com/google-apps/gmail/imap_extensions#extension_of_the_search_command_x-gm-raw"&gt;search criteria&lt;/a&gt;. This
allows you to use the same search expressions as from within&amp;nbsp;Gmail.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>Using deft mode for notes in Emacs</title><link href="https://pseudofish.com/using-deft-mode-for-notes-in-emacs.html" rel="alternate"></link><published>2013-03-14T00:00:00+01:00</published><updated>2013-03-14T00:00:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2013-03-14:/using-deft-mode-for-notes-in-emacs.html</id><summary type="html">&lt;p&gt;How to use emacs to simplify note&amp;nbsp;taking.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://jblevins.org/projects/deft/"&gt;Deft&lt;/a&gt; mode is one of my favorite
discoveries of &lt;a href="http://www.gnu.org/software/emacs/"&gt;emacs&lt;/a&gt;, especially when
combined with the magic of &lt;a href="http://orgmode.org/"&gt;org-mode&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I use the combination of both deft and org-mode almost every day. If I&amp;#8217;m doing
an interview, taking notes in a meeting, keeping a personal backlog or ideas
for a project, then this is what I&amp;#8217;m&amp;nbsp;using.&lt;/p&gt;
&lt;p&gt;Deft solves the problem of where to put text files. Org-mode structures what
goes into&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;Deft can be installed via emacs packaging. I configure it like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;deft&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;noerror&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;deft-extension&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;org&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;deft-directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;~/Dropbox/Notes/&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;deft-text-mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;org-mode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I put the default folder within my Dropbox folder. This ensures notes are
backed up and available on any computer where I&amp;#8217;m using Dropbox and&amp;nbsp;emacs.&lt;/p&gt;
&lt;p&gt;Once in deft mode (&lt;code&gt;M-x deft&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RET&lt;/code&gt; &amp;#8212; open the current&amp;nbsp;file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-c C-n / C-RET&lt;/code&gt; &amp;#8212; create a new file (auto&amp;nbsp;named)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-c RET&lt;/code&gt; &amp;#8212; create a new file (prompt for&amp;nbsp;name)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-c C-r&lt;/code&gt; &amp;#8212; rename a&amp;nbsp;file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-c C-d&lt;/code&gt; &amp;#8212; delete a&amp;nbsp;file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To search for a particular file, just start typing and the results are
filtered in the same&amp;nbsp;view.&lt;/p&gt;
&lt;p&gt;For me, this has been near perfect for quick note taking. My current notes
folder holds over 150 org files and is still fast to&amp;nbsp;search.&lt;/p&gt;
&lt;p&gt;When sharing notes from meetings with others, I use org-mode&amp;#8217;s export feature
(&lt;code&gt;C-c C-e A&lt;/code&gt;), then highlight the part I want, and send it to the clipboard (&lt;code&gt;M-|
pbcopy&lt;/code&gt;) to paste into&amp;nbsp;email.&lt;/p&gt;
&lt;p&gt;Getting a solid system for note taking in emacs has helped with how often I
use the same text editor. This was also part of my motivation of migrating my
blog to text files (although markdown&amp;nbsp;formatted).&lt;/p&gt;
&lt;h2&gt;Additional&amp;nbsp;tips&lt;/h2&gt;
&lt;p&gt;To launch emacs from the command line with deft mode open, I set the following&amp;nbsp;alias:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;alias de=&amp;quot;emacs --eval &amp;#39;(deft)&amp;#39;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Often I have similar formats for things like notes, minutes or interviews. To
avoid lots of typing, I use
&lt;a href="http://capitaomorte.github.io/yasnippet/"&gt;yasnippet&lt;/a&gt; to create&amp;nbsp;templates.&lt;/p&gt;
&lt;p&gt;For some examples, see my
&lt;a href="https://github.com/gmwils/dotfiles/tree/master/emacs.d/snippets/org-mode"&gt;dotfiles&lt;/a&gt;.&lt;/p&gt;</content><category term="emacs"></category></entry><entry><title>Scandinavian Startups</title><link href="https://pseudofish.com/scandinavian-startups.html" rel="alternate"></link><published>2013-02-21T00:00:00+01:00</published><updated>2013-02-21T00:00:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2013-02-21:/scandinavian-startups.html</id><summary type="html">&lt;p&gt;There is something in the water up here. The economy seems to be going well,
and the press seems to have taken&amp;nbsp;notice.&lt;/p&gt;
&lt;p&gt;An
&lt;a href="http://www.usatoday.com/story/tech/2013/02/16/klarna-spotify-mysql-king-dice-izettle/1923609/"&gt;example&lt;/a&gt;
from &lt;span class="caps"&gt;USA&lt;/span&gt;&amp;nbsp;Today:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If music service Spotify landed Stockholm on the high-tech map, companies
 such as Klarna underscore its growing&amp;nbsp;influence.&lt;/p&gt;
&lt;p&gt;In the first quarter …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;There is something in the water up here. The economy seems to be going well,
and the press seems to have taken&amp;nbsp;notice.&lt;/p&gt;
&lt;p&gt;An
&lt;a href="http://www.usatoday.com/story/tech/2013/02/16/klarna-spotify-mysql-king-dice-izettle/1923609/"&gt;example&lt;/a&gt;
from &lt;span class="caps"&gt;USA&lt;/span&gt;&amp;nbsp;Today:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If music service Spotify landed Stockholm on the high-tech map, companies
 such as Klarna underscore its growing&amp;nbsp;influence.&lt;/p&gt;
&lt;p&gt;In the first quarter of 2012, Sweden took in almost 20% of all venture
 capital invested in the European Union, trailing only&amp;nbsp;Germany&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And Pando Daily on
&lt;a href="http://pandodaily.com/2012/11/20/why-tiny-stockholm-has-the-most-stunning-startup-ecosystem-since-tel-aviv/"&gt;Stockholm&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thanks to Klarna, Spotify, Rebtel, and King.com, among others, Stockholm has
a longer history of tech successes and more big-dollar exits than its German
rival&amp;nbsp;[Berlin].&lt;/p&gt;
&lt;p&gt;For instance, the Nordic region as a whole — which still represents a
much smaller population than Germany — accounted for about 6.5 percent of
the world’s billion-dollar exits from 2005 to 2012, according to statistics
provided by Stockholm-based venture capital firm&amp;nbsp;Creandum.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is still room to grow, as European startups in general are
&lt;a href="http://thenextweb.com/insider/2013/02/16/european-startups-need-to-be-celebrated-for-success/"&gt;undervalued&lt;/a&gt;
compared to the &lt;span class="caps"&gt;US&lt;/span&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Listed European technology firms valued at more than $100 million are on
average 32 percent cheaper than their North American peers. Bloomberg says
they trade at an average ratio of 15 times earnings compared with 22 times
earnings in the &lt;span class="caps"&gt;US&lt;/span&gt; and&amp;nbsp;Canada.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Economist goes into depth on in their special report on
&lt;a href="http://www.economist.com/printedition/2013-02-02"&gt;The Nordic Lights&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Finland has become much more market- and entrepreneur-friendly. It has
produced an impressive number of start-ups, including 300 founded by former
Nokia&amp;nbsp;employees.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Nordic countries have not only largely escaped the economic problems that
are convulsing the Mediterranean world; they have also largely escaped the
social ills that plague&amp;nbsp;America.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I feel very lucky to have worked for a number of Nordic companies, and to
continue my Scandinavian adventure with Spotify here in&amp;nbsp;Stockholm.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>New Blog</title><link href="https://pseudofish.com/new-blog.html" rel="alternate"></link><published>2013-02-10T00:00:00+01:00</published><updated>2013-02-10T00:00:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2013-02-10:/new-blog.html</id><summary type="html">&lt;p&gt;If things went well, this post will be from my new&amp;nbsp;blog.&lt;/p&gt;
&lt;p&gt;I migrated my existing blog across to use
&lt;a href="http://docs.getpelican.com/"&gt;Pelican&lt;/a&gt;, a static site generator written in
Python. This is part of attempting to use emacs &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; python for as much of my
workflow as&amp;nbsp;possible.&lt;/p&gt;
&lt;p&gt;During the migration, all the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;If things went well, this post will be from my new&amp;nbsp;blog.&lt;/p&gt;
&lt;p&gt;I migrated my existing blog across to use
&lt;a href="http://docs.getpelican.com/"&gt;Pelican&lt;/a&gt;, a static site generator written in
Python. This is part of attempting to use emacs &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; python for as much of my
workflow as&amp;nbsp;possible.&lt;/p&gt;
&lt;p&gt;During the migration, all the code and formatting were cleaned up, so it
should be easy to change. Previously, all the content was in a Wordpress
database, and not so easy to&amp;nbsp;transform.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not sure how attached I&amp;#8217;ll be to Markdown. I am contemplating adding
&lt;a href="http://orgmode.org/"&gt;org-mode&lt;/a&gt; support to Pelican, as I use it for most other&amp;nbsp;notetaking.&lt;/p&gt;
&lt;p&gt;You may notice some duplicate articles via &lt;span class="caps"&gt;RSS&lt;/span&gt;. This is unfortunately due to
changing the &lt;span class="caps"&gt;URL&lt;/span&gt;&amp;nbsp;scheme.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>Postgres database migrations with Python</title><link href="https://pseudofish.com/postgres-database-migrations-with-python.html" rel="alternate"></link><published>2012-11-18T02:41:00+01:00</published><updated>2012-11-18T02:41:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2012-11-18:/postgres-database-migrations-with-python.html</id><summary type="html">&lt;p&gt;If you need to setup database migrations that work both locally and on
&lt;a href="https://devcenter.heroku.com/articles/heroku-postgresql"&gt;Heroku&lt;/a&gt; in Python, these steps may be&amp;nbsp;helpful.&lt;/p&gt;
&lt;p&gt;For a recent project, I wanted to be able to manage the database schema.
I&amp;#8217;m not using an &lt;span class="caps"&gt;ORM&lt;/span&gt;, however the migration features in &lt;a href="https://sqlalchemy-migrate.readthedocs.org/en/v0.7.2/versioning.html"&gt;SQLAlchemy&lt;/a&gt;
turn out to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;If you need to setup database migrations that work both locally and on
&lt;a href="https://devcenter.heroku.com/articles/heroku-postgresql"&gt;Heroku&lt;/a&gt; in Python, these steps may be&amp;nbsp;helpful.&lt;/p&gt;
&lt;p&gt;For a recent project, I wanted to be able to manage the database schema.
I&amp;#8217;m not using an &lt;span class="caps"&gt;ORM&lt;/span&gt;, however the migration features in &lt;a href="https://sqlalchemy-migrate.readthedocs.org/en/v0.7.2/versioning.html"&gt;SQLAlchemy&lt;/a&gt;
turn out to be quite&amp;nbsp;useful.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install the SQLAlchemy migration package, by adding the following to&amp;nbsp;requirements.txt.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Migrations&lt;/span&gt;
&lt;span class="n"&gt;sqlalchemy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;migrate&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7.2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and&amp;nbsp;update:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a repository for database&amp;nbsp;migrations&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;migrate create db &amp;quot;Cihui&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This creates a directory &lt;code&gt;db/&lt;/code&gt; where the code and migrations will&amp;nbsp;reside.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update the migrate script to use Heroku &lt;span class="caps"&gt;DB&lt;/span&gt;&amp;nbsp;url&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;migrate.versioning.shell&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;db_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATABASE_URL&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;postgresql://localhost:5432/cihui&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;db_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;postgres:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;postgresql:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;db_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;False&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;db&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This should allow you to run migrations locally or on Heroku. There
was a warning message on Heroku for the url starting with postgres
rather than postgresql, thus the &lt;code&gt;replace&lt;/code&gt; line.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update&amp;nbsp;Procfile&lt;/p&gt;
&lt;p&gt;This sets up a few useful targets to run on Heroku and locally using
&lt;a href="http://ddollar.github.com/foreman/"&gt;foreman&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;db_init&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;version_control&lt;/span&gt;
&lt;span class="n"&gt;db_version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db_version&lt;/span&gt;
&lt;span class="n"&gt;migrate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;upgrade&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To migrate&amp;nbsp;locally&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;foreman run init_db # first time
foreman run migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To run on&amp;nbsp;Heroku&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;heroku run db_init
heroku run migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write migrations as &lt;span class="caps"&gt;SQL&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I prefer to manually write the migrations, and SQLAlchemy has great
support for this. Refer to their docs for &lt;a href="https://sqlalchemy-migrate.readthedocs.org/en/v0.7.2/versioning.html#writings-sql-scripts"&gt;details&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;python db/manage.py script_sql postgresql &amp;#39;add list table&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This generates an upgrade and downgrade sql script in &lt;code&gt;db/versions&lt;/code&gt;
with an appropriate version&amp;nbsp;number.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Test the&amp;nbsp;migration:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;python db/manage.py test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Runs upgrade and then downgrade on a single&amp;nbsp;version.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class="caps"&gt;DB&lt;/span&gt; access to&amp;nbsp;Heroku&lt;/p&gt;
&lt;p&gt;Console access is available&amp;nbsp;via:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;heroku pg:psql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Useful for checking specific values or fixing broken&amp;nbsp;migrations.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&amp;#8217;m still iterating on this project, so may change some things around as
I go. For the moment, this allowed me to manage the database schema
easily in multiple&amp;nbsp;databases.&lt;/p&gt;</content><category term="python"></category></entry><entry><title>Reading email in Chinese with Python</title><link href="https://pseudofish.com/reading-email-in-chinese-with-python.html" rel="alternate"></link><published>2012-10-15T16:41:00+02:00</published><updated>2012-10-15T16:41:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2012-10-15:/reading-email-in-chinese-with-python.html</id><summary type="html">&lt;p&gt;Read email from a mailbox, in Chinese, with Python. Sounded&amp;nbsp;easy.&lt;/p&gt;
&lt;p&gt;After playing at the python prompt and many Google searches later, still
no success. Then, I found &lt;a href="http://ginstrom.com/scribbles/2007/11/19/parsing-multilingual-email-with-python/"&gt;two&lt;/a&gt; &lt;a href="http://lobstertech.com/python_unicode.html#hands_on_with_asian_spam"&gt;articles&lt;/a&gt; that&amp;nbsp;helped.&lt;/p&gt;
&lt;p&gt;Turns out that there are a few tricks to getting email parsing to work
properly for multi-byte&amp;nbsp;languages …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Read email from a mailbox, in Chinese, with Python. Sounded&amp;nbsp;easy.&lt;/p&gt;
&lt;p&gt;After playing at the python prompt and many Google searches later, still
no success. Then, I found &lt;a href="http://ginstrom.com/scribbles/2007/11/19/parsing-multilingual-email-with-python/"&gt;two&lt;/a&gt; &lt;a href="http://lobstertech.com/python_unicode.html#hands_on_with_asian_spam"&gt;articles&lt;/a&gt; that&amp;nbsp;helped.&lt;/p&gt;
&lt;p&gt;Turns out that there are a few tricks to getting email parsing to work
properly for multi-byte&amp;nbsp;languages.&lt;/p&gt;
&lt;p&gt;So, if you end up with strings something&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;=?GB2312?Q?Qingwen_Word_List:_=D3=D0=D2=E2=CB=BC=B5=C4=B4=CA?=
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AF&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AF&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A8&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;D9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inscription&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A2&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;DC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;musical&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instruments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;B0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;D2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;F4&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ba1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yin1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;C0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A8&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CCm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A8&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A2nhu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A8&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;D9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cymbidium&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orchid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, you&amp;#8217;ll need two different approaches. One for the header strings,
and one for the body&amp;nbsp;text.&lt;/p&gt;
&lt;p&gt;Given an &lt;a href="http://docs.python.org/library/email.html"&gt;email&lt;/a&gt; message, either from a string or&amp;nbsp;file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;email&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;email&lt;/span&gt;
&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message_from_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str_msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, headers can be read using something&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Subject&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which&amp;nbsp;gives:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Qingwen&lt;/span&gt; &lt;span class="n"&gt;Word&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;有意思的词&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case, the encoding can be read from the email message and is&amp;nbsp;&amp;#8216;gb2312&amp;#8217;.&lt;/p&gt;
&lt;p&gt;The body text needs a slightly different&amp;nbsp;approach:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_payload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_content_charset&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;replace&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;石&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;石&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shí&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;①&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;②&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;③&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inscription&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;④&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ancient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;musical&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instruments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;八音&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ba1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yin1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;兰花&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;花&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lánhuā&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;①&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cymbidium&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;②&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orchid&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="http://docs.python.org/library/functions.html?highlight=unicode#unicode"&gt;&amp;#8216;replace&amp;#8217;&lt;/a&gt; option will mark unknown characters using U+&lt;span class="caps"&gt;FFFD&lt;/span&gt;,
rather than throw an&amp;nbsp;exception.&lt;/p&gt;
&lt;p&gt;This approach should work for most languages. Getting the various
decodings sorted out allowed me to move forward on a project I&amp;#8217;m working
on. Now to re-implement it test&amp;nbsp;first.&lt;/p&gt;
&lt;p&gt;I know the format of the emails coming in, so can ignore multi-part &lt;span class="caps"&gt;MIME&lt;/span&gt;
messages. If you are looking for some more details on how to handle
them, check out &lt;a href="http://ginstrom.com/scribbles/2007/11/19/parsing-multilingual-email-with-python/"&gt;this article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you were curious about the =&lt;span class="caps"&gt;DA&lt;/span&gt; encoding, it is called
&lt;a href="http://en.wikipedia.org/wiki/Quoted-printable"&gt;quoted-printable&lt;/a&gt; (&lt;a href="http://tools.ietf.org/html/rfc2045#section-6.7"&gt;&lt;span class="caps"&gt;RFC&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;</content><category term="python"></category></entry><entry><title>Good Strategy Bad Strategy</title><link href="https://pseudofish.com/good-strategy-bad-strategy.html" rel="alternate"></link><published>2012-06-24T22:53:00+02:00</published><updated>2012-06-24T22:53:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2012-06-24:/good-strategy-bad-strategy.html</id><summary type="html">&lt;p&gt;My current reading list is mixed between coding, decision making, agile,
and strategy. Richard Rumelt&amp;#8217;s &lt;a href="http://www.amazon.com/gp/product/B004J4WKEC/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=B004J4WKEC"&gt;Good Strategy Bad Strategy&lt;/a&gt; stands out
as an interesting and entertaining&amp;nbsp;read.&lt;/p&gt;
&lt;p&gt;I liked how he outlined good strategy, and also how to identify bad
strategy. This really helps in pushing through from a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;My current reading list is mixed between coding, decision making, agile,
and strategy. Richard Rumelt&amp;#8217;s &lt;a href="http://www.amazon.com/gp/product/B004J4WKEC/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=B004J4WKEC"&gt;Good Strategy Bad Strategy&lt;/a&gt; stands out
as an interesting and entertaining&amp;nbsp;read.&lt;/p&gt;
&lt;p&gt;I liked how he outlined good strategy, and also how to identify bad
strategy. This really helps in pushing through from a good enough
attempt to a strategy that will make a&amp;nbsp;difference.&lt;/p&gt;
&lt;p&gt;Some&amp;nbsp;quotes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Good strategy almost always looks this simple and obvious and does not
take a thick deck of PowerPoint slides to explain. It does not pop out
of some “strategic management” tool, matrix, chart, triangle, or
fill-in-the-blanks scheme. Instead, a talented leader identifies the
one or two critical issues in the situation—the pivot points that can
multiply the effectiveness of effort—and then focuses and concentrates
action and resources on&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;Good strategy requires leaders who are willing and able to say no to a
wide variety of actions and interests. Strategy is at least as much
about what an organization does not do as it is about what it&amp;nbsp;does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On identifying bad&amp;nbsp;strategy:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have condensed my list of its key hallmarks to the four listed in
the beginning of this chapter: fluff, the failure to face the
challenge, mistaking goals for strategy, and bad strategic&amp;nbsp;objectives.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On the structure of a good&amp;nbsp;strategy:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The kernel of a strategy contains three elements: a diagnosis, a
guiding policy, and coherent action. The guiding policy specifies the
approach to dealing with the obstacles called out in the diagnosis. It
is like a signpost, marking the direction forward but not defining the
details of the trip. Coherent actions are feasible coordinated
policies, resource commitments, and actions designed to carry out the
guiding&amp;nbsp;policy.&lt;/p&gt;
&lt;p&gt;The problem of coming up with a good strategy has the same logical
structure as the problem of coming up with a good scientific
hypothesis. The key differences are that most scientific knowledge is
broadly shared, whereas you are working with accumulated wisdom about
your business and your industry that is unlike anyone else’s. A good
strategy is, in the end, a hypothesis about what will&amp;nbsp;work.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The book provides insight into the structure of a good strategy.
However, it stops short of providing actionable techniques or analysis
to help you get there. In this, it advocates strategy work being done by
someone with a deep understanding of the business and competitive&amp;nbsp;landscape.&lt;/p&gt;
&lt;p&gt;This left me wanting more, and fortunately there are books out there
that provide guidelines on this type of analysis. I see a few &lt;a href="http://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&amp;amp;field-keywords=Michael+Porter"&gt;Michael
Porter&lt;/a&gt; books in my future&amp;nbsp;reading.&lt;/p&gt;</content><category term="business"></category></entry><entry><title>Debugging Python with PDB</title><link href="https://pseudofish.com/debugging-python-with-pdb.html" rel="alternate"></link><published>2012-05-03T02:51:00+02:00</published><updated>2012-05-03T02:51:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2012-05-03:/debugging-python-with-pdb.html</id><summary type="html">&lt;p&gt;I suck at using debuggers, largely because I don&amp;#8217;t launch them often&amp;nbsp;enough.&lt;/p&gt;
&lt;p&gt;Fortunately, this year&amp;#8217;s PyCon had a &lt;a href="http://pyvideo.org/video/644/introduction-to-pdb"&gt;great talk&lt;/a&gt; from Chris McDonough
on how to get started with Python&amp;#8217;s debugger, &lt;a href="http://docs.python.org/library/pdb.html"&gt;&lt;span class="caps"&gt;PDB&lt;/span&gt;&lt;/a&gt;. The friendly
people at Stockholm&amp;#8217;s &lt;a href="http://www.meetup.com/pysthlm/"&gt;Python meet-up&lt;/a&gt; suggested&amp;nbsp;it.&lt;/p&gt;
&lt;iframe width="420" height="315" src="http://www.youtube.com/embed/vfPtGsSJldg" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;I made notes while …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I suck at using debuggers, largely because I don&amp;#8217;t launch them often&amp;nbsp;enough.&lt;/p&gt;
&lt;p&gt;Fortunately, this year&amp;#8217;s PyCon had a &lt;a href="http://pyvideo.org/video/644/introduction-to-pdb"&gt;great talk&lt;/a&gt; from Chris McDonough
on how to get started with Python&amp;#8217;s debugger, &lt;a href="http://docs.python.org/library/pdb.html"&gt;&lt;span class="caps"&gt;PDB&lt;/span&gt;&lt;/a&gt;. The friendly
people at Stockholm&amp;#8217;s &lt;a href="http://www.meetup.com/pysthlm/"&gt;Python meet-up&lt;/a&gt; suggested&amp;nbsp;it.&lt;/p&gt;
&lt;iframe width="420" height="315" src="http://www.youtube.com/embed/vfPtGsSJldg" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;I made notes while watching, to remove excuses from future me on
launching&amp;nbsp;pdb.&lt;/p&gt;
&lt;p&gt;Where you want to have the debugger start, add the following&amp;nbsp;code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pdb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;pdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_trace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This drops you into a &lt;span class="caps"&gt;PDB&lt;/span&gt; prompt. This is more helpful than putting in
yet more print&amp;nbsp;statements.&lt;/p&gt;
&lt;p&gt;Some helpful commands once you&amp;#8217;re&amp;nbsp;in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;l - list&amp;nbsp;code&lt;/li&gt;
&lt;li&gt;args - arguments to current&amp;nbsp;function&lt;/li&gt;
&lt;li&gt;p &amp;lt;var&amp;gt; - print a&amp;nbsp;var&lt;/li&gt;
&lt;li&gt;pp &amp;lt;var&amp;gt; - pretty print a&amp;nbsp;var&lt;/li&gt;
&lt;li&gt;n -&amp;nbsp;next&lt;/li&gt;
&lt;li&gt;s -&amp;nbsp;step&lt;/li&gt;
&lt;li&gt;w - where (stack trace for current&amp;nbsp;position)&lt;/li&gt;
&lt;li&gt;h -&amp;nbsp;help&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While in &lt;span class="caps"&gt;PDB&lt;/span&gt;, you can evaluate python code. The evaluated code won&amp;#8217;t
impact the running&amp;nbsp;program.&lt;/p&gt;
&lt;p&gt;For a bonus trick if you&amp;#8217;re using Emacs, try out &lt;a href="http://wiki.zope.org/klm/PDBTrack"&gt;pdb track mode&lt;/a&gt;.
Launch your python process to be debugged in an emacs shell (M-x shell).
Stepping through the code in pdb will track with a source code&amp;nbsp;buffer.&lt;/p&gt;
&lt;p&gt;This worked out of the box with my emacs config. Your milage may&amp;nbsp;vary.&lt;/p&gt;
&lt;p&gt;I may actually start to enjoy debugging&amp;nbsp;now!&lt;/p&gt;</content><category term="python"></category></entry><entry><title>Unit testing in Python with folder watching</title><link href="https://pseudofish.com/unit-testing-in-python-with-folder-watching.html" rel="alternate"></link><published>2012-03-14T05:09:00+01:00</published><updated>2012-03-14T05:09:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2012-03-14:/unit-testing-in-python-with-folder-watching.html</id><summary type="html">&lt;p&gt;Unit testing is good. Running unit tests manually is&amp;nbsp;annoying.&lt;/p&gt;
&lt;p&gt;Rspec has a great addition in &lt;a href="http://lostechies.com/derickbailey/2010/05/03/zentest-autospec-is-an-rspec-tdder-s-best-friend/"&gt;autospec&lt;/a&gt;, which automatically re-runs
specs that are changed or have the associated code changed. This model
of working has a long history in the ruby community, with &lt;a href="http://nubyonrails.com/articles/autotest-rails"&gt;autotest&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I wanted a similar thing for …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Unit testing is good. Running unit tests manually is&amp;nbsp;annoying.&lt;/p&gt;
&lt;p&gt;Rspec has a great addition in &lt;a href="http://lostechies.com/derickbailey/2010/05/03/zentest-autospec-is-an-rspec-tdder-s-best-friend/"&gt;autospec&lt;/a&gt;, which automatically re-runs
specs that are changed or have the associated code changed. This model
of working has a long history in the ruby community, with &lt;a href="http://nubyonrails.com/articles/autotest-rails"&gt;autotest&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I wanted a similar thing for python/&lt;a href="http://readthedocs.org/docs/nose/en/latest/"&gt;nose&lt;/a&gt;, but hadn&amp;#8217;t had much&amp;nbsp;luck.&lt;/p&gt;
&lt;p&gt;The solution is &lt;a href="http://pytest.org/latest/"&gt;py.test&lt;/a&gt;, with some plugins&amp;nbsp;added.&lt;/p&gt;
&lt;p&gt;This was suggested to me at the &lt;a href="http://www.meetup.com/pysthlm/"&gt;Stockholm Python user group&lt;/a&gt;, and I
am very grateful. My testing life is now much&amp;nbsp;simpler.&lt;/p&gt;
&lt;p&gt;To get started, try something&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;pytest&lt;span class="w"&gt; &lt;/span&gt;pytest-xdist&lt;span class="w"&gt; &lt;/span&gt;pytest-cov
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The simple way to get started is to watch your tests&amp;nbsp;folder:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;py.test -f test/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now as you change files, the relevant tests will automatically be
re-run. Perfect to display on that second&amp;nbsp;monitor.&lt;/p&gt;
&lt;p&gt;As I was working on some legacy code, I was looking to improve the test
coverage, so wanted to see how that was going with &lt;a href="http://pypi.python.org/pypi/pytest-cov"&gt;pytest-cov&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;py&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;cov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Adding the &lt;em&gt;package.name&lt;/em&gt; for your main package means you won&amp;#8217;t generate
coverage for libraries you are using. Makes the output&amp;nbsp;simpler.&lt;/p&gt;
&lt;p&gt;Still not quite happy, it wasn&amp;#8217;t showing me which lines I needed
coverage on. No&amp;nbsp;problem:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;py&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;cov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;cov&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;missing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For comparison, here is how to get similar results from nose, but
without watch&amp;nbsp;support:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;nosetests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;nosetests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;with&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;coverage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;cover&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;erase&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;cover&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;One hurdle I had with py.test was working with &lt;a href="http://twistedmatrix.com/trac/"&gt;Twisted&lt;/a&gt; based
test-cases. You need to ensure that you use a version of py.test later
than 2.0. Debian squeeze does not package this by default, so use pip to&amp;nbsp;install.&lt;/p&gt;
&lt;p&gt;The annoyance is if you change the code so it doesn&amp;#8217;t terminate. This
still needs a context switch to kill off the tests and re-run. Keeps me
focused on getting it right the first&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://pypi.python.org/pypi/pytest-xdist"&gt;pytest-xdist&lt;/a&gt; includes lots of really cool options, such as
distribution of tests across multiple cores, versions, hosts and&amp;nbsp;platforms.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve since discovered this &lt;a href="http://wiki.python.org/moin/PythonTestingToolsTaxonomy"&gt;comprehensive summary&lt;/a&gt; of the options
available. I&amp;#8217;m happy I found this after selecting &lt;a href="http://pytest.org/latest/"&gt;py.test&lt;/a&gt;, or I&amp;#8217;d
still be stuck in evaluation mode rather than writing&amp;nbsp;code.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: check out &lt;a href="http://pypi.python.org/pypi/sniffer"&gt;sniffer&lt;/a&gt; if you want a more generic watcher&amp;nbsp;framework.&lt;/p&gt;</content><category term="python"></category></entry><entry><title>Sharpen the Saw: Typing</title><link href="https://pseudofish.com/sharpen-the-saw-typing.html" rel="alternate"></link><published>2012-03-07T00:14:00+01:00</published><updated>2012-03-07T00:14:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2012-03-07:/sharpen-the-saw-typing.html</id><summary type="html">&lt;p&gt;I once explained my job as an overpaid&amp;nbsp;typist.&lt;/p&gt;
&lt;p&gt;There is some truth in that, as much of my day is spent typing. Writing
code, taking notes for meetings, email, documentation, writing blogs&amp;nbsp;posts.&lt;/p&gt;
&lt;p&gt;It would make sense to become very good at&amp;nbsp;typing.&lt;/p&gt;
&lt;p&gt;The basics are often overlooked. You …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I once explained my job as an overpaid&amp;nbsp;typist.&lt;/p&gt;
&lt;p&gt;There is some truth in that, as much of my day is spent typing. Writing
code, taking notes for meetings, email, documentation, writing blogs&amp;nbsp;posts.&lt;/p&gt;
&lt;p&gt;It would make sense to become very good at&amp;nbsp;typing.&lt;/p&gt;
&lt;p&gt;The basics are often overlooked. You can get a lot of benefit from
paying attention to&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;For typing, it comes down to three main&amp;nbsp;areas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Accuracy&lt;/li&gt;
&lt;li&gt;Speed&lt;/li&gt;
&lt;li&gt;Touch&amp;nbsp;typing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Touch typing is perhaps the most important aspect of this. You need to
be able to type without looking at the keyboard. If you get really good,
you shouldn&amp;#8217;t need to even look at the screen to confirm what you&amp;#8217;re&amp;nbsp;typing.&lt;/p&gt;
&lt;p&gt;Accuracy and speed can be built together. Focus on accuracy to start
with, and then stretch for speed. There is no point going faster if you
can&amp;#8217;t maintain a high&amp;nbsp;accuracy.&lt;/p&gt;
&lt;p&gt;I found two websites to be helpful in my quest for improved typing&amp;nbsp;skills:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://wwwtyro.github.com/keyzen/"&gt;Keyzen&lt;/a&gt; — a site focused on improving typing for&amp;nbsp;programmers.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://speedtest.10fastfingers.com/"&gt;10 fast fingers&lt;/a&gt; — general typing improvement with natural
    language&amp;nbsp;exercises.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, the other thing to do to improve typing is to do lots of
typing. If you are writing lots of code, email or documents, then focus
on your typing while you are doing&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;It helps to have a good environment for typing, such as a comfortable
keyboard, good posture, but you know this already. Add it to the list of
things to focus&amp;nbsp;on.&lt;/p&gt;
&lt;p&gt;Also, make sure that you are using a program that can keep up with you
as you type. I find &lt;span class="caps"&gt;MS&lt;/span&gt; Word to lag when in full &lt;span class="caps"&gt;WYSIWG&lt;/span&gt; mode, whereas
emacs and vi always manage to keep&amp;nbsp;up!&lt;/p&gt;
&lt;p&gt;Update: You may also want to check out &lt;a href="http://typespeed.sourceforge.net/"&gt;Typespeed&lt;/a&gt;.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>About Face, Edition 3</title><link href="https://pseudofish.com/about-face-edition-3.html" rel="alternate"></link><published>2012-02-29T17:21:00+01:00</published><updated>2012-02-29T17:21:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2012-02-29:/about-face-edition-3.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;In any field, if you expand your view to know all the ecosystem around
you it’s&amp;nbsp;beneficial.&lt;/p&gt;
&lt;p&gt;—&lt;a href="http://intenseminimalism.com/2011/designers-shouldnt-code-the-digital-duo/"&gt;Davide&amp;nbsp;Casali&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you are a developer, a product owner, or manage a development team,
much of the input is going to be about product design. It is very useful
to understand …&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;In any field, if you expand your view to know all the ecosystem around
you it’s&amp;nbsp;beneficial.&lt;/p&gt;
&lt;p&gt;—&lt;a href="http://intenseminimalism.com/2011/designers-shouldnt-code-the-digital-duo/"&gt;Davide&amp;nbsp;Casali&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you are a developer, a product owner, or manage a development team,
much of the input is going to be about product design. It is very useful
to understand a bit about a good design process, so you can better ask
questions and help refine the design based on technical&amp;nbsp;constraints.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.amazon.com/gp/product/B001C323BI/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399373&amp;amp;creativeASIN=B001C323BI"&gt;About Face&lt;/a&gt;, by Alan Cooper, is a great book to start&amp;nbsp;with.&lt;/p&gt;
&lt;p&gt;I highlighted much of it on my&amp;nbsp;Kindle!&lt;/p&gt;
&lt;p&gt;Here are some&amp;nbsp;quotes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Good design makes users more&amp;nbsp;effective.&lt;/p&gt;
&lt;p&gt;Customers, although they might be able to articulate the problems with
an interaction, are not often capable of visualizing the solutions to
those&amp;nbsp;problems.&lt;/p&gt;
&lt;p&gt;One of the most powerful tools designers bring to the table is&amp;nbsp;empathy&lt;/p&gt;
&lt;p&gt;One of the most dangerous practices in product development is
isolating designers from the users because doing so eliminates
empathic&amp;nbsp;knowledge.&lt;/p&gt;
&lt;p&gt;narrative is also one of our most powerful creative&amp;nbsp;methods.&lt;/p&gt;
&lt;p&gt;What would a helpful human do? What would a thoughtful, considerate
interaction feel&amp;nbsp;like?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All ideas are broken down into discrete sections, with lots of detail
and examples on how to implement this with your&amp;nbsp;customers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Goal-Directed Design combines techniques of ethnography, stakeholder
interviews, market research, detailed user models, scenario-based
design, and a core set of interaction principles and&amp;nbsp;patterns.&lt;/p&gt;
&lt;p&gt;This process can be roughly divided into six phases: Research,
Modeling, Requirements Definition, Framework Definition, Refinement,
and&amp;nbsp;Support&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The book discusses the mindset required to be a good&amp;nbsp;designer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;in anything at all, perfection is finally attained not when there is
no longer anything to add, but when there is no longer anything to
take&amp;nbsp;away&lt;/p&gt;
&lt;p&gt;Next time you find yourself crowing about what cool interaction you&amp;#8217;ve
designed, just remember that the ultimate user interface for most
purposes is no interface at&amp;nbsp;all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The first part of the book focuses on processes to elicit a good design.
The latter part of the book covers specific examples found in user
interface design and attempts to encode common&amp;nbsp;patterns.&lt;/p&gt;
&lt;p&gt;I found the first section much more valuable to how I think about
designing a new product. The latter parts I felt were obvious, although
that is perhaps their&amp;nbsp;importance.&lt;/p&gt;
&lt;p&gt;Well worth a&amp;nbsp;read.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: Bret&amp;#8217;s &lt;a href="http://worrydream.com/#!/MagicInk"&gt;Magic Ink&lt;/a&gt; is a useful counterpoint to About&amp;nbsp;Face.&lt;/p&gt;</content><category term="design"></category></entry><entry><title>Positioning</title><link href="https://pseudofish.com/positioning.html" rel="alternate"></link><published>2011-11-28T20:37:00+01:00</published><updated>2011-11-28T20:37:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-11-28:/positioning.html</id><summary type="html">&lt;p&gt;&lt;a href="http://www.amazon.com/gp/product/B000SEGIW2/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399373&amp;amp;creativeASIN=B000SEGIW2"&gt;Positioning&lt;/a&gt;, by Al Ries and Jack Trout, has long been on my &lt;em&gt;to
read&lt;/em&gt; list, and I wish I had read it&amp;nbsp;sooner.&lt;/p&gt;
&lt;p&gt;The core message of how to position a product is becoming more relevant
as the marketplace continues to&amp;nbsp;crowd.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In our overcommunicated society, the name of the …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.amazon.com/gp/product/B000SEGIW2/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399373&amp;amp;creativeASIN=B000SEGIW2"&gt;Positioning&lt;/a&gt;, by Al Ries and Jack Trout, has long been on my &lt;em&gt;to
read&lt;/em&gt; list, and I wish I had read it&amp;nbsp;sooner.&lt;/p&gt;
&lt;p&gt;The core message of how to position a product is becoming more relevant
as the marketplace continues to&amp;nbsp;crowd.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In our overcommunicated society, the name of the game today is
positioning. And only the better players are going to&amp;nbsp;survive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The book draws on a wide range of examples of different products, where
a &lt;em&gt;product&lt;/em&gt; could be a type of beer, the Catholic Church or your own&amp;nbsp;career.&lt;/p&gt;
&lt;p&gt;The key message is that your products position is determined by how it
fits into the consumer&amp;#8217;s mind. All the things that matter to you, to
your company, are irrelevant if you can&amp;#8217;t create a distinct position to
separate you from everything&amp;nbsp;else.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Experience has shown that a positioning exercise is a search for the
obvious. Those are the easiest concepts to communicate because they
make the most sense to the recipient of a&amp;nbsp;message.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The authors are quite scathing about &amp;#8220;me too&amp;#8221; products that attempt to
beat out a competitor by going head-to-head. Many examples are provided
within the&amp;nbsp;book.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The suicidal bent of companies that go head-on against established
competition is hard to&amp;nbsp;understand.&lt;/p&gt;
&lt;p&gt;To repeat, the first rule of positioning is: To win the battle for the
mind, you can’t compete head-on against a company that has a strong,
established position. You can go around, under or over, but never head
to&amp;nbsp;head.&lt;/p&gt;
&lt;p&gt;The leader owns the high ground. The No. 1 position in the prospect’s
mind. The top rung of the product&amp;nbsp;ladder.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The book covers a range of detail levels, and dips into more detail on
key areas such as product&amp;nbsp;naming:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As a guide, the five most common initial letters are S, C, P, A, and
T. The five least common are X, Z, Y, Q, and K. One out of eight
English words starts with an S. One out of 3000 starts with an&amp;nbsp;X.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The authors are often quite blunt as to how they see things. This is a
refreshing change from most business&amp;nbsp;books:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Creative people often resist positioning thinking because they believe
it restricts their creativity. And you know what? It does. Positioning
thinking does restrict&amp;nbsp;creativity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I gained a lot of insight into how products have succeeded, or not, by
reading this book. The examples are clear and will easily map to
situations you are&amp;nbsp;experiencing.&lt;/p&gt;
&lt;p&gt;I recommend &lt;a href="http://www.amazon.com/gp/product/B000SEGIW2/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399373&amp;amp;creativeASIN=B000SEGIW2"&gt;Positioning&lt;/a&gt; for anyone involved in creating something
new. This is a book that I will&amp;nbsp;re-read.&lt;/p&gt;</content><category term="business"></category></entry><entry><title>Emacs or Vim</title><link href="https://pseudofish.com/emacs-or-vim.html" rel="alternate"></link><published>2011-11-25T01:33:00+01:00</published><updated>2011-11-25T01:33:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-11-25:/emacs-or-vim.html</id><summary type="html">&lt;p&gt;After over 12 years of using Vi(m), and a brief fling with TextMate, I
&lt;a href="http://pseudofish.com/blog/2010/09/18/learning-clojure-with-google-app-engine-and-emacs/"&gt;started&lt;/a&gt; &lt;a href="http://pseudofish.com/blog/2011/04/14/emacs-update/"&gt;using&lt;/a&gt; Emacs as my primary&amp;nbsp;editor.&lt;/p&gt;
&lt;h3&gt;Emacs&lt;/h3&gt;
&lt;p&gt;The switch has been very positive. The learning curve has been
relatively steep, as my expectations from a text editor are quite&amp;nbsp;high.&lt;/p&gt;
&lt;p&gt;Emacs strength (and weakness …&lt;/p&gt;</summary><content type="html">&lt;p&gt;After over 12 years of using Vi(m), and a brief fling with TextMate, I
&lt;a href="http://pseudofish.com/blog/2010/09/18/learning-clojure-with-google-app-engine-and-emacs/"&gt;started&lt;/a&gt; &lt;a href="http://pseudofish.com/blog/2011/04/14/emacs-update/"&gt;using&lt;/a&gt; Emacs as my primary&amp;nbsp;editor.&lt;/p&gt;
&lt;h3&gt;Emacs&lt;/h3&gt;
&lt;p&gt;The switch has been very positive. The learning curve has been
relatively steep, as my expectations from a text editor are quite&amp;nbsp;high.&lt;/p&gt;
&lt;p&gt;Emacs strength (and weakness) is that it is incredibly extensible. Where
I&amp;#8217;m finding Emacs a win over Vim is that I don&amp;#8217;t have to leave Emacs to
get things done. With Vim, I tend to use more of a mix of terminal
windows and the&amp;nbsp;editor.&lt;/p&gt;
&lt;p&gt;I began by using the &lt;a href="https://github.com/technomancy/emacs-starter-kit"&gt;starter kit&lt;/a&gt; to get going with Emacs
configuration. This made it quicker to get moving, but added a lot of
things I ended up not needing. After getting more comfortable with
elisp, I started from scratch and rebuilt my &lt;a href="https://github.com/gmwils/dotfiles/tree/master/emacs.d"&gt;emacs.d folder&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To jump in quickly, I also purchased the tutorial video from
&lt;a href="https://peepcode.com/products/meet-emacs"&gt;Peepcode&lt;/a&gt;. This certainly helped as emacs is a mental shift coming
from&amp;nbsp;Vim.&lt;/p&gt;
&lt;p&gt;The big benefit I have found with Emacs is the extension packages. These
can be installed from the &lt;span class="caps"&gt;ELPA&lt;/span&gt; &lt;a href="http://www.emacswiki.org/emacs/ELPA"&gt;repository&lt;/a&gt;, and include a range of
different &lt;em&gt;modes&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Some of my favourite modes&amp;nbsp;include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.emacswiki.org/emacs/ParEdit"&gt;paredit&lt;/a&gt; - essential for any lisp, it ensures your brackets&amp;nbsp;match.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jblevins.org/projects/deft/"&gt;deft&lt;/a&gt; - simplified note taking. (I it sync via &lt;a href="http://emacs-fu.blogspot.com/2011/09/quick-note-taking-with-deft-and-org.html"&gt;Dropbox&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.emacswiki.org/emacs/Magit"&gt;magit&lt;/a&gt; - comprehensive Git workflow within&amp;nbsp;Emacs&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jblevins.org/projects/markdown-mode/"&gt;markdown-mode&lt;/a&gt; - my current default for writing notes, although
    I&amp;#8217;m leaning towards org-mode&amp;nbsp;now.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://orgmode.org/"&gt;org-mode&lt;/a&gt; - highly capable note taking mode, with export options
    to everything. You can use it to write a book, create slides, or
    manage your todo&amp;nbsp;list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the Mac, I&amp;#8217;ve been using &lt;a href="http://aquamacs.org/"&gt;Aquamacs&lt;/a&gt; for most of my text editing,
and used &lt;a href="http://www.macports.org/"&gt;macports&lt;/a&gt; to install the command line&amp;nbsp;client.&lt;/p&gt;
&lt;p&gt;I have yet to try Emacs on Windows, as I haven&amp;#8217;t been using Windows much
at all. There is a release available &lt;a href="http://www.gnu.org/software/emacs/windows/Getting-Emacs.html#Getting-Emacs"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After cleaning up my .emacs.d configuration, I&amp;#8217;ve now started using
Emacs on Linux servers I use regularly. For temporary servers, I&amp;#8217;ll
fallback to Vim as Emacs is often not&amp;nbsp;installed.&lt;/p&gt;
&lt;p&gt;If you want to improve your emacs skills follow @&lt;a href="https://twitter.com/emacs_knight"&gt;emacs_knight&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Vim&lt;/h3&gt;
&lt;p&gt;To get started with Vim, it is worth reading &lt;a href="http://robots.thoughtbot.com/post/13164810557/the-vim-learning-curve-is-a-myth"&gt;The Vim Learning Curve is
a Myth&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Over the years, the popular mythology around vim has become that it’s
insanely difficult to learn; a task to be attempted by only those with
the thickest of neck-beards. I’ve heard dozens of times from folks who
are convinced it will take them months to reach&amp;nbsp;proficiency.&lt;/p&gt;
&lt;p&gt;These beliefs are &lt;em&gt;false&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My feeling is that Vim is unrivalled for the simple task of text
editing. Even after a day or two of learning, you will be&amp;nbsp;faster.&lt;/p&gt;
&lt;p&gt;Where things get a bit more complicated is when you start to realise
that text editing isn&amp;#8217;t the whole story for a text&amp;nbsp;editor.&lt;/p&gt;
&lt;p&gt;Platform support is superb. The first thing I do to a Windows machine is
install &lt;a href="http://www.vim.org/download.php"&gt;Vim&lt;/a&gt;. It is rare for an application with a Unix heritage to
be so comfortable on&amp;nbsp;Windows.&lt;/p&gt;
&lt;p&gt;Historically, I hadn&amp;#8217;t been a fan of the graphical version of
&lt;a href="http://code.google.com/p/macvim/"&gt;MacVim&lt;/a&gt;. This is something that is much better in recent releases.
Load times are much&amp;nbsp;improved.&lt;/p&gt;
&lt;p&gt;Integration into external tools is where I feel Vim is lacking a bit.
With the number of developers migrating from TextMate to Vim, this gap
is being rapidly addressed. However, Vim isn&amp;#8217;t as extensible as some
other&amp;nbsp;editors.&lt;/p&gt;
&lt;p&gt;I really noticed this when trying out Clojure programming. If you are
dealing with a &lt;span class="caps"&gt;REPL&lt;/span&gt; based environment, Vim has a way to&amp;nbsp;go.&lt;/p&gt;
&lt;h3&gt;Closing&amp;nbsp;Thoughts&lt;/h3&gt;
&lt;p&gt;If you aren&amp;#8217;t using either of them, it&amp;#8217;s not too late to start. You
can&amp;#8217;t make a bad&amp;nbsp;choice.&lt;/p&gt;
&lt;p&gt;If you are already using either Emacs or Vim,&amp;nbsp;enjoy!&lt;/p&gt;
&lt;p&gt;Both are great editors that allow you to be incredibly productive at
working with text. Try learning a new feature each week. You use your
text editor so often that a small improvement is a major&amp;nbsp;payoff.&lt;/p&gt;</content><category term="emacs"></category></entry><entry><title>Calculating earlier dates using a shell script</title><link href="https://pseudofish.com/calculating-earlier-dates-using-a-shell-script.html" rel="alternate"></link><published>2011-10-07T01:40:00+02:00</published><updated>2011-10-07T01:40:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-10-07:/calculating-earlier-dates-using-a-shell-script.html</id><summary type="html">&lt;p&gt;Mongo has a database size limit in 32 bit mode, so I want to purge out
items that are less than a certain date in the past. I decided that it
would be easy to write a simple shell script to run the&amp;nbsp;query.&lt;/p&gt;
&lt;p&gt;The tricky part was calculating dates …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Mongo has a database size limit in 32 bit mode, so I want to purge out
items that are less than a certain date in the past. I decided that it
would be easy to write a simple shell script to run the&amp;nbsp;query.&lt;/p&gt;
&lt;p&gt;The tricky part was calculating dates in shell. This is what I ended up&amp;nbsp;with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="nv"&gt;MONTHS_AGO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="nv"&gt;DATE_AGO_EPOCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;date&lt;span class="w"&gt; &lt;/span&gt;+%s&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$MONTHS_AGO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;31&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3600&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="nv"&gt;OSTYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;uname&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;FORMAT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;+%Y-%m-%d&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Linux&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OSTYPE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;DATE_AGO_ISO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;date&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1970-01-01 00:00 UTC + &lt;/span&gt;&lt;span class="nv"&gt;$DATE_AGO_EPOCH&lt;/span&gt;&lt;span class="s2"&gt; seconds&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FORMAT&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;DATE_AGO_ISO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;date&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DATE_AGO_EPOCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FORMAT&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="nv"&gt;DB_CMD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;db.items.find( { publish_date : { \$lt : \&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$DATE_AGO_ISO&lt;/span&gt;&lt;span class="s2"&gt;\&amp;quot; } } ).count()&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;# DB_CMD=&amp;quot;db.items.remove( { publish_date : { \$lt : \&amp;quot;$DATE_AGO_ISO\&amp;quot; } } )&amp;quot;&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DB_CMD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mongo&lt;span class="w"&gt; &lt;/span&gt;pz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This now provides a simple way of purging out old items that can be
called from&amp;nbsp;cron.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>Storm - a real time Hadoop like system in Clojure</title><link href="https://pseudofish.com/storm-a-real-time-hadoop-like-system-in-clojure.html" rel="alternate"></link><published>2011-09-26T02:33:00+02:00</published><updated>2011-09-26T02:33:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-09-26:/storm-a-real-time-hadoop-like-system-in-clojure.html</id><summary type="html">&lt;p&gt;I am very excited about the potential unleashed by &lt;a href="https://github.com/nathanmarz/storm"&gt;Storm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Previously at BackType, &lt;a href="https://twitter.com/nathanmarz"&gt;Nathan Marz&lt;/a&gt; has now built Storm into Twitter
and then open sourced the&amp;nbsp;platform.&lt;/p&gt;
&lt;p&gt;Storm opens up a lot of possibilities, by bringing real-time distributed
processing together in an elegant way. And it is built in&amp;nbsp;Clojure …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I am very excited about the potential unleashed by &lt;a href="https://github.com/nathanmarz/storm"&gt;Storm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Previously at BackType, &lt;a href="https://twitter.com/nathanmarz"&gt;Nathan Marz&lt;/a&gt; has now built Storm into Twitter
and then open sourced the&amp;nbsp;platform.&lt;/p&gt;
&lt;p&gt;Storm opens up a lot of possibilities, by bringing real-time distributed
processing together in an elegant way. And it is built in&amp;nbsp;Clojure!&lt;/p&gt;
&lt;p&gt;Some useful&amp;nbsp;links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nathanmarz/storm/wiki/Rationale"&gt;Rationale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.slideshare.net/nathanmarz/storm-distributed-and-faulttolerant-realtime-computation"&gt;Slides&lt;/a&gt; - detailed presentation on Storm by&amp;nbsp;Nathan&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nathanmarz/storm-starter"&gt;Starter project&lt;/a&gt; - a few basic demo use&amp;nbsp;cases&lt;/li&gt;
&lt;li&gt;&lt;a href="http://groups.google.com/group/storm-user"&gt;Mailing&amp;nbsp;List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://storm.twitsprout.com/"&gt;Taking the Emmys by Storm&lt;/a&gt; - an hour long video of how to use
    Storm to aggregate data from Twitter in realtime to spot&amp;nbsp;trends.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While playing around I wanted to try from Clojure (most examples are in
Java). There is a great &lt;span class="caps"&gt;DSL&lt;/span&gt; for Clojure that makes using Storm super
easy. I forked the &lt;a href="https://github.com/gmwils/storm-starter/"&gt;storm-starter&lt;/a&gt; project to add &lt;a href="https://github.com/gmwils/storm-starter/blob/master/src/clj/storm/starter/wordcount.clj"&gt;examples&lt;/a&gt; based
on a &lt;a href="https://gist.github.com/1228302"&gt;Gist&lt;/a&gt; from&amp;nbsp;Nathan.&lt;/p&gt;</content><category term="clojure"></category></entry><entry><title>Java interop with Clojure and Mahout</title><link href="https://pseudofish.com/java-interop-with-clojure-and-mahout.html" rel="alternate"></link><published>2011-08-24T02:13:00+02:00</published><updated>2011-08-24T02:13:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-08-24:/java-interop-with-clojure-and-mahout.html</id><summary type="html">&lt;p&gt;While porting a simple example of generating a Hadoop file for Mahout, I
came across a number of edge cases of the Clojure &lt;a href="http://clojure.org/java_interop"&gt;Java interop&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Nested&amp;nbsp;Classes&lt;/h3&gt;
&lt;p&gt;Java allows for classes to be nested. However, Clojure doesn&amp;#8217;t provide
an obvious way of referencing&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;For example, Hadoop&amp;#8217;s &lt;a href="http://hadoop.apache.org/common/docs/current/api/org/apache/hadoop/io/SequenceFile.html"&gt;SequenceFile …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;While porting a simple example of generating a Hadoop file for Mahout, I
came across a number of edge cases of the Clojure &lt;a href="http://clojure.org/java_interop"&gt;Java interop&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Nested&amp;nbsp;Classes&lt;/h3&gt;
&lt;p&gt;Java allows for classes to be nested. However, Clojure doesn&amp;#8217;t provide
an obvious way of referencing&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;For example, Hadoop&amp;#8217;s &lt;a href="http://hadoop.apache.org/common/docs/current/api/org/apache/hadoop/io/SequenceFile.html"&gt;SequenceFile&lt;/a&gt; includes SequenceFile.Writer and&amp;nbsp;SequenceFile.Reader.&lt;/p&gt;
&lt;p&gt;To access these in Clojure, the period is replaced by a dollar&amp;nbsp;sign.&lt;/p&gt;
&lt;p&gt;For &lt;a href="https://github.com/gmwils/mahoutinaction/blob/master/src/mahoutinaction/ch08.clj"&gt;example&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;ns &lt;/span&gt;&lt;span class="nv"&gt;example&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;org.apache.hadoop.io&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;SequenceFile$Writer&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

&lt;span class="nv"&gt;...&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;writer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;SequenceFile$Writer.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;fs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;conf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;
&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;class &lt;/span&gt;&lt;span class="nv"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;class &lt;/span&gt;&lt;span class="nv"&gt;VectorWritable&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nv"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://groups.google.com/group/clojure/browse_thread/thread/3f86ac8939ef970c"&gt;This thread&lt;/a&gt; on the mailing list has some more&amp;nbsp;details.&lt;/p&gt;
&lt;h3&gt;Generics&lt;/h3&gt;
&lt;p&gt;From the Java code, generics add annotations about the type. However, at
the &lt;span class="caps"&gt;JVM&lt;/span&gt; level, generics are nowhere to be seen. It turns out that
generics are a compiler level feature&amp;nbsp;only.&lt;/p&gt;
&lt;p&gt;What this means for Clojure is that you can safely ignore them, provided
that you honour the types that are included in the&amp;nbsp;generic.&lt;/p&gt;
&lt;p&gt;Thus the following&amp;nbsp;Java:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NamedVector&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;apples&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NamedVector&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Can be written in&amp;nbsp;Clojure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;apples&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ArrayList.&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The responsibility is then on the programmer to ensure the types put
into the&amp;nbsp;collection.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://groups.google.com/group/clojure/browse_thread/thread/39ee5e1c8e9dab44?pli=1"&gt;This thread&lt;/a&gt; on the mailing list has some&amp;nbsp;background.&lt;/p&gt;
&lt;h3&gt;Primitive&amp;nbsp;Arrays&lt;/h3&gt;
&lt;p&gt;I started out looking at how to construct a &lt;code&gt;double[]&lt;/code&gt; to pass to
&lt;a href="http://search-lucene.com/jd/mahout/math/org/apache/mahout/math/DenseVector.html#DenseVector(double[])"&gt;DenseVector&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Turns out that there are a number of things to be wary of when
constructing primitive arrays. &lt;a href="http://measuringmeasures.com/bradfordcross/"&gt;Bradford Cross&lt;/a&gt; has written this up
with examples in &lt;a href="http://measuringmeasures.com/blog/2010/3/27/fast-clojure-vectors-and-multidimensional-arrays.html"&gt;a blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The considerations I took away&amp;nbsp;were:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;double-array&lt;/code&gt; function to migrate a Clojure data&amp;nbsp;structure&lt;/li&gt;
&lt;li&gt;&lt;code&gt;make-array&lt;/code&gt; with &lt;code&gt;Double/TYPE&lt;/code&gt; to pre-allocate the&amp;nbsp;array&lt;/li&gt;
&lt;li&gt;Type hints should be&amp;nbsp;considered&lt;/li&gt;
&lt;li&gt;Odd things are likely to be happening with type coercion, so check
    run time&amp;nbsp;performance.&lt;/li&gt;
&lt;/ol&gt;</content><category term="clojure"></category></entry><entry><title>McKinsey on testing your strategy</title><link href="https://pseudofish.com/mckinsey-on-testing-your-strategy.html" rel="alternate"></link><published>2011-08-22T18:09:00+02:00</published><updated>2011-08-22T18:09:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-08-22:/mckinsey-on-testing-your-strategy.html</id><summary type="html">&lt;p&gt;In &lt;a href="https://www.mckinseyquarterly.com/Strategy/Strategic_Thinking/Have_you_tested_your_strategy_lately_2711"&gt;an article&lt;/a&gt; from January 2011, McKinsey outlines a series of ten
tests to validate your current&amp;nbsp;strategy:&lt;/p&gt;
&lt;p&gt;Summary of the&amp;nbsp;tests:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Will your strategy beat the&amp;nbsp;market?&lt;/li&gt;
&lt;li&gt;Does your strategy tap a true source of&amp;nbsp;advantage?&lt;/li&gt;
&lt;li&gt;Is your strategy granular about where to&amp;nbsp;compete?&lt;/li&gt;
&lt;li&gt;Does your strategy put you …&lt;/li&gt;&lt;/ol&gt;</summary><content type="html">&lt;p&gt;In &lt;a href="https://www.mckinseyquarterly.com/Strategy/Strategic_Thinking/Have_you_tested_your_strategy_lately_2711"&gt;an article&lt;/a&gt; from January 2011, McKinsey outlines a series of ten
tests to validate your current&amp;nbsp;strategy:&lt;/p&gt;
&lt;p&gt;Summary of the&amp;nbsp;tests:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Will your strategy beat the&amp;nbsp;market?&lt;/li&gt;
&lt;li&gt;Does your strategy tap a true source of&amp;nbsp;advantage?&lt;/li&gt;
&lt;li&gt;Is your strategy granular about where to&amp;nbsp;compete?&lt;/li&gt;
&lt;li&gt;Does your strategy put you ahead of&amp;nbsp;trends?&lt;/li&gt;
&lt;li&gt;Does your strategy rest on privileged&amp;nbsp;insights?&lt;/li&gt;
&lt;li&gt;Does your strategy embrace&amp;nbsp;uncertainty?&lt;/li&gt;
&lt;li&gt;Does your strategy balance commitment and&amp;nbsp;flexibility?&lt;/li&gt;
&lt;li&gt;Is your strategy contaminated by&amp;nbsp;bias?&lt;/li&gt;
&lt;li&gt;Is there conviction to act on your&amp;nbsp;strategy?&lt;/li&gt;
&lt;li&gt;Have you translated your strategy into an action&amp;nbsp;plan?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each test includes a more detailed description, and an example of a
company or industry where it is particularly relevant. There are also
links through to relevant articles or&amp;nbsp;books.&lt;/p&gt;
&lt;p&gt;Although aimed at corporate strategy, this is an interesting list of
points to consider at a personal or project level as&amp;nbsp;well.&lt;/p&gt;</content><category term="business"></category></entry><entry><title>Calling Mahout from Clojure</title><link href="https://pseudofish.com/calling-mahout-from-clojure.html" rel="alternate"></link><published>2011-08-18T18:07:00+02:00</published><updated>2011-08-18T18:07:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-08-18:/calling-mahout-from-clojure.html</id><summary type="html">&lt;p&gt;Mahout is a set of libraries for running machine learning processes,
such as recommendation, clustering and&amp;nbsp;categorisation.&lt;/p&gt;
&lt;p&gt;The libraries work against an abstract model that can be anything from a
file to a full Hadoop cluster. This means you can start playing around
with small data sets in files, a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Mahout is a set of libraries for running machine learning processes,
such as recommendation, clustering and&amp;nbsp;categorisation.&lt;/p&gt;
&lt;p&gt;The libraries work against an abstract model that can be anything from a
file to a full Hadoop cluster. This means you can start playing around
with small data sets in files, a local database, a Hadoop cluster or a
custom data&amp;nbsp;store.&lt;/p&gt;
&lt;p&gt;After a bit of &lt;a href="http://groups.google.com/group/clojure/browse_thread/thread/6e01fd108c32d701?pli=1"&gt;research&lt;/a&gt;, it turned out not to be too complex to call
via any &lt;span class="caps"&gt;JVM&lt;/span&gt; language. When you compile and install Mahout, the libraries
are installed into your local Maven cache. This makes it very easy to
include them into any &lt;span class="caps"&gt;JVM&lt;/span&gt; type&amp;nbsp;project.&lt;/p&gt;
&lt;p&gt;To help work through the various features, I&amp;#8217;m reading the early access
edition of &lt;a href="http://www.manning.com/owen/"&gt;Mahout in Action&lt;/a&gt;. I am trying out the &lt;a href="http://www.manning.com/owen/MIA_Recommender_code_archive.zip"&gt;examples&lt;/a&gt; in
Clojure as I read&amp;nbsp;through.&lt;/p&gt;
&lt;p&gt;To get started, the following steps will setup a Clojure project to work
with&amp;nbsp;Mahout:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://cwiki.apache.org/MAHOUT/buildingmahout.html"&gt;Build and install&amp;nbsp;Mahout&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The process installs the Mahout jars into your local maven
repository, making them accessible to&amp;nbsp;lein.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new&amp;nbsp;project&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;lein new mahoutexample
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add dependencies to &lt;a href="https://github.com/gmwils/mahoutinaction/blob/master/project.clj"&gt;project.clj&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For&amp;nbsp;example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;:dependencies [
  [org.clojure/clojure &amp;quot;1.2.1&amp;quot;]
  [org.apache.mahout/mahout-core &amp;quot;0.5&amp;quot;]
  [org.apache.mahout/mahout-math &amp;quot;0.5&amp;quot;]
  [org.apache.mahout/mahout-utils &amp;quot;0.5&amp;quot;]]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then load the dependencies into your&amp;nbsp;project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;lein deps
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add your&amp;nbsp;code&lt;/p&gt;
&lt;p&gt;For example, &lt;a href="https://github.com/gmwils/mahoutinaction/blob/master/src/mahoutinaction/ch02.clj"&gt;ch02.clj&lt;/a&gt; shows calling a recommendation&amp;nbsp;engine.&lt;/p&gt;
&lt;p&gt;The time consuming part is adding in the right import&amp;nbsp;statements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Evaluate from the &lt;span class="caps"&gt;REPL&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This is where it gets fun. Clojure makes it easy to try out
different data sets and learning algorithms to rapidly&amp;nbsp;iterate.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[Optional] Add a run&amp;nbsp;task&lt;/p&gt;
&lt;p&gt;In &lt;a href="https://github.com/gmwils/mahoutinaction/blob/master/project.clj"&gt;project.clj&lt;/a&gt;, you can assign a class as the main class. Lein
will attempt to find a function called &amp;#8220;&lt;a href="https://github.com/gmwils/mahoutinaction/blob/master/src/mahoutinaction/core.clj#L12"&gt;-main&lt;/a&gt;&amp;#8221; and call&amp;nbsp;that.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;lein run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As an example, I&amp;#8217;ve ported the first chapter of the book to Clojure and
it is available on &lt;a href="https://github.com/gmwils/mahoutinaction"&gt;github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some other articles on using parts of Mahout with Clojure are the &lt;em&gt;opus
artificem probat&lt;/em&gt;&amp;nbsp;blog:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://antoniogarrote.wordpress.com/2011/05/08/visualizing-mahouts-output-with-clojure-and-incanter/"&gt;Visualizing Mahout’s output with Clojure and&amp;nbsp;Incanter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://antoniogarrote.wordpress.com/2011/06/26/monte-carlo-integration-with-clojure-and-mahout/"&gt;Monte Carlo integration with Clojure and&amp;nbsp;Mahout&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="technology"></category></entry><entry><title>Book Reviews</title><link href="https://pseudofish.com/book-reviews.html" rel="alternate"></link><published>2011-08-12T15:54:00+02:00</published><updated>2011-08-12T15:54:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-08-12:/book-reviews.html</id><summary type="html">&lt;p&gt;I&amp;#8217;ve read a few books this year, thanks to Kindle for iPhone &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Mac as
well as a few actual printed books either found or borrowed from work&amp;#8217;s
extensive library (one of my favourite parts of our Stockholm&amp;nbsp;office).&lt;/p&gt;
&lt;p&gt;These are my&amp;nbsp;highlights.&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://www.amazon.com/gp/product/1558601910/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=1558601910"&gt;Paradigms of &lt;span class="caps"&gt;AI&lt;/span&gt;&amp;nbsp;Programming&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After re-discovering …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve read a few books this year, thanks to Kindle for iPhone &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Mac as
well as a few actual printed books either found or borrowed from work&amp;#8217;s
extensive library (one of my favourite parts of our Stockholm&amp;nbsp;office).&lt;/p&gt;
&lt;p&gt;These are my&amp;nbsp;highlights.&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://www.amazon.com/gp/product/1558601910/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=1558601910"&gt;Paradigms of &lt;span class="caps"&gt;AI&lt;/span&gt;&amp;nbsp;Programming&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After re-discovering Lisp style programming with Clojure, this book came
high on my to-read list and I was not&amp;nbsp;disappointed.&lt;/p&gt;
&lt;p&gt;The book covers a wide range of classic &lt;span class="caps"&gt;AI&lt;/span&gt; problems, and walks through
solutions in Common Lisp. This makes the book partly about solving &lt;span class="caps"&gt;AI&lt;/span&gt;
problems, and partly an advanced book on Lisp&amp;nbsp;programming.&lt;/p&gt;
&lt;p&gt;I loved it for both&amp;nbsp;aspects.&lt;/p&gt;
&lt;p&gt;Be warned however, Peter Norvig is a master of his tools and reading
along you can be seduced into how obvious each next step is. It is worth
trying to implement some of these algorithms yourself, or even try
solving &lt;a href="http://norvig.com/sudoku.html"&gt;Sudoku&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This book won&amp;#8217;t make you an expert on the latest &lt;span class="caps"&gt;AI&lt;/span&gt; techniques, but it
will add to the class of problems you can solve, and make you a better&amp;nbsp;programmer.&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://www.amazon.com/gp/product/1416596585/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=1416596585"&gt;Into the&amp;nbsp;Plex&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A great insight into the history and workings of Google. There are lots
of examples of how Google goes about solving problems and lots of behind
the scenes&amp;nbsp;information.&lt;/p&gt;
&lt;p&gt;One section I found interesting was on staff&amp;nbsp;allocation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Around 2005, Google determined a simple formula to distribute its
engineering talent: 70-20-10. Seventy percent of its engineers would
work in either search or ads. Twenty percent would focus on key
products such as applications. The remaining 10 percent would work on
wild cards, which often emerged from the 20 percent time where people
could choose their own&amp;nbsp;projects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;&lt;a href="http://www.amazon.com/gp/product/069114592X/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=069114592X"&gt;Animal&amp;nbsp;Spirits&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After finishing Robert Schiller&amp;#8217;s course on &lt;a href="http://itunes.apple.com/us/itunes-u/financial-markets-video/id341651306"&gt;finance via iTunes
University&lt;/a&gt;, I picked up his book Animal&amp;nbsp;Spirits.&lt;/p&gt;
&lt;p&gt;This is an approachable book that doesn&amp;#8217;t assume too much finance
background, and covers how behavioural finance fits into a macro
economic framework. Or rather, how human emotions messes up existing
approaches to making decisions for the broad&amp;nbsp;economy.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re interested in how government should be setting policy, or how
human psychology impacts economics, this is well worth a&amp;nbsp;read.&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://www.amazon.com/gp/product/0915299143/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0915299143"&gt;Toyota Production&amp;nbsp;System&lt;/a&gt;&lt;/h3&gt;
&lt;h3&gt;&lt;a href="http://www.amazon.com/gp/product/0071392319/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0071392319"&gt;The Toyota&amp;nbsp;Way&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I started by reading Toyota Production System, as the Toyota Way was
already loaned out. This turned out to be&amp;nbsp;fortuitous.&lt;/p&gt;
&lt;p&gt;The Toyota Production System is written by &lt;a href="http://en.wikipedia.org/wiki/Taiichi_Ohno"&gt;Taiichi Ohno&lt;/a&gt;, who was
responsible for putting in place most of the practices that define their
production system. The book is translated from the Japanese, and reads
like the writings of a Zen master. Everything is very clear and concise
with no superfluous words or&amp;nbsp;explanations.&lt;/p&gt;
&lt;p&gt;I found it enlightening. However, it is worth pausing often throughout
the book to ponder the implications of what has been said, and was it
assumes. This is a book to read to understand the fundamentals and the
attitude required to implement a similar approach to your&amp;nbsp;business.&lt;/p&gt;
&lt;p&gt;The Toyota Way is an easier read, and based on the time Jeffrey Liker
has spent studying Toyota. He had access to a range of plants in the &lt;span class="caps"&gt;US&lt;/span&gt;
and interviewed many of the key Toyota people. His book is written as a
series of stories that act as a set of case studies for how the Toyota
Way was applied to a range of engineering&amp;nbsp;challenges.&lt;/p&gt;
&lt;p&gt;I particularly loved the chapters explaining how Toyota created the
Lexus brand and the&amp;nbsp;Prius.&lt;/p&gt;
&lt;p&gt;To get a good understanding of how Toyota works, it is worth reading
both books. I feel like it is clearer on how Kanban fits into a wider
corporate picture, after having previously read &lt;a href="http://pseudofish.com/blog/2011/04/19/kanban-agile-development/"&gt;David Anderson&amp;#8217;s
book&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://www.amazon.com/gp/product/015602943X/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=015602943X"&gt;The Time Traveller&amp;#8217;s&amp;nbsp;Wife&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This was left by a previous occupant of the apartment we rented for the
summer in Paris. It was a great holiday&amp;nbsp;read.&lt;/p&gt;
&lt;p&gt;Suspend disbelief for a while, and just let the story flow. The
characters are well thought out and carry the story&amp;nbsp;well.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>Prolog in Clojure</title><link href="https://pseudofish.com/prolog-in-clojure.html" rel="alternate"></link><published>2011-08-05T16:31:00+02:00</published><updated>2011-08-05T16:31:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-08-05:/prolog-in-clojure.html</id><summary type="html">&lt;p&gt;After reading Peter Novig&amp;#8217;s classic, &lt;a href="http://www.amazon.com/gp/product/1558601910/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=1558601910"&gt;Paradigms of &lt;span class="caps"&gt;AI&lt;/span&gt; Programming&lt;/a&gt;, I
decided to try porting his implementation of Prolog in Lisp to&amp;nbsp;Clojure.&lt;/p&gt;
&lt;p&gt;The initial results are available on &lt;a href="http://github.com/gmwils/clj-prolog"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The interpreter allows solving of simple &lt;a href="http://www.allisons.org/ll/Logic/Prolog/Examples/witch/"&gt;logic problems&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;witch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;burns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;female&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;burns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wooden&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wooden&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;After reading Peter Novig&amp;#8217;s classic, &lt;a href="http://www.amazon.com/gp/product/1558601910/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=1558601910"&gt;Paradigms of &lt;span class="caps"&gt;AI&lt;/span&gt; Programming&lt;/a&gt;, I
decided to try porting his implementation of Prolog in Lisp to&amp;nbsp;Clojure.&lt;/p&gt;
&lt;p&gt;The initial results are available on &lt;a href="http://github.com/gmwils/clj-prolog"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The interpreter allows solving of simple &lt;a href="http://www.allisons.org/ll/Logic/Prolog/Examples/witch/"&gt;logic problems&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;witch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;burns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;female&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;burns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wooden&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wooden&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;floats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;floats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sameweight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Duck&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;?x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;female&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Girl&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sameweight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Duck&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Girl&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;?-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;witch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Girl&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Porting this turned out to be an interesting challenge. There were a few
Lisp functions that weren&amp;#8217;t available in Clojure, along with some subtle
changes in&amp;nbsp;idiom.&lt;/p&gt;
&lt;p&gt;This gave me an opportunity to dive further into Clojure and think about
how to implement the algorithms and data structures in a way that made
sense, yet was still close to the&amp;nbsp;original.&lt;/p&gt;
&lt;p&gt;There is still much to do, as the book further develops the interpreter
with user interaction and then refactors it into a compiler. Should keep
me busy for a while&amp;nbsp;longer!&lt;/p&gt;
&lt;p&gt;Note: Please don&amp;#8217;t consider this production code. If you want to look
deeper at logic programming, consider either a real Prolog
implementation, the &lt;a href="https://github.com/clojure/core.logic"&gt;core.logic&lt;/a&gt; library in Clojure or check out
&lt;a href="http://www.mercury.csse.unimelb.edu.au/"&gt;Mercury&lt;/a&gt;.&lt;/p&gt;</content><category term="clojure"></category></entry><entry><title>Stockholm Tourist Sights</title><link href="https://pseudofish.com/stockholm-tourist-sights.html" rel="alternate"></link><published>2011-07-30T19:00:00+02:00</published><updated>2011-07-30T19:00:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-07-30:/stockholm-tourist-sights.html</id><summary type="html">&lt;p&gt;This is my current list of things to do and see if you happen to be
visiting Stockholm for a weekend or a bit longer. The list is based on
things we&amp;#8217;ve seen, or that friends have&amp;nbsp;found.&lt;/p&gt;
&lt;p&gt;To get up-to-date tips, contact me directly or via Twitter
(@&lt;a href="http://twitter.com/gmwils"&gt;gmwils …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is my current list of things to do and see if you happen to be
visiting Stockholm for a weekend or a bit longer. The list is based on
things we&amp;#8217;ve seen, or that friends have&amp;nbsp;found.&lt;/p&gt;
&lt;p&gt;To get up-to-date tips, contact me directly or via Twitter
(@&lt;a href="http://twitter.com/gmwils"&gt;gmwils&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Fjäderholmarna, Stockholm Archipeligo" src="http://farm7.static.flickr.com/6026/5987241892_973d037135.jpg" title="Fjäderholmarna, Stockholm Archipeligo"&gt;&lt;/p&gt;
&lt;h3&gt;Sights&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://vasamuseet.se/en/"&gt;Vasa Museum&lt;/a&gt; — an old ship that has been preserved due to failure
    to launch. Interesting museum on maritime history. There are
    sometimes queues to get in, so may be worth a morning&amp;nbsp;visit.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Nordic_Museum"&gt;Nordic Museum&lt;/a&gt; — provides a history of the nordic region, and is
    just near the Vasa&amp;nbsp;Museum.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.skansen.se/en/"&gt;Skansen&lt;/a&gt; — an open air museum / zoo / cultural centre. This whole
    park is quite large, so it is worth spending a full day, as there is
    lots to do. A good chance to see reindeer and moose in&amp;nbsp;Stockholm.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.fotografiska.eu/"&gt;Fotographiska&lt;/a&gt; — a photography museum / gallery on Södermalm.
    Three floors of photography, with a nice café with a view of
    Stockholm on the top&amp;nbsp;floor.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.modernamuseet.se/en/Stockholm/"&gt;Modern Art Museum&lt;/a&gt; — meant to be quite good, but still on my todo&amp;nbsp;list.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Gamla_stan"&gt;Gamla Stan&lt;/a&gt; - well worth half a day wandering around, see the
    palace, explore the streets. Almost everything is over priced, but
    then it is the main tourist district. It also has some of the better
    restaurants in&amp;nbsp;town.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Södermalm"&gt;Södermalm&lt;/a&gt; — itself is one of the nicer areas of Stockholm. The
    shore of the island on the south is a popular place for hanging out.
    There are lots of nice restaurants near Slussen on the northern side
    too. The cliffs above Slussen provide a good vantage point to see
    Galma Stan (old town) and the city in&amp;nbsp;general.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Östermalm"&gt;Östermalm&lt;/a&gt; — a nice area in between the city centre and
    Djurgården island (where the Vasa &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Skansen are). Lots of nice cafés
    to pass the day&amp;nbsp;in.&lt;/li&gt;
&lt;li&gt;Boat trips — there are ferries that shuttle between the various
    islands and make a nice way to get from Skeppholmen to&amp;nbsp;Djurgården.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.thelocal.se/34460/20110620/"&gt;Stockholm Archipelago&lt;/a&gt; — this city is all about islands, and
    there are a number of boat cruises that leave for the &lt;a href="http://www.thelocal.se/34460/20110620/"&gt;wider
    Archipelago&lt;/a&gt;. We visited Fjäderholmarna,
    which is small and close and made for a nice place to wander around.
    The article has some info on boats, they also depart from near&amp;nbsp;Östermalm.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Restaurants&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.rival.se/bistro_bar_cafe/en/default.aspx"&gt;Rival Hotel&lt;/a&gt; — the restaurant here is worth a visit, a short walk
    from Mariatorget&amp;nbsp;station&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.thelocal.se/restaurants/18109/"&gt;Gondolen&lt;/a&gt; — quite a cool location for a restaurant, suspended
    underneath a bridge near Slussen station. We went for drinks at
    their bar, which gives a good view of Stockholm. If you want a seat
    at the restaurant, it is worth booking&amp;nbsp;ahead.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.vetekatten.se/"&gt;Vete-Katten&lt;/a&gt; — Downtown is mostly shops, however if you’re
    wandering around and looking for somewhere for lunch, Vete-Katten
    has a great range of traditional Swedish&amp;nbsp;cakes.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.gyldenefreden.se/dgf_eng/noflash/index_eng_noflash.html"&gt;Den Gyldene Freden&lt;/a&gt; — modern take on tradition Swedish food. We
    found the service to be&amp;nbsp;friendly.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sturehof.com/homeeng"&gt;Sturehof&lt;/a&gt; — interesting restaurant in&amp;nbsp;Östermalm.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.pelikan.se/sidor/eng_history.htm"&gt;Pelikan&lt;/a&gt; — Swedish home style&amp;nbsp;food.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://olivertwist.se/"&gt;Oliver Twist&lt;/a&gt; (House of Ale) — cozy pub in the midst of Södermalm
    with a good range of local beers and hearty pub food. Bookings
    recommended, although we&amp;#8217;ve been lucky&amp;nbsp;before.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.djuret.se/index.php?lang=eng"&gt;Djuret&lt;/a&gt; — means &amp;#8220;the animal&amp;#8221; in Swedish, and they only serve one
    animal at a time. Interesting concept, and has been recommended to&amp;nbsp;me.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For suggestions of coffee places on Södermalm, check out &lt;a href="http://www.thelocal.se/35032/20110719/"&gt;this
article&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Transport&lt;/h3&gt;
&lt;p&gt;To get around, it is worth getting tickets for the underground train
line (Tunnelbana, abbreviated to large signs with a T). It runs pretty
much everywhere and will make it easier to see the&amp;nbsp;city.&lt;/p&gt;
&lt;p&gt;To transfer from the airport, taxi works out cost effective if there are
more than one person travelling. Otherwise, the train system is fast and
easy to&amp;nbsp;navigate.&lt;/p&gt;
&lt;h3&gt;Swedish&amp;nbsp;News&lt;/h3&gt;
&lt;p&gt;For news in English about what is happening in Sweden, try &lt;a href="http://www.thelocal.se/"&gt;The
Local&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For Swedish, &lt;a href="http://www.dn.se/"&gt;&lt;span class="caps"&gt;DN&lt;/span&gt;.se&lt;/a&gt; and for Swedish restaurant reviews try &lt;a href="http://www.pastan.nu/?ref=dntab"&gt;På
Stan&lt;/a&gt; (with &lt;a href="http://translate.google.com/#sv|en|"&gt;Google translate&lt;/a&gt; to&amp;nbsp;help).&lt;/p&gt;
&lt;h3&gt;Language&amp;nbsp;Basics&lt;/h3&gt;
&lt;p&gt;Almost everyone here speaks perfect English as their second language, so
knowing some Swedish isn’t important. That said, some pleasantries
always&amp;nbsp;helps.&lt;/p&gt;
&lt;p&gt;These few phrases will get you&amp;nbsp;far:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hej (pron. “Hey!) — hello, or goodbye, general&amp;nbsp;greeting.&lt;/li&gt;
&lt;li&gt;Hej då (pron. “Hey door”) —&amp;nbsp;goodbye.&lt;/li&gt;
&lt;li&gt;Tack — thanks, and please. Pointing at something and saying tack, or
    saying tack after receiving something is common. You’ll hear this
    word a&amp;nbsp;lot.&lt;/li&gt;
&lt;li&gt;Tack så mycket (pron. “Tack so mickey”) — thank you very much, often
    used at the end of&amp;nbsp;transactions.&lt;/li&gt;
&lt;/ul&gt;</content><category term="musings"></category></entry><entry><title>CS229 Machine Learning at Stanford (iTunes U)</title><link href="https://pseudofish.com/cs229-machine-learning-at-stanford-itunes-u.html" rel="alternate"></link><published>2011-07-29T02:40:00+02:00</published><updated>2011-07-29T02:40:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-07-29:/cs229-machine-learning-at-stanford-itunes-u.html</id><summary type="html">&lt;p&gt;Andrew Ng&amp;#8217;s course at Stanford on &lt;a href="http://www.stanford.edu/class/cs229/"&gt;Machine Learning&lt;/a&gt; provides a great
overview of the different types and applications of current machine
learning algorithms. The course is available for free either on
&lt;a href="http://www.youtube.com/results?search_query=machine+learning+stanford+%22machine+learning%22&amp;amp;as=1&amp;amp;and_queries=machine+learning+stanford&amp;amp;exact_query=machine+learning&amp;amp;or_queries=&amp;amp;negative_queries=&amp;amp;geo_name=stanford+ca&amp;amp;geo_latlong=&amp;amp;search_duration=&amp;amp;search_hl=&amp;amp;search_category_type=specific&amp;amp;search_category=27&amp;amp;search_sort=&amp;amp;uploaded="&gt;YouTube&lt;/a&gt; or subscribe in &lt;a href="http://deimos3.apple.com/WebObjects/Core.woa/Browse/itunes.stanford.edu.1615003397.01615003400.1607367212?i=1436041694"&gt;iTunes University&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Be warned, this is a course on theory, so is taught through …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Andrew Ng&amp;#8217;s course at Stanford on &lt;a href="http://www.stanford.edu/class/cs229/"&gt;Machine Learning&lt;/a&gt; provides a great
overview of the different types and applications of current machine
learning algorithms. The course is available for free either on
&lt;a href="http://www.youtube.com/results?search_query=machine+learning+stanford+%22machine+learning%22&amp;amp;as=1&amp;amp;and_queries=machine+learning+stanford&amp;amp;exact_query=machine+learning&amp;amp;or_queries=&amp;amp;negative_queries=&amp;amp;geo_name=stanford+ca&amp;amp;geo_latlong=&amp;amp;search_duration=&amp;amp;search_hl=&amp;amp;search_category_type=specific&amp;amp;search_category=27&amp;amp;search_sort=&amp;amp;uploaded="&gt;YouTube&lt;/a&gt; or subscribe in &lt;a href="http://deimos3.apple.com/WebObjects/Core.woa/Browse/itunes.stanford.edu.1615003397.01615003400.1607367212?i=1436041694"&gt;iTunes University&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Be warned, this is a course on theory, so is taught through mathematics
rather than programming. You will develop a deeper understanding, but it
may hurt your&amp;nbsp;brain.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://www.stanford.edu/class/cs229/materials.html"&gt;section notes&lt;/a&gt; provide some assistance in reviewing the key
concepts that you&amp;#8217;ll&amp;nbsp;need.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve watched the course, but I keep forgetting which lesson covered
which topic. To remember, I&amp;#8217;ve put together a brief summary&amp;nbsp;below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 — Introduction and&amp;nbsp;overview.&lt;/li&gt;
&lt;li&gt;2 — &lt;a href="http://en.wikipedia.org/wiki/Linear_regression"&gt;Linear regression&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Gradient_descent"&gt;Gradient Descent&lt;/a&gt;, and &lt;a href="http://en.wikipedia.org/wiki/Normal_equations"&gt;Normal
    Equations&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;3 — Linear regression &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; probabilistic interpretation, logistic
    regression (classification algorithm), &lt;a href="http://en.wikipedia.org/wiki/Newton%27s_method"&gt;Newton&amp;#8217;s method&lt;/a&gt; and a
    brief introduction to the &lt;a href="http://en.wikipedia.org/wiki/Perceptron"&gt;Perceptron&lt;/a&gt;&amp;nbsp;algorithm.&lt;/li&gt;
&lt;li&gt;4 — &lt;a href="http://en.wikipedia.org/wiki/Logistic_regression"&gt;Logistic regression&lt;/a&gt; &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Newton&amp;#8217;s method, &lt;a href="http://en.wikipedia.org/wiki/Exponential_family"&gt;Exponential
    Family&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Generalised_linear_model"&gt;Generalised Linear Models&lt;/a&gt;&amp;nbsp;(GLMs).&lt;/li&gt;
&lt;li&gt;5 — Generative learning algorithms, &lt;a href="http://en.wikipedia.org/wiki/Gaussian_discriminant_analysis"&gt;Gaussian Discriminate
    Analysis&lt;/a&gt; (&lt;span class="caps"&gt;GDA&lt;/span&gt;), Generative vs Discriminate algorithms, &lt;a href="http://en.wikipedia.org/wiki/Naive_Bayes_classifier"&gt;Naive
    Bayes&lt;/a&gt;, and &lt;a href="http://en.wikipedia.org/wiki/Laplace_smoothing"&gt;Laplace Smoothing&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;6 — Naive Bayes &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Event Models, &lt;a href="http://en.wikipedia.org/wiki/Artificial_neural_network"&gt;Neural Networks&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Support_vector_machine"&gt;Support Vector
    Machines&lt;/a&gt;&amp;nbsp;(SVMs).&lt;/li&gt;
&lt;li&gt;7 — Optimal Margin Classifier, Primal/Dual optimisation problem
    (&lt;span class="caps"&gt;KKT&lt;/span&gt;), &lt;span class="caps"&gt;SVM&lt;/span&gt; dual, &lt;a href="http://en.wikipedia.org/wiki/Kernel_(statistics)"&gt;Kernels&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;8 — SVMs (Kernels, &lt;a href="http://en.wikipedia.org/wiki/Support_vector_machine#Soft_margin"&gt;Soft Margin&lt;/a&gt;, &lt;span class="caps"&gt;SMO&lt;/span&gt;&amp;nbsp;algorithm)&lt;/li&gt;
&lt;li&gt;9 — Learning theory: Bias/Variance, &lt;a href="http://en.wikipedia.org/wiki/Empirical_risk_minimization"&gt;Empirical Risk Minimisation&lt;/a&gt;
    (&lt;span class="caps"&gt;ERM&lt;/span&gt;), Union Bound/&lt;a href="http://en.wikipedia.org/wiki/Hoeffding%27s_inequality"&gt;Hoeffding inequality&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Uniform_convergence"&gt;Uniform
    Convergence&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;10 — &lt;span class="caps"&gt;VC&lt;/span&gt; dimension, Model selection (cross validation, feature
    selection), Bayesian statistics &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;&amp;nbsp;regularisation.&lt;/li&gt;
&lt;li&gt;11 — Bayesian statistics &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; regularisation, Online Learning, Advice
    for applying &lt;span class="caps"&gt;ML&lt;/span&gt;&amp;nbsp;algorithms.&lt;/li&gt;
&lt;li&gt;12 — &lt;a href="http://en.wikipedia.org/wiki/Cluster_analysis#K-means_and_derivatives"&gt;Clustering&lt;/a&gt; (k-means), &lt;a href="http://en.wikipedia.org/wiki/Mixture_of_gaussians"&gt;Mixture of Gaussians&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Jensen%27s_inequality"&gt;Jensen&amp;#8217;s
    Inequality&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Expectation-maximization_algorithm"&gt;Expectation Maximisation&lt;/a&gt; (&lt;span class="caps"&gt;EM&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;13 — Mixture of Gaussians, Mixture of Naive Bayes, &lt;a href="http://en.wikipedia.org/wiki/Factor_analysis"&gt;Factor
    Analysis&lt;/a&gt;, and more on Gaussian&amp;nbsp;distributions.&lt;/li&gt;
&lt;li&gt;14 — Factor Analysis (&lt;span class="caps"&gt;EM&lt;/span&gt; steps), &lt;a href="http://en.wikipedia.org/wiki/Principle_components_analysis"&gt;Principal Component Analysis&lt;/a&gt;
    (&lt;span class="caps"&gt;PCA&lt;/span&gt;).&lt;/li&gt;
&lt;li&gt;15 — &lt;span class="caps"&gt;PCA&lt;/span&gt;: &lt;a href="http://en.wikipedia.org/wiki/Latent_semantic_indexing"&gt;Latent Semantic Indexing&lt;/a&gt; (&lt;span class="caps"&gt;LSI&lt;/span&gt;), &lt;a href="http://en.wikipedia.org/wiki/Singular_value_decomposition"&gt;Singular Value
    Decomposition&lt;/a&gt; (&lt;span class="caps"&gt;SVD&lt;/span&gt;) algorithm, and &lt;a href="http://en.wikipedia.org/wiki/Independent_component_analysis"&gt;Independent Component
    Analysis&lt;/a&gt; (&lt;span class="caps"&gt;ICA&lt;/span&gt;).&lt;/li&gt;
&lt;li&gt;16 — &lt;a href="http://en.wikipedia.org/wiki/Markov_decision_process"&gt;Markov Decision Process&lt;/a&gt; (MDPs), Value Function, &lt;a href="http://en.wikipedia.org/wiki/Value_iteration#Value_iteration"&gt;Value
    Iteration&lt;/a&gt;, and &lt;a href="http://en.wikipedia.org/wiki/Value_iteration#Policy_iteration"&gt;Policy Iteration&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;17 — Reinforcement learning, using &lt;a href="http://en.wikipedia.org/wiki/Markov_decision_process"&gt;Markov Decision
    Processes&lt;/a&gt; (MDPs), scaled up to continuous
    variables. Motivating example is controlling an inverted pendulum.
    Models of system to control can either be derived (eg. physics
    model) or learned (eg. via a helicopter&amp;nbsp;pilot)&lt;/li&gt;
&lt;li&gt;18 — State Action Rewards, Finite Horizon MDPs, Linear Dynamic
    Systems (Models, &lt;a href="http://en.wikipedia.org/wiki/Linear-quadratic_regulator"&gt;Linear Quadratic Regulation&lt;/a&gt; (&lt;span class="caps"&gt;LQR&lt;/span&gt;), &lt;a href="http://en.wikipedia.org/wiki/Riccati_equation"&gt;Riccati
    equation&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;19 — Debugging &lt;span class="caps"&gt;RL&lt;/span&gt; algorithms, &lt;span class="caps"&gt;LQR&lt;/span&gt; (Differential Dynamic Programming
    (&lt;span class="caps"&gt;DDP&lt;/span&gt;)), &lt;a href="http://en.wikipedia.org/wiki/Kalman_filter"&gt;Kalman Filters&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Linear-quadratic-Gaussian_control"&gt;Linear Quadratic Gaussians&lt;/a&gt; (&lt;span class="caps"&gt;LQG&lt;/span&gt;).&lt;/li&gt;
&lt;li&gt;20 — &lt;a href="http://en.wikipedia.org/wiki/Partially_observable_Markov_decision_process"&gt;POMDPs&lt;/a&gt; (Partially Observable MDPs), Policy Search,
    Reinforce, Pegasus,&amp;nbsp;Conclusion.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;iTunes University is a great way to keep up to date with a range of
topics. Worth checking out to see what else you can&amp;nbsp;find.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>Replacing sublis in Clojure</title><link href="https://pseudofish.com/replacing-sublis-in-clojure.html" rel="alternate"></link><published>2011-07-27T04:06:00+02:00</published><updated>2011-07-27T04:06:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-07-27:/replacing-sublis-in-clojure.html</id><summary type="html">&lt;p&gt;In porting some Lisp code across to Clojure, I was missing the
&lt;a href="http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-ref/xlisp-ref-267.htm"&gt;sublis&lt;/a&gt; function, or at least something&amp;nbsp;similar.&lt;/p&gt;
&lt;p&gt;The closest I could find was &lt;code&gt;replace&lt;/code&gt;, however it failed on nested&amp;nbsp;structures:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;user&amp;gt; (replace &amp;#39;{?x ?x_123} &amp;#39;(?x (?y ?x)))(?x_123 (?y ?x))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;postwalk-replace&lt;/code&gt; from &lt;a href="http://richhickey.github.com/clojure/clojure.walk-api.html"&gt;clojure.walk&lt;/a&gt; solved the&amp;nbsp;problem:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;user …&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;In porting some Lisp code across to Clojure, I was missing the
&lt;a href="http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-ref/xlisp-ref-267.htm"&gt;sublis&lt;/a&gt; function, or at least something&amp;nbsp;similar.&lt;/p&gt;
&lt;p&gt;The closest I could find was &lt;code&gt;replace&lt;/code&gt;, however it failed on nested&amp;nbsp;structures:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;user&amp;gt; (replace &amp;#39;{?x ?x_123} &amp;#39;(?x (?y ?x)))(?x_123 (?y ?x))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;postwalk-replace&lt;/code&gt; from &lt;a href="http://richhickey.github.com/clojure/clojure.walk-api.html"&gt;clojure.walk&lt;/a&gt; solved the&amp;nbsp;problem:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;user&amp;gt; (use &amp;#39;clojure.walk)
nil
user&amp;gt; (postwalk-replace &amp;#39;{?x ?x_123} &amp;#39;(?x (?y ?x)))(?x_123 (?y ?x_123))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I almost started to write out my own recursive solution. However, I
thought that walking clojure data should be a solved problem, and found
that replacing elements was also a solved&amp;nbsp;problem.&lt;/p&gt;
&lt;p&gt;The more I read through the standard libraries for Clojure, the less
code I&amp;nbsp;write.&lt;/p&gt;</content><category term="clojure"></category></entry><entry><title>Bitly API via Clojure</title><link href="https://pseudofish.com/bitly-api-via-clojure.html" rel="alternate"></link><published>2011-07-03T04:51:00+02:00</published><updated>2011-07-03T04:51:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-07-03:/bitly-api-via-clojure.html</id><summary type="html">&lt;p&gt;While playing with links in Clojure for &lt;a href="http://www.photozeit.org/"&gt;Photozeit&lt;/a&gt;, I wanted to
shorten them via Bit.ly and to also lookup click counts per&amp;nbsp;link.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;API&lt;/span&gt; is quite straightforward, so I wrote a small library,
&lt;a href="https://github.com/gmwils/clojure-bitly"&gt;clojure-bitly&lt;/a&gt;, to allow access to it from&amp;nbsp;Clojure.&lt;/p&gt;
&lt;p&gt;The Github page includes some example code …&lt;/p&gt;</summary><content type="html">&lt;p&gt;While playing with links in Clojure for &lt;a href="http://www.photozeit.org/"&gt;Photozeit&lt;/a&gt;, I wanted to
shorten them via Bit.ly and to also lookup click counts per&amp;nbsp;link.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;API&lt;/span&gt; is quite straightforward, so I wrote a small library,
&lt;a href="https://github.com/gmwils/clojure-bitly"&gt;clojure-bitly&lt;/a&gt;, to allow access to it from&amp;nbsp;Clojure.&lt;/p&gt;
&lt;p&gt;The Github page includes some example code, and the library can be
downloaded from &lt;a href="http://clojars.org/clojure-bitly"&gt;Clojars&lt;/a&gt; using either Lein or&amp;nbsp;Maven.&lt;/p&gt;
&lt;p&gt;Here is how to shorten a&amp;nbsp;url:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;user&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;bitly/with-auth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*bitly-user*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*bitly-apikey*&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;bitly/shorten&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.google.com/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;http://j.mp/lMfE5t&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;user&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="http://code.google.com/p/bitly-api/wiki/ApiDocumentation#/v3"&gt;Bitly &lt;span class="caps"&gt;API&lt;/span&gt; docs&lt;/a&gt; have more details on which methods are available,
or check out the &lt;a href="https://github.com/gmwils/clojure-bitly/blob/master/src/bitly.clj"&gt;source&lt;/a&gt;.&lt;/p&gt;</content><category term="clojure"></category></entry><entry><title>Analysis of data with MongoDB and R</title><link href="https://pseudofish.com/analysis-of-data-with-mongodb-and-r.html" rel="alternate"></link><published>2011-05-25T00:59:00+02:00</published><updated>2011-05-25T00:59:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-05-25:/analysis-of-data-with-mongodb-and-r.html</id><summary type="html">&lt;p&gt;For my &lt;a href="http://photozeit.org/"&gt;photography news&lt;/a&gt; site, I&amp;#8217;ve ended up with a data store of a
lot of blog articles in &lt;a href="http://www.mongodb.org/"&gt;MongoDB&lt;/a&gt;. To try and look for patterns, I
want to run some analysis. &lt;a href="http://www.r-project.org/"&gt;R&lt;/a&gt; looks like the right tool for the&amp;nbsp;job.&lt;/p&gt;
&lt;h3&gt;Integration&amp;nbsp;Installation&lt;/h3&gt;
&lt;p&gt;To link &lt;a href="http://www.r-project.org/"&gt;R&lt;/a&gt; to Mongo, use …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For my &lt;a href="http://photozeit.org/"&gt;photography news&lt;/a&gt; site, I&amp;#8217;ve ended up with a data store of a
lot of blog articles in &lt;a href="http://www.mongodb.org/"&gt;MongoDB&lt;/a&gt;. To try and look for patterns, I
want to run some analysis. &lt;a href="http://www.r-project.org/"&gt;R&lt;/a&gt; looks like the right tool for the&amp;nbsp;job.&lt;/p&gt;
&lt;h3&gt;Integration&amp;nbsp;Installation&lt;/h3&gt;
&lt;p&gt;To link &lt;a href="http://www.r-project.org/"&gt;R&lt;/a&gt; to Mongo, use the &lt;a href="https://github.com/quid/RMongo"&gt;RMongo&lt;/a&gt; library. Behind the scenes,
this uses a R to Java bridge and the Java MongoDB&amp;nbsp;driver.&lt;/p&gt;
&lt;p&gt;Installation is reasonably&amp;nbsp;simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Validate&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;..$&lt;span class="w"&gt; &lt;/span&gt;R&lt;span class="w"&gt; &lt;/span&gt;CMD&lt;span class="w"&gt; &lt;/span&gt;check&lt;span class="w"&gt; &lt;/span&gt;RMongo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Build&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;R&lt;span class="w"&gt; &lt;/span&gt;CMD&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;RMongo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;R&lt;span class="w"&gt; &lt;/span&gt;CMD&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;RMongo*.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These steps assume you already have R installed and available from the
command&amp;nbsp;line.&lt;/p&gt;
&lt;h3&gt;Query for&amp;nbsp;Data&lt;/h3&gt;
&lt;p&gt;Now from within R, you can connect to a local MongoDB. The
mongoDbConnect function takes some additional arguments if your database
is&amp;nbsp;remote.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;library&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;RMongo&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;mongo&lt;span class="w"&gt;  &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;mongoDbConnect&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;db&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;result&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;dbGetQuery&lt;span class="o"&gt;(&lt;/span&gt;mongo,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;items&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;result&lt;span class="nv"&gt;$publish_date&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2011-03-03&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2011-03-03&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2011-04-20&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2011-01-24&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2011-01-24&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2011-04-11&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2011-03-29&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2011-03-28&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2011-03-22&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2011-03-14&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To some extent, it is as simple as that. You can use more complex
queries to extract the data that you&amp;nbsp;want.&lt;/p&gt;
&lt;p&gt;The main query function takes five&amp;nbsp;arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;database&amp;nbsp;connection&lt;/li&gt;
&lt;li&gt;collection&amp;nbsp;name&lt;/li&gt;
&lt;li&gt;query&lt;/li&gt;
&lt;li&gt;skip - how many objects to&amp;nbsp;skip&lt;/li&gt;
&lt;li&gt;limit - total number of objects to&amp;nbsp;return&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, extract all fields from an items collection where an item
was published during April&amp;nbsp;2011:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;&amp;gt; &lt;/span&gt;&lt;span class="ge"&gt;result &amp;lt; - dbGetQuery(mongo, &amp;quot;items&amp;quot;, &amp;quot;{&amp;#39;publish_date&amp;#39; : { &amp;#39;$gte&amp;#39; : &amp;#39;2011-04-01&amp;#39;, &amp;#39;$lt&amp;#39; : &amp;#39;2011-05-01&amp;#39;}}&amp;quot;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To limit data returned to specific fields, use dbGetQueryForKeys&amp;nbsp;instead:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;&amp;gt; &lt;/span&gt;&lt;span class="ge"&gt;result &amp;lt; - dbGetQueryForKeys(mongo, &amp;quot;items&amp;quot;, &amp;quot;{&amp;#39;publish_date&amp;#39; : { &amp;#39;$gte&amp;#39; : &amp;#39;2011-04-01&amp;#39;, &amp;#39;$lt&amp;#39; : &amp;#39;2011-05-01&amp;#39;}}&amp;quot;, &amp;quot;{&amp;#39;publish_date&amp;#39; : 1, &amp;#39;rank&amp;#39; : 1}&amp;quot;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Plotting of&amp;nbsp;Results&lt;/h3&gt;
&lt;p&gt;First, summarise the results into a&amp;nbsp;table:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;&amp;gt; &lt;/span&gt;&lt;span class="ge"&gt;res &amp;lt; - transform(result, day = weekdays(as.Date(publish_date)))&lt;/span&gt;
&lt;span class="k"&gt;&amp;gt; &lt;/span&gt;&lt;span class="ge"&gt;res.days &amp;lt; - factor(res$day, levels = c(&amp;#39;Sunday&amp;#39;, &amp;#39;Monday&amp;#39;, &amp;#39;Tuesday&amp;#39;, &amp;#39;Wednesday&amp;#39;, &amp;#39;Thursday&amp;#39;, &amp;#39;Friday&amp;#39;, &amp;#39;Saturday&amp;#39;), ordered=TRUE)&lt;/span&gt;
&lt;span class="k"&gt;&amp;gt; &lt;/span&gt;&lt;span class="ge"&gt;table(res.days)&lt;/span&gt;
res.days
Sunday    Monday   Tuesday Wednesday  Thursday    Friday    Saturday
    30        74       123       121       131       128          86
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, plot as a&amp;nbsp;barchar:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt; barplot(t(as.matrix(table(res.days))), main=&amp;#39;Items per day of week&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which gives the following&amp;nbsp;graphic:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Items per day" src="/illustrations/2011/items_per_day.png" title="items_per_day.png"&gt;&lt;/p&gt;
&lt;p&gt;This makes it easy to see how many articles were available per day
across&amp;nbsp;April.&lt;/p&gt;
&lt;p&gt;While I am still scratching the surface, the combination of R with
MongoDB looks to be quite&amp;nbsp;useful.&lt;/p&gt;</content><category term="data"></category></entry><entry><title>Reading a Twitter account from Clojure</title><link href="https://pseudofish.com/reading-a-twitter-account-from-clojure.html" rel="alternate"></link><published>2011-05-09T06:52:00+02:00</published><updated>2011-05-09T06:52:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-05-09:/reading-a-twitter-account-from-clojure.html</id><summary type="html">&lt;p&gt;For my &lt;a href="http://photozeit.org/"&gt;photography news&lt;/a&gt; site, I want to use Twitter as a data source
for popular links. This involves getting tweets out of Twitter and into&amp;nbsp;MongoDB.&lt;/p&gt;
&lt;p&gt;The first step is to be able to read the tweets from an account using
Clojure. The library that holds the key is …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For my &lt;a href="http://photozeit.org/"&gt;photography news&lt;/a&gt; site, I want to use Twitter as a data source
for popular links. This involves getting tweets out of Twitter and into&amp;nbsp;MongoDB.&lt;/p&gt;
&lt;p&gt;The first step is to be able to read the tweets from an account using
Clojure. The library that holds the key is &lt;a href="https://github.com/mattrepl/clojure-twitter"&gt;clojure-twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To try this out, I created a new lein project, and added the following
to&amp;nbsp;project.clj:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defproject &lt;/span&gt;&lt;span class="nv"&gt;twitter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.0.0-SNAPSHOT&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ss"&gt;:description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Sample project to read in a tweet stream&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ss"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;org.clojure/clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.2.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;clojure-twitter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.2.5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ss"&gt;:dev-dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;swank-clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.3.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then run &lt;code&gt;lein deps&lt;/code&gt; and start working out the&amp;nbsp;code.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/mattrepl/clojure-twitter"&gt;example&lt;/a&gt; is a good start, however it the various
authentication keys didn&amp;#8217;t quite make sense to me on first&amp;nbsp;look.&lt;/p&gt;
&lt;p&gt;After &lt;a href="https://dev.twitter.com/apps/new"&gt;registering&lt;/a&gt; an &lt;a href="https://dev.twitter.com/apps"&gt;application&lt;/a&gt;, you will need to copy four
strings from your Twitter&amp;nbsp;account:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consumer key&lt;/strong&gt; - identifier for your &lt;a href="https://dev.twitter.com/apps"&gt;application&lt;/a&gt;, found with
    your app&amp;nbsp;details.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consumer secret&lt;/strong&gt; - shown with your consumer key and almost twice
    as long. Keep this&amp;nbsp;secret.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Access Token&lt;/strong&gt; (oauth_token) - identifier for your user, found
    under the &amp;#8220;My Access Token&amp;#8221; button next to your application&amp;nbsp;details.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Access Token Secret&lt;/strong&gt; (oauth_token_secret) - shown with your
    Access&amp;nbsp;Token&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The access token took me a little while to find. Yours will be at a &lt;span class="caps"&gt;URL&lt;/span&gt;
similar&amp;nbsp;to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;https://dev.twitter.com/apps/123456/my_token
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Where 123456 is the identifier of your&amp;nbsp;application.&lt;/p&gt;
&lt;p&gt;Armed with these four pieces of information, the code is quite simple.
First include the &lt;span class="caps"&gt;API&lt;/span&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;ns &lt;/span&gt;&lt;span class="nv"&gt;twitter.core&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;twitter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;oauth.client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;oauth&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then setup the various keys and secret&amp;nbsp;phrases:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;;; Make a OAuth consumer&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;oauth-consumer&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;oauth/make-consumer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;N0tr3a11ym1k3y&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;;; consumer key&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;R23mnasdfphsfjas08ujhasf08aslfkjasfd234asfd&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;;; consumer secret&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://api.twitter.com/oauth/request_token&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://api.twitter.com/oauth/access_token&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://api.twitter.com/oauth/authorize&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="ss"&gt;:hmac-sha1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;oauth-access-token&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1234456789-asdfjklkjasdfjkllASDFASDF&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;oauth-access-token-secret&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CompletelyRandomStringWithNumbersAndLetters&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Obviously, include your own keys and&amp;nbsp;tokens.&lt;/p&gt;
&lt;p&gt;The Clojure &lt;span class="caps"&gt;API&lt;/span&gt; is easy to read from the &lt;a href="https://github.com/mattrepl/clojure-twitter/blob/master/src/twitter.clj"&gt;source&lt;/a&gt; and follows closely
to Twitter&amp;#8217;s &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I chose to use the https version of the &lt;span class="caps"&gt;API&lt;/span&gt; and also scope the
authentication. To read the most recent tweets from my&amp;nbsp;followers:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;latest-tweets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;twitter/with-https&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;twitter/with-oauth&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;oauth-consumer&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;oauth-access-token&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;oauth-access-token-secret&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;twitter/home-timeline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str &lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I&amp;#8217;m not sure why the limit parameter only takes a string. Now after
running &lt;code&gt;lein swank&lt;/code&gt; and connecting up Emacs, I can&amp;nbsp;run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;user&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:reload&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;twitter.core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;nil&lt;/span&gt;
&lt;span class="nv"&gt;user&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;latest-tweets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;OK, that&amp;#39;s 20 videos this weekend alone I posted at http://t.co/Vm2sVQV Hope you like (please subscribe if you do!)&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is quite a lot of information returned for each tweet, such as
conversation threads, user info and retweet data. Now I just need to
decide how much of it to store for later&amp;nbsp;analysis.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>Set the HTTP User-Agent string in Clojure</title><link href="https://pseudofish.com/set-the-http-user-agent-string-in-clojure.html" rel="alternate"></link><published>2011-04-27T02:38:00+02:00</published><updated>2011-04-27T02:38:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-04-27:/set-the-http-user-agent-string-in-clojure.html</id><summary type="html">&lt;p&gt;I wanted to be able to set the User Agent string for web requests made
from Clojure. This is polite when crawling other sites, otherwise the
request appears as a generic &lt;a href="http://www.httpuseragent.org/list/Java+VM+1.6-n697.htm"&gt;Java application&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To interact with the web, I&amp;#8217;m using a &lt;a href="https://github.com/getwoven/clj-http"&gt;wrapper&lt;/a&gt; around the Apache http&amp;nbsp;client.&lt;/p&gt;
&lt;p&gt;To add …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I wanted to be able to set the User Agent string for web requests made
from Clojure. This is polite when crawling other sites, otherwise the
request appears as a generic &lt;a href="http://www.httpuseragent.org/list/Java+VM+1.6-n697.htm"&gt;Java application&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To interact with the web, I&amp;#8217;m using a &lt;a href="https://github.com/getwoven/clj-http"&gt;wrapper&lt;/a&gt; around the Apache http&amp;nbsp;client.&lt;/p&gt;
&lt;p&gt;To add into your project, put the following in&amp;nbsp;project.clj:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;clj-http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.1.2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The user agent string can be set on each&amp;nbsp;call:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;http-agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;crawlbot/1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;get-body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;client/get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:headers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;User-Agent&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;http-agent&lt;/span&gt;&lt;span class="p"&gt;}})))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The next step is to move this out to a property that the wrapper can
read, so it can be set once. This refactoring isn&amp;#8217;t yet justified, as I
make a limited number of&amp;nbsp;calls.&lt;/p&gt;</content><category term="clojure"></category></entry><entry><title>Kanban &amp; Agile Development</title><link href="https://pseudofish.com/kanban-agile-development.html" rel="alternate"></link><published>2011-04-19T19:16:00+02:00</published><updated>2011-04-19T19:16:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-04-19:/kanban-agile-development.html</id><summary type="html">&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Kanban"&gt;Kanban&lt;/a&gt; is a scheduling system for work items that I&amp;#8217;m exploring&amp;nbsp;further.&lt;/p&gt;
&lt;p&gt;I heard about it from several sources, but didn&amp;#8217;t focus my attention
until earlier this&amp;nbsp;year.&lt;/p&gt;
&lt;p&gt;I highly recommend &lt;a href="http://www.amazon.com/gp/product/0984521402/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399349&amp;amp;creativeASIN=0984521402"&gt;Kanban&lt;/a&gt; by David J Anderson. He is someone who is
a practitioner as well as an author …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Kanban"&gt;Kanban&lt;/a&gt; is a scheduling system for work items that I&amp;#8217;m exploring&amp;nbsp;further.&lt;/p&gt;
&lt;p&gt;I heard about it from several sources, but didn&amp;#8217;t focus my attention
until earlier this&amp;nbsp;year.&lt;/p&gt;
&lt;p&gt;I highly recommend &lt;a href="http://www.amazon.com/gp/product/0984521402/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=pseudofish-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399349&amp;amp;creativeASIN=0984521402"&gt;Kanban&lt;/a&gt; by David J Anderson. He is someone who is
a practitioner as well as an author, which really helps in his&amp;nbsp;explanations.&lt;/p&gt;
&lt;p&gt;His book is broken up into four&amp;nbsp;sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Benefits of&amp;nbsp;Kanban&lt;/li&gt;
&lt;li&gt;Implementing&amp;nbsp;Kanban&lt;/li&gt;
&lt;li&gt;Making&amp;nbsp;improvements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each section is filled with references to industry theory, both in
software and manufacturing, and liberally sprinkled with case studies
from his own&amp;nbsp;companies.&lt;/p&gt;
&lt;p&gt;One part that really resonated with me is that introducing Kanban layers
over the top of an existing development process. That is, you do not
need to change your current process. Instead, the focus is on scheduling
the work that goes into the&amp;nbsp;process.&lt;/p&gt;
&lt;p&gt;This makes Kanban a logical fit for processes such as Agile, as well as
more traditional iterative or even waterfall development&amp;nbsp;projects.&lt;/p&gt;
&lt;p&gt;From the&amp;nbsp;book:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Kanban is an approach that drives change by optimizing your existing
process. The essence of starting with Kanban is to change as little as
possible. You must resist the temptation to change workflow, job
titles, roles and responsibilities, and specific working practices.
Everything from which the team members and other partners,
participants, and stakeholders derive their self-esteem, professional
pride, and ego should be left&amp;nbsp;unchanged.&lt;/p&gt;
&lt;p&gt;The main target of change will be the quantity of &lt;span class="caps"&gt;WIP&lt;/span&gt; and the
interface to and interaction with upstream and downstream parts of
your business. So you must work with your team to map the value stream
as it exists. Try not to change it or invent it in an idealistic&amp;nbsp;fashion&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As with any new area of knowledge, I feel like I&amp;#8217;ve only scratched the
surface. The interesting part is the range of topics to explore further,
such as &lt;a href="http://en.wikipedia.org/wiki/W._Edwards_Deming"&gt;Deming&amp;#8217;s writing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It is also helpful to be working with teams that have already
implemented many of the techniques from Kanban process, and to hear
first hand stories of their&amp;nbsp;implementation.&lt;/p&gt;</content><category term="agile"></category></entry><entry><title>Emacs Update</title><link href="https://pseudofish.com/emacs-update.html" rel="alternate"></link><published>2011-04-14T21:22:00+02:00</published><updated>2011-04-14T21:22:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-04-14:/emacs-update.html</id><summary type="html">&lt;p&gt;Now that I’ve been using Emacs for a while, I&amp;#8217;m finding that my reflexes
are adjusting to the Emacs way. On the bright side, I can still jump
back into Vim and be&amp;nbsp;productive.&lt;/p&gt;
&lt;p&gt;A &lt;a href="http://benjisimon.blogspot.com/2011/04/10-concepts-emacs-newbie-should-master.html"&gt;recent blog&lt;/a&gt; post highlighted the areas that I still need to&amp;nbsp;explore.&lt;/p&gt;
&lt;p&gt;I …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Now that I’ve been using Emacs for a while, I&amp;#8217;m finding that my reflexes
are adjusting to the Emacs way. On the bright side, I can still jump
back into Vim and be&amp;nbsp;productive.&lt;/p&gt;
&lt;p&gt;A &lt;a href="http://benjisimon.blogspot.com/2011/04/10-concepts-emacs-newbie-should-master.html"&gt;recent blog&lt;/a&gt; post highlighted the areas that I still need to&amp;nbsp;explore.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m finding the deeper I dive into Emacs use, the more there is to find.
The idea of a &lt;a href="http://www.mostlymaths.net/2010/12/emacs-30-day-challenge.html"&gt;30 day challenge&lt;/a&gt; to use nothing but Emacs is going &lt;a href="http://www.mostlymaths.net/2010/12/emacs-30-day-challenge-update-1-writing.html"&gt;a
bit far&lt;/a&gt;, however I do find myself using it for more and more&amp;nbsp;things.&lt;/p&gt;
&lt;p&gt;Originally my focus was on Clojure, due to the great Lisp integration. I
even have the keyboard shortcuts for &lt;a href="http://www.emacswiki.org/emacs/PareditCheatsheet"&gt;Paredit mode&lt;/a&gt; as the background
image on my screen. Now, I also use it for note taking and for
organising ideas before preparing presentations. Rails coding is also
emacs&amp;nbsp;friendly.&lt;/p&gt;
&lt;p&gt;A pleasant surprise is just how many controls and tools support emacs
key bindings. Almost every textbox on Mac &lt;span class="caps"&gt;OS&lt;/span&gt; X for example. Typically, I
make use of Ctrl-A, Ctrl-E to jump to the beginning and ends of lines,
and Ctrl-D to forward delete a&amp;nbsp;character.&lt;/p&gt;
&lt;p&gt;The one area I still tend to fall back to Vim with is managing servers.
I think I need some more practice with keyboard combos on terminals. I
am also still to really learn emacs&amp;#8217;&amp;nbsp;lisp.&lt;/p&gt;
&lt;p&gt;Overall, I&amp;#8217;m very happy with the&amp;nbsp;switch.&lt;/p&gt;</content><category term="emacs"></category></entry><entry><title>Notes on using Maven</title><link href="https://pseudofish.com/notes-on-using-maven.html" rel="alternate"></link><published>2011-03-14T03:38:00+01:00</published><updated>2011-03-14T03:38:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-03-14:/notes-on-using-maven.html</id><summary type="html">&lt;p&gt;I&amp;#8217;ve been looking at build tools for &lt;span class="caps"&gt;JVM&lt;/span&gt; projects. These are the notes I
took while reviewing &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mvn install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mvn site&lt;/code&gt; - generate a summary of the&amp;nbsp;project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mvn dependency:analyze&lt;/code&gt; - determine missing or unused&amp;nbsp;dependencies&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mvn dependency:tree&lt;/code&gt; - tree view of&amp;nbsp;dependencies&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mvn help:effective-pom&lt;/code&gt; - useful for&amp;nbsp;debugging …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve been looking at build tools for &lt;span class="caps"&gt;JVM&lt;/span&gt; projects. These are the notes I
took while reviewing &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mvn install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mvn site&lt;/code&gt; - generate a summary of the&amp;nbsp;project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mvn dependency:analyze&lt;/code&gt; - determine missing or unused&amp;nbsp;dependencies&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mvn dependency:tree&lt;/code&gt; - tree view of&amp;nbsp;dependencies&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mvn help:effective-pom&lt;/code&gt; - useful for&amp;nbsp;debugging&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Refactoring Maven&amp;nbsp;Projects&lt;/h3&gt;
&lt;p&gt;For a given Maven project, these are some strategies to optimise the
process. Mostly this is the &lt;span class="caps"&gt;DRY&lt;/span&gt; principle - Don&amp;#8217;t Repeat&amp;nbsp;Yourself.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pull up common dependencies to &amp;#8220;dependencyManagement&amp;#8221;, then only
    refer to groupId:artifactId in the child&amp;nbsp;project&lt;/li&gt;
&lt;li&gt;Use built-ins &lt;code&gt;${project.version}&lt;/code&gt; and &lt;code&gt;${project.groupId}&lt;/code&gt; when
    referring to a sibling&amp;nbsp;project&lt;/li&gt;
&lt;li&gt;Use properties to re-factor version numbers across multiple
    dependencies from the same&amp;nbsp;group&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Build&amp;nbsp;profiles&lt;/h3&gt;
&lt;p&gt;Use build profiles to setup different environments for&amp;nbsp;dev/test/staging/production&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Specify profiles as the last things in a &lt;span class="caps"&gt;POM&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Call using -P e.g. mvn clean install -Pproduction&amp;nbsp;-X&lt;/li&gt;
&lt;li&gt;Activation parameters automatically select a profile based on a set
    of selectors. (ie. a &lt;span class="caps"&gt;JDK6&lt;/span&gt; profile if &lt;span class="caps"&gt;JDK6&lt;/span&gt; is&amp;nbsp;used)&lt;/li&gt;
&lt;li&gt;Profiles can be stored in a separate &amp;#8220;profiles.xml&amp;#8221; that lives next
    to&amp;nbsp;&amp;#8220;pom.xml&amp;#8221;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mvn help:active-profiles&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;You can set a default profile in your &lt;code&gt;~/.m2/settings.xml&lt;/code&gt; and put
    passwords into settings files as&amp;nbsp;well&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Finding&amp;nbsp;bundles&lt;/h3&gt;
&lt;p&gt;There is an online repository at &lt;a href="http://mvnrepository.com/"&gt;http://mvnrepository.com/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Maven&amp;nbsp;Properties&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;project.*&lt;/strong&gt; – Maven Project Object Model, that is stuff in your
    pom.xml. See:&amp;nbsp;http://maven.apache.org/ref/2.2.1/maven-model/maven.html&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;settings.*&lt;/strong&gt; – Things from your \~/.m2/settings.xml file. See:
    &lt;a href="http://maven.apache.org/ref/2.2.1/maven-settings/settings.html"&gt;online&amp;nbsp;docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;env.*&lt;/strong&gt; – Environment variables, such as &lt;span class="caps"&gt;PATH&lt;/span&gt;, &lt;span class="caps"&gt;HOME&lt;/span&gt;, JAVA_HOME
    and M2_HOME. Note: prefer ${user.home} to ${env.&lt;span class="caps"&gt;HOME&lt;/span&gt;}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System properties&lt;/strong&gt; – things from System.getProperty(), such as
    java.version, java.home, os.name, os.arch, user.dir, user.home,&amp;nbsp;etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User defined&lt;/strong&gt; – arbitrary properties within your&amp;nbsp;pom.xml&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: you can use maven properties in resource files, such as a
.properties or .xml file under&amp;nbsp;src/main/resources.&lt;/p&gt;
&lt;p&gt;You need to enable this in the&amp;nbsp;pom.xml:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;resources&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;src/main/resources&lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;filtering&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/filtering&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/resources&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Assigning custom properties per profile can help with deployment into
multiple&amp;nbsp;environments.&lt;/p&gt;
&lt;h3&gt;Maven &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;&amp;nbsp;Eclipse&lt;/h3&gt;
&lt;p&gt;Eclipse has very good integration for Maven. Later versions of Eclipse
include this in their package. It can also be added from
&lt;a href="http://m2eclipse.codehaus.org/"&gt;http://m2eclipse.codehaus.org/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Maven&amp;nbsp;Archetypes&lt;/h3&gt;
&lt;p&gt;Archetypes exist for a range of different project&amp;nbsp;types.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;mvn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;archetype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;generate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Custom archetypes can be developed if you have a new type of &lt;a href="http://maven.apache.org/guides/mini/guide-creating-archetypes.html"&gt;project&lt;/a&gt;
or generated from an existing &lt;a href="http://maven.apache.org/archetype/maven-archetype-plugin/create-from-project-mojo.html"&gt;project&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Maven&amp;nbsp;sites&lt;/h3&gt;
&lt;p&gt;Maven can generate a site for your project showing information about the
project and various&amp;nbsp;reports.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;mvn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;archetype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;DgroupId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;DartifactId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;sample&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;
&lt;span class="nx"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sample&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;
&lt;span class="nx"&gt;mvn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;
&lt;span class="nx"&gt;mvn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;
&lt;span class="nx"&gt;mvn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;
&lt;span class="nx"&gt;mvn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Repository&amp;nbsp;Manager&lt;/h3&gt;
&lt;p&gt;Hosting a local repository for a team provides a number of benefits,
including a local cache to avoid excessive network usage. Additionally,
work can be shared both internally and&amp;nbsp;externally.&lt;/p&gt;
&lt;p&gt;A repository can be as simple as a file system with the appropriate
layout, or a full &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-repositories.html"&gt;repository&lt;/a&gt; &lt;a href="http://maven.apache.org/repository-management.html"&gt;manager&lt;/a&gt;. Nexus is an option for
hosting a repository. It can be downloaded from:
&lt;a href="http://nexus.sonatype.org/download-nexus.html"&gt;http://nexus.sonatype.org/download-nexus.html&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Other&amp;nbsp;Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://nbtconsulting.com/cheat-sheets/maven-cheat-sheet.html"&gt;Cheat sheet&lt;/a&gt; – comprehensive list of useful&amp;nbsp;commands.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/Maven-Definitive-Guide-Sonatype-Company/dp/0596517335/ref=sr_1_1?ie=UTF8&amp;amp;qid=1299666613&amp;amp;sr=8-1"&gt;Maven - The Definitive&amp;nbsp;Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sonatype.com/books.html"&gt;Various&amp;nbsp;Books&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://cemerick.com/2010/03/25/why-using-maven-for-clojure-builds-is-a-no-brainer/"&gt;Using Maven with&amp;nbsp;Clojure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: I&amp;#8217;m continuing with &lt;a href="http://alexott.net/en/clojure/ClojureLein.html"&gt;lein&lt;/a&gt; for my clojure projects. To integrate
with Maven, you can generate a pom.xml file for a with &amp;#8220;&lt;code&gt;lein pom&lt;/code&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>Tracking Outbound Links with Rails 3</title><link href="https://pseudofish.com/tracking-outbound-links-with-rails-3.html" rel="alternate"></link><published>2011-02-28T05:45:00+01:00</published><updated>2011-02-28T05:45:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-02-28:/tracking-outbound-links-with-rails-3.html</id><summary type="html">&lt;p&gt;To gain some insight on what interests users, I want to be able to track
which links they click&amp;nbsp;on.&lt;/p&gt;
&lt;p&gt;There were a number of options I considered, and finally settled on
using Javascript to update an underlying Click model. For analytics, I
intend to aggregate the data offline. Thus …&lt;/p&gt;</summary><content type="html">&lt;p&gt;To gain some insight on what interests users, I want to be able to track
which links they click&amp;nbsp;on.&lt;/p&gt;
&lt;p&gt;There were a number of options I considered, and finally settled on
using Javascript to update an underlying Click model. For analytics, I
intend to aggregate the data offline. Thus the current aim is capture&amp;nbsp;only.&lt;/p&gt;
&lt;p&gt;To store the data, I created a simple model&amp;nbsp;using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;rails g model Click url:string request_ip:string user_agent:string user_id:string
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I decided not to store the all the request data, and instead just track
the&amp;nbsp;following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;URL&lt;/span&gt;&lt;/strong&gt; - these are already&amp;nbsp;normalized&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Request &lt;span class="caps"&gt;IP&lt;/span&gt;&lt;/strong&gt; - I aim to use this to figure out geo-location at a
    later&amp;nbsp;date&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Agent&lt;/strong&gt; - which browser&amp;nbsp;used&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User &lt;span class="caps"&gt;ID&lt;/span&gt;&lt;/strong&gt; - a unique hash for the user, kept in a&amp;nbsp;cookie&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rails kindly adds in the created_at column, which is the final key
piece of&amp;nbsp;data.&lt;/p&gt;
&lt;p&gt;To generate the click data, I added the following into my
&lt;a href="https://github.com/gmwils/clicks/blob/master/public/javascripts/application.js"&gt;application.js&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;live&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/clicks&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;document.location = &amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This posts the click through to the &lt;a href="https://github.com/gmwils/clicks/blob/master/app/controllers/clicks_controller.rb#L42"&gt;Click controller&lt;/a&gt;. In the
controller, I added in the&amp;nbsp;following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="vi"&gt;@click&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Click&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:click&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="vi"&gt;@click&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remote_addr&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="vi"&gt;@click&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_agent&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="vi"&gt;@click&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:uid&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;respond_to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vi"&gt;@click&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vi"&gt;@click&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vi"&gt;@click&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To generate the tracking cookie, I included the following in
&lt;a href="https://github.com/gmwils/clicks/blob/master/public/javascripts/application.js"&gt;application.js&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;uid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracking_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;md5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;314159&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Current time + random seed&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;uid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracking_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;expires&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;365&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By using an &lt;span class="caps"&gt;MD5&lt;/span&gt; hash of the current time and a random number, I am
comfortable enough that it is unique enough for tracking&amp;nbsp;purposes.&lt;/p&gt;
&lt;p&gt;In this example, I am tracking all clicks on the application. For
production use, I&amp;#8217;ll filter this down to only the outbound article&amp;nbsp;titles.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve included a skeleton Rails 3 app that includes the code on
&lt;a href="https://github.com/gmwils/clicks/"&gt;GitHub&lt;/a&gt;. I used a jQuery plugin for cookies and &lt;span class="caps"&gt;MD5&lt;/span&gt; hash generation,
and these are included in the &lt;a href="https://github.com/gmwils/clicks/tree/master/public/javascripts/jquery"&gt;public/javascripts&lt;/a&gt;&amp;nbsp;directory.&lt;/p&gt;
&lt;p&gt;There are a few things that this misses, such as links clicked via &lt;span class="caps"&gt;RSS&lt;/span&gt;,
via Twitter, and a heap of tests. I&amp;#8217;m looking into Feedburner and bit.ly
to see if I they fill in the missing&amp;nbsp;metrics.&lt;/p&gt;</content><category term="programming"></category></entry><entry><title>Web Application Frameworks</title><link href="https://pseudofish.com/web-application-frameworks.html" rel="alternate"></link><published>2011-02-03T21:53:00+01:00</published><updated>2011-02-03T21:53:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2011-02-03:/web-application-frameworks.html</id><summary type="html">&lt;p&gt;I&amp;#8217;ve been thinking about building a web application that behaves more
like a desktop application. Think MobileMe, GMail, Google Docs,&amp;nbsp;etc.&lt;/p&gt;
&lt;p&gt;This post collects together some of the research that I&amp;#8217;ve been doing so
I can refer back to&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;SproutCore&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.sproutcore.com/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/SproutCore"&gt;SproutCore on&amp;nbsp;Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sproutcore.com/get-started/"&gt;Getting&amp;nbsp;Started&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cappuccino …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve been thinking about building a web application that behaves more
like a desktop application. Think MobileMe, GMail, Google Docs,&amp;nbsp;etc.&lt;/p&gt;
&lt;p&gt;This post collects together some of the research that I&amp;#8217;ve been doing so
I can refer back to&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;SproutCore&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.sproutcore.com/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/SproutCore"&gt;SproutCore on&amp;nbsp;Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sproutcore.com/get-started/"&gt;Getting&amp;nbsp;Started&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cappuccino&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://cappuccino.org/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Cappuccino_(application_development_framework)"&gt;Cappuccino on&amp;nbsp;Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://cappuccino.org/learn/tutorials/"&gt;Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Raphaël&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://raphaeljs.com/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Raphaël_(JavaScript_Library)"&gt;Raphaël on&amp;nbsp;Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cjheath/Raphaelle/"&gt;Drag &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Drop&amp;nbsp;support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is a few places that have a comparison between some of these,&amp;nbsp;including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/4287953/sproutcore-vs-cappuccino"&gt;SproutCore vs Cappuccino&lt;/a&gt;&amp;nbsp;(stackoverflow)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/370598/sproutcore-and-cappuccino"&gt;SproutCore and Cappuccino&lt;/a&gt; (stackoverflow) - if you use Cocoa,
    pick Cappuccino, else use&amp;nbsp;SproutCore.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://thelucid.com/2010/04/09/to-sproutcore-or-not-to-sproutcore/"&gt;To SproutCore, or not to&amp;nbsp;SproutCore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://groups.google.com/group/rails-oceania/browse_thread/thread/75d90debf51d3ab2"&gt;Building a Project Planning App&lt;/a&gt; (ruby or rails&amp;nbsp;oceania)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From my current reading, my inclination is to dive deeper into
SproutCore. Apple and &lt;a href="http://blog.sproutcore.com/post/3075780393/sproutcore-amber-a-report-by-yehuda"&gt;Yehuda&lt;/a&gt; seem to be investing a lot into it.
That said, Cappuccino looks quite&amp;nbsp;interesting.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update:&lt;/em&gt; &lt;a href="http://addyosmani.com/blog/large-scale-jquery/"&gt;This&lt;/a&gt; article provides a good summary of large scale
development using&amp;nbsp;Javascript.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>Making Emacs even more like TextMate</title><link href="https://pseudofish.com/making-emacs-even-more-like-textmate.html" rel="alternate"></link><published>2010-12-23T15:21:00+01:00</published><updated>2010-12-23T15:21:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-12-23:/making-emacs-even-more-like-textmate.html</id><summary type="html">&lt;p&gt;Much as I love TextMate, I&amp;#8217;m still trying to get back to one editor.
Here are a two more things to make Aquamacs even more TextMate&amp;nbsp;like.&lt;/p&gt;
&lt;h3&gt;TextMate Minor&amp;nbsp;Mode&lt;/h3&gt;
&lt;p&gt;Go to defunkt&amp;#8217;s github &lt;a href="https://github.com/defunkt/textmate.el"&gt;page&lt;/a&gt; and follow the&amp;nbsp;instructions.&lt;/p&gt;
&lt;p&gt;This gives you access to some of the magical …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Much as I love TextMate, I&amp;#8217;m still trying to get back to one editor.
Here are a two more things to make Aquamacs even more TextMate&amp;nbsp;like.&lt;/p&gt;
&lt;h3&gt;TextMate Minor&amp;nbsp;Mode&lt;/h3&gt;
&lt;p&gt;Go to defunkt&amp;#8217;s github &lt;a href="https://github.com/defunkt/textmate.el"&gt;page&lt;/a&gt; and follow the&amp;nbsp;instructions.&lt;/p&gt;
&lt;p&gt;This gives you access to some of the magical TextMate features. The ones
I missed the most&amp;nbsp;are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⌘T - Go to&amp;nbsp;File&lt;/li&gt;
&lt;li&gt;⌘/ - Comment Line (or&amp;nbsp;Selection/Region)&lt;/li&gt;
&lt;li&gt;⌘L - Go to&amp;nbsp;Line&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By adding in these few shortcuts, I find it much easier to jump between
the&amp;nbsp;editors.&lt;/p&gt;
&lt;h3&gt;Cucumber&amp;nbsp;Support&lt;/h3&gt;
&lt;p&gt;A simple set of &lt;a href="https://github.com/michaelklishin/cucumber.el"&gt;scripts&lt;/a&gt; to enable cucumber support into emacs. See
the installation page for how to set it up. And don&amp;#8217;t forget the&amp;nbsp;pre-req.&lt;/p&gt;
&lt;p&gt;Once installed, you get syntax highlighting for feature files, and
snippet&amp;nbsp;support.&lt;/p&gt;
&lt;p&gt;You can also setup run targets, however that requires a few &lt;a href="https://github.com/michaelklishin/cucumber.el/issues#issue/3"&gt;more
dependencies&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Other Rails&amp;nbsp;Files&lt;/h3&gt;
&lt;p&gt;Try the &lt;a href="https://github.com/technomancy/emacs-starter-kit/raw/master/starter-kit-ruby.el"&gt;following&lt;/a&gt; in your .emacs to include additional syntax&amp;nbsp;highlighting:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;;; Rake files are ruby, too, as are gemspecs, rackup files, etc.&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;auto-mode-alist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\.rake$&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ruby-mode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;auto-mode-alist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\.gemspec$&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ruby-mode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;auto-mode-alist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\.ru$&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ruby-mode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;auto-mode-alist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Rakefile$&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ruby-mode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;auto-mode-alist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Gemfile$&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ruby-mode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;auto-mode-alist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Capfile$&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ruby-mode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;auto-mode-alist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Vagrantfile$&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ruby-mode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="emacs"></category></entry><entry><title>Following Url Redirects with Clojure</title><link href="https://pseudofish.com/following-url-redirects-with-clojure.html" rel="alternate"></link><published>2010-11-11T00:33:00+01:00</published><updated>2010-11-11T00:33:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-11-11:/following-url-redirects-with-clojure.html</id><summary type="html">&lt;p&gt;In attempting to normalize urls for a project, I needed to unravel the&amp;nbsp;redirects.&lt;/p&gt;
&lt;p&gt;Urls that are provided could be via a &lt;span class="caps"&gt;URL&lt;/span&gt; shortening service, an &lt;span class="caps"&gt;RSS&lt;/span&gt;
feed or from another source. To compare them, I need to determine the
final destination of the &lt;span class="caps"&gt;URL&lt;/span&gt;, not what is initially&amp;nbsp;supplied …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In attempting to normalize urls for a project, I needed to unravel the&amp;nbsp;redirects.&lt;/p&gt;
&lt;p&gt;Urls that are provided could be via a &lt;span class="caps"&gt;URL&lt;/span&gt; shortening service, an &lt;span class="caps"&gt;RSS&lt;/span&gt;
feed or from another source. To compare them, I need to determine the
final destination of the &lt;span class="caps"&gt;URL&lt;/span&gt;, not what is initially&amp;nbsp;supplied.&lt;/p&gt;
&lt;p&gt;To solve this in Clojure, I used the java.net.&lt;span class="caps"&gt;URL&lt;/span&gt; class to open a
connection. By calling .getResponse, the connection will follow through
the redirects. If this is successful, I return the final &lt;span class="caps"&gt;URL&lt;/span&gt;, otherwise
I give back the initial &lt;span class="caps"&gt;URL&lt;/span&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;test-url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://feedproxy.google.com/~r/amateurphotographercouk/feeds/rss/newsxml/~3/ds1Q9VsOjhI/story01.htm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;resolve-redirect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;initial-url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Follows any redirects to the supplied url and returns the final destination&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;java.net.URL.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;initial-url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;conn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.openConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;= &lt;/span&gt;&lt;span class="nv"&gt;HttpURLConnection/HTTP_OK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.getResponseCode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;.. &lt;/span&gt;&lt;span class="nv"&gt;conn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;getURL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;initial-url&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I&amp;#8217;m still to test this out on a wide variety of production uses, so your
milage may&amp;nbsp;vary.&lt;/p&gt;
&lt;p&gt;Note: You&amp;#8217;ll need to include the HttpURLConnection with
&lt;code&gt;(:import (java.net HttpURLConnection))&lt;/code&gt; in your namespace&amp;nbsp;declaration.&lt;/p&gt;</content><category term="clojure"></category></entry><entry><title>MapReduce Examples</title><link href="https://pseudofish.com/mapreduce-examples.html" rel="alternate"></link><published>2010-10-30T21:36:00+02:00</published><updated>2010-10-30T21:36:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-10-30:/mapreduce-examples.html</id><summary type="html">&lt;p&gt;In investigating &lt;a href="http://www.mongodb.org/"&gt;MongoDB&lt;/a&gt; I decided to explore MapReduce to analyse
the posts from a heap of &lt;span class="caps"&gt;RSS&lt;/span&gt; feeds. However, the MongoDB documentation
is &lt;a href="http://www.mongodb.org/display/DOCS/MapReduce"&gt;fairly&lt;/a&gt; basic. &lt;a href="http://rickosborne.org/blog/index.php/2010/02/08/playing-around-with-mongodb-and-mapreduce-functions/"&gt;This post&lt;/a&gt; has a bit more detail on more complex
map/reduce&amp;nbsp;functions.&lt;/p&gt;
&lt;p&gt;Looking outside of MongoDB, there are a few other groups working with …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In investigating &lt;a href="http://www.mongodb.org/"&gt;MongoDB&lt;/a&gt; I decided to explore MapReduce to analyse
the posts from a heap of &lt;span class="caps"&gt;RSS&lt;/span&gt; feeds. However, the MongoDB documentation
is &lt;a href="http://www.mongodb.org/display/DOCS/MapReduce"&gt;fairly&lt;/a&gt; basic. &lt;a href="http://rickosborne.org/blog/index.php/2010/02/08/playing-around-with-mongodb-and-mapreduce-functions/"&gt;This post&lt;/a&gt; has a bit more detail on more complex
map/reduce&amp;nbsp;functions.&lt;/p&gt;
&lt;p&gt;Looking outside of MongoDB, there are a few other groups working with
MapReduce. Google started the whole thing off, and has some good&amp;nbsp;resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://code.google.com/edu/parallel/mapreduce-tutorial.html"&gt;MapReduce Tutorial&lt;/a&gt; - good overview of the process with some&amp;nbsp;examples.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://research.google.com/archive/mapreduce.html"&gt;Original Paper&lt;/a&gt; - details of the original MapReduce&amp;nbsp;publication&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/edu/submissions/mapreduce-minilecture/listing.html"&gt;Lecture Series&lt;/a&gt; - I didn&amp;#8217;t watch this, but it does seem&amp;nbsp;comprehensive.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/edu/submissions/mapreduce/listing.html"&gt;Slides&lt;/a&gt; - See Lecture&amp;nbsp;3.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some examples of using MapReduce &lt;a href="http://code.google.com/edu/parallel/mapreduce-tutorial.html#MRExamples"&gt;include&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Distributed Grep&lt;/strong&gt; - emit(matched line),&amp;nbsp;reduce(identity)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Count of &lt;span class="caps"&gt;URL&lt;/span&gt; Access Frequency&lt;/strong&gt; - emit(url, 1), reduce(url,&amp;nbsp;sum)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reverse Web-Link Graph&lt;/strong&gt; - emit(target, source), reduce(target,
    cons) =&amp;gt; {target,&amp;nbsp;[sources]}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Term-Vector per Host&lt;/strong&gt; - {hostname, [term&amp;nbsp;vector]}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inverted&amp;nbsp;Index&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distributed&amp;nbsp;Sort&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The reverse web-link graph sounds&amp;nbsp;interesting:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The map function outputs &lt;target , source&gt; pairs for each link to a
target &lt;span class="caps"&gt;URL&lt;/span&gt; found in a page named &amp;#8220;source&amp;#8221;. The reduce function
concatenates the list of all source URLs associated with a given
target &lt;span class="caps"&gt;URL&lt;/span&gt; and emits the pair:
&lt;/target&gt;&lt;target , list(source)&gt;.&lt;/target&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is also &lt;a href="http://atbrox.com/2010/02/08/parallel-machine-learning-for-hadoopmapreduce-a-python-example/"&gt;some work&lt;/a&gt; on using MapReduce to allow for machine
classification to run in parallel. I also found a presentation on &lt;a href="http://www.slideshare.net/marin_dimitrov/large-scale-data-analysis-with-mapreduce-part-i"&gt;Large
Scale Data Analysis&lt;/a&gt; that was&amp;nbsp;helpful.&lt;/p&gt;
&lt;p&gt;The main thing to get my head around is that the map function can return
more complicated results than just a simple count. The reduce function
then just glues the results together in some&amp;nbsp;way.&lt;/p&gt;
&lt;p&gt;And then there is the idea of &lt;a href="http://cookbook.mongodb.org/patterns/unique_items_map_reduce/"&gt;multi-pass MapReduce&lt;/a&gt;. That could get&amp;nbsp;interesting.&lt;/p&gt;
&lt;p&gt;For now, I&amp;#8217;m doing a lot of reading. The next step will be start to put
into practice some of these ideas for analysing data. Actually, the next
step is collecting the data, but that&amp;#8217;s on a different&amp;nbsp;thread.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>Emacs and Colour</title><link href="https://pseudofish.com/emacs-and-colour.html" rel="alternate"></link><published>2010-10-20T09:53:00+02:00</published><updated>2010-10-20T09:53:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-10-20:/emacs-and-colour.html</id><summary type="html">&lt;p&gt;After spending time with emacs, I really enjoy its support for Clojure.
However, the default colour scheme made me&amp;nbsp;sad.&lt;/p&gt;
&lt;p&gt;For vim, I&amp;#8217;ve been using desert and for TextMate, the railscasts colour
theme. Fortunately, someone has already made a Railscast colour theme
for &lt;a href="http://github.com/olegshaldybin/color-theme-railscasts"&gt;emacs&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Installation was painless. Drop a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;After spending time with emacs, I really enjoy its support for Clojure.
However, the default colour scheme made me&amp;nbsp;sad.&lt;/p&gt;
&lt;p&gt;For vim, I&amp;#8217;ve been using desert and for TextMate, the railscasts colour
theme. Fortunately, someone has already made a Railscast colour theme
for &lt;a href="http://github.com/olegshaldybin/color-theme-railscasts"&gt;emacs&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Installation was painless. Drop a file into a directory under .emacs.d
and update my .emacs file&amp;nbsp;with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;color-theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;color-theme-initialize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;load-file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;~/.emacs.d/site-lisp/themes/color-theme-railscasts.el&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;color-theme-railscasts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now emacs loads in a sensible colour scheme and I don&amp;#8217;t hurt my eyes
while&amp;nbsp;programming.&lt;/p&gt;
&lt;p&gt;One more thing I &lt;a href="http://github.com/technomancy/swank-clojure"&gt;found&lt;/a&gt; was the option to set Clojure syntax
highlighting in the repl&amp;nbsp;window:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;slime-repl-mode-hook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;clojure-mode-font-lock-setup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="emacs"></category></entry><entry><title>Owning an Agile Product</title><link href="https://pseudofish.com/owning-an-agile-product.html" rel="alternate"></link><published>2010-09-19T17:23:00+02:00</published><updated>2010-09-19T17:23:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-09-19:/owning-an-agile-product.html</id><summary type="html">&lt;p&gt;One of the challenges in running a successful agile project is having a
strong product&amp;nbsp;owner.&lt;/p&gt;
&lt;p&gt;In learning about agile processes, this is an area I haven&amp;#8217;t read much
about. &lt;a href="http://www.scrumalliance.org/articles/181-owning-an-agile-product"&gt;This recent article&lt;/a&gt; on the Scrum Alliance site is a valuable
addition and thinking about how to build a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;One of the challenges in running a successful agile project is having a
strong product&amp;nbsp;owner.&lt;/p&gt;
&lt;p&gt;In learning about agile processes, this is an area I haven&amp;#8217;t read much
about. &lt;a href="http://www.scrumalliance.org/articles/181-owning-an-agile-product"&gt;This recent article&lt;/a&gt; on the Scrum Alliance site is a valuable
addition and thinking about how to build a better product&amp;nbsp;owner.&lt;/p&gt;
&lt;p&gt;Some&amp;nbsp;quotes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Creating any product can be challenge. With a product being developed
at the speed of agility, these challenges&amp;nbsp;increase.&lt;/p&gt;
&lt;p&gt;What teams need most is a product owner who is able to prioritize the
product&amp;nbsp;backlog.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s the product owner&amp;#8217;s responsibility to know and communicate a
product vision for the team. Knowing where you want to go enables you
to reach your destination; the details of getting there we all
discover along the&amp;nbsp;way.&lt;/p&gt;
&lt;p&gt;Product owners must be able to earn the respect of the team, resolve
conflicts through conversations, and adjust priorities accordingly.
There are whole books dedicated to managing conflicts. Learning when
to take a stand and when to give is important. It is more important,
though, that everyone has a&amp;nbsp;voice.&lt;/p&gt;
&lt;p&gt;Be concerned about creating a stable environment for the team members
to learn and contribute. It&amp;#8217;s imperative that you keep the team from
being&amp;nbsp;distracted.&lt;/p&gt;
&lt;p&gt;The product owner is not a dictated hierarchy, but a service role. The
customer, the team, and the company are all tuned around the product
by the product&amp;nbsp;owner.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is worth &lt;a href="http://www.scrumalliance.org/articles/181-owning-an-agile-product"&gt;reading in full&lt;/a&gt;.&lt;/p&gt;</content><category term="agile"></category></entry><entry><title>Chinese vocabulary for Social Media</title><link href="https://pseudofish.com/chinese-vocabulary-for-social-media.html" rel="alternate"></link><published>2010-09-19T15:30:00+02:00</published><updated>2010-09-19T15:30:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-09-19:/chinese-vocabulary-for-social-media.html</id><summary type="html">&lt;p&gt;&lt;a href="http://www.webbinchina.com/"&gt;Jeremy Webb&lt;/a&gt;, over at the &lt;a href="http://www.asiadigitalmap.com/"&gt;Asia Digital Map blog&lt;/a&gt;, has a great list
of &lt;a href="http://www.asiadigitalmap.com/2010/03/chinese_social_media_vocabulary/"&gt;Chinese terms&lt;/a&gt; for the social media&amp;nbsp;web:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Location-based service: 定位服务 dìngwèi&amp;nbsp;fúwù&lt;/p&gt;
&lt;p&gt;Augmented reality: 现实增强 xiànshí&amp;nbsp;zēngqiáng&lt;/p&gt;
&lt;p&gt;Desktop client: 桌面客户端 zhuōmiàn&amp;nbsp;kèhùduān&lt;/p&gt;
&lt;p&gt;Mobile phone client: 手 …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.webbinchina.com/"&gt;Jeremy Webb&lt;/a&gt;, over at the &lt;a href="http://www.asiadigitalmap.com/"&gt;Asia Digital Map blog&lt;/a&gt;, has a great list
of &lt;a href="http://www.asiadigitalmap.com/2010/03/chinese_social_media_vocabulary/"&gt;Chinese terms&lt;/a&gt; for the social media&amp;nbsp;web:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Location-based service: 定位服务 dìngwèi&amp;nbsp;fúwù&lt;/p&gt;
&lt;p&gt;Augmented reality: 现实增强 xiànshí&amp;nbsp;zēngqiáng&lt;/p&gt;
&lt;p&gt;Desktop client: 桌面客户端 zhuōmiàn&amp;nbsp;kèhùduān&lt;/p&gt;
&lt;p&gt;Mobile phone client: 手机客户端 shǒujī&amp;nbsp;kèhùduān&lt;/p&gt;
&lt;p&gt;App (iPhone etc.): 应用程序 yīngyòng&amp;nbsp;chéngxù&lt;/p&gt;
&lt;p&gt;&amp;#8230;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As I&amp;#8217;ve been using &lt;a href="http://iphone.chbeer.de/en/iVocabulary/"&gt;iVocabulary&lt;/a&gt; to study vocabulary, I added all the
terms into the &lt;a href="http://chbeer.de/updates/provoc/ProVoc.dmg"&gt;ProVoc&lt;/a&gt; (dng)&amp;nbsp;format.&lt;/p&gt;
&lt;p&gt;If you have a Mac, the file is available &lt;a href="/files/SocialMedia.pvoc.zip"&gt;here&lt;/a&gt;&amp;nbsp;(zip).&lt;/p&gt;</content><category term="chinese"></category></entry><entry><title>Learning Clojure with Google App Engine and Emacs</title><link href="https://pseudofish.com/learning-clojure-with-google-app-engine-and-emacs.html" rel="alternate"></link><published>2010-09-18T23:30:00+02:00</published><updated>2010-09-18T23:30:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-09-18:/learning-clojure-with-google-app-engine-and-emacs.html</id><summary type="html">&lt;p&gt;This is an overview to my attempts at getting Clojure with Emacs.
Inspired by &lt;a href="http://www.hackers-with-attitude.com/2009/08/intertactive-programming-with-clojure.html"&gt;this post&lt;/a&gt;, I set out to learn three things
simultaneously: emacs, clojure and Google App&amp;nbsp;Engine.&lt;/p&gt;
&lt;p&gt;For comparison, my current web prototyping combination is TextMate,
Rails, and Heroku. Prior to that it was a mix of …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is an overview to my attempts at getting Clojure with Emacs.
Inspired by &lt;a href="http://www.hackers-with-attitude.com/2009/08/intertactive-programming-with-clojure.html"&gt;this post&lt;/a&gt;, I set out to learn three things
simultaneously: emacs, clojure and Google App&amp;nbsp;Engine.&lt;/p&gt;
&lt;p&gt;For comparison, my current web prototyping combination is TextMate,
Rails, and Heroku. Prior to that it was a mix of python, php or perl,
with&amp;nbsp;vim.&lt;/p&gt;
&lt;p&gt;There are already number of articles on getting &lt;span class="caps"&gt;GAE&lt;/span&gt; and Clojure to work.
Consider this me making notes for myself because I keep forgetting the
Emacs&amp;nbsp;shortcuts!&lt;/p&gt;
&lt;h3&gt;Emacs&lt;/h3&gt;
&lt;p&gt;I settled on Aquamacs to start out with emacs on the Mac. It seems to be
more forgiving if I use normal Mac keyboard shortcuts while I learn
emacs keys. Also makes it easy to switch between it and&amp;nbsp;TextMate.&lt;/p&gt;
&lt;p&gt;The other feature I love is full screen mode:&amp;nbsp;⌘-Shift-Return&lt;/p&gt;
&lt;p&gt;To get command line access, you need to go to Tools-&amp;gt;Install Command
Line Tools. This gives you an &amp;#8220;&lt;code&gt;aquamacs&lt;/code&gt;&amp;#8221; shortcut in the shell. I
aliased it to &amp;#8220;&lt;code&gt;aq&lt;/code&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;For some help on learning emacs,&amp;nbsp;consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.gnu.org/software/emacs/tour/"&gt;Emacs&amp;nbsp;Tour&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.elmindreda.org/emacs.html"&gt;Emacs for Vi&amp;nbsp;users&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may also want to setup Clojure to run with &lt;a href="http://riddell.us/ClojureSwankLeiningenWithEmacsOnLinux.html"&gt;Emacs&lt;/a&gt;. &lt;a href="http://riddell.us/ClojureSwankLeiningenWithEmacsOnLinux.html"&gt;This
article&lt;/a&gt; assumes you are using&amp;nbsp;lein.&lt;/p&gt;
&lt;h3&gt;Google App Engine (&lt;span class="caps"&gt;GAE&lt;/span&gt;)&lt;/h3&gt;
&lt;p&gt;The &lt;span class="caps"&gt;GAE&lt;/span&gt; distribution is available here: &lt;a href="http://code.google.com/appengine/downloads.html"&gt;&lt;span class="caps"&gt;GAE&lt;/span&gt; Download&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I setup my shell to include a $GAE_BASE directory for where I unpacked
it, and added $GAE_BASE/bin to my&amp;nbsp;path.&lt;/p&gt;
&lt;h3&gt;Creating a Clojure&amp;nbsp;Project&lt;/h3&gt;
&lt;p&gt;The first post I read assumed that you were starting with a manual
layout of your project. I&amp;#8217;m going to use lein, a build manager for
clojure, similar to rake for ruby. Behind the scenes lein uses Java&amp;#8217;s
maven as a package management system (similar to&amp;nbsp;gems).&lt;/p&gt;
&lt;p&gt;To make things a bit more interesting, I plan to write a very basic &lt;span class="caps"&gt;CMS&lt;/span&gt;
to explore the various APIs. I&amp;#8217;m keeping everything on the &lt;a href="http://github.com/gmwils/gaecms"&gt;githubs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The steps to getting setup look something&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;lein&lt;span class="w"&gt; &lt;/span&gt;new&lt;span class="w"&gt; &lt;/span&gt;gaecms
$&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;war/WEB-INF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then make some changes to your project.clj&amp;nbsp;file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defproject &lt;/span&gt;&lt;span class="nv"&gt;gae-cms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.0.0-SNAPSHOT&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ss"&gt;:description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A basic CMS built on Google App Engine (GAE)&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ss"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;org.clojure/clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.2.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;org.clojure/clojure-contrib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.2.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.4.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring/ring-servlet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.2.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;appengine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.4-SNAPSHOT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="ss"&gt;:dev-dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;leiningen/lein-swank&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.2.0-SNAPSHOT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="ss"&gt;:compile-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;war/WEB-INF/classes&amp;quot;&lt;/span&gt;
&lt;span class="ss"&gt;:library-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;war/WEB-INF/lib&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To save some typing, you can clone:
&lt;a href="http://github.com/gmwils/gaecms"&gt;git://github.com/gmwils/gaecms.git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To run the interpreter locally, try the&amp;nbsp;following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;lein&lt;span class="w"&gt; &lt;/span&gt;deps
$&lt;span class="w"&gt; &lt;/span&gt;lein&lt;span class="w"&gt; &lt;/span&gt;swank
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To test out that the interpreted mode is working, open up
src/gae_cms/core.clj in &lt;span class="caps"&gt;AQ&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Then connect to the&amp;nbsp;server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;M&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slime&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;connect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;From within the editor, you can now run either of the&amp;nbsp;following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;C-x C-e    % evaluate current line
C-c C-k    % compile the current file
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You also have an interactive clojure shell for typing commands into. Try
adding the following into your source code and then pressing C-x C-e to&amp;nbsp;evaluate:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(System/getProperty &amp;quot;java.class.path&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should see your current &lt;span class="caps"&gt;CLASSPATH&lt;/span&gt; printed&amp;nbsp;out.&lt;/p&gt;
&lt;h3&gt;Setup for &lt;span class="caps"&gt;GAE&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;In &lt;code&gt;$HOME/war/WEB-INF/web.xml&lt;/code&gt; map the URLs that you want your custom
servlet to handle. In this case, send everything into the&amp;nbsp;servlet:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;ISO-8859-1&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;web-app&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://java.sun.com/xml/ns/javaee&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2.5&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;display-name&amp;gt;&lt;/span&gt;CMS&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;GAE&lt;span class="nt"&gt;&amp;lt;/display-name&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;servlet&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;cms&lt;span class="nt"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;servlet-class&amp;gt;&lt;/span&gt;gae-cms.core&lt;span class="nt"&gt;&amp;lt;/servlet-class&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/servlet&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;servlet-mapping&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;cms&lt;span class="nt"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/&lt;span class="nt"&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/web-app&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In &lt;code&gt;$HOME/war/WEB-INF/appengine-web.xml&lt;/code&gt; add the following to setup
Google App Engine to refer to your servlet&amp;nbsp;above.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;appengine-web-app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://appengine.google.com/ns/1.0&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;application&amp;gt;&lt;/span&gt;cms-clj&lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="cm"&gt;&amp;lt;!-- GAE app id for your app --&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;v0-1&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="cm"&gt;&amp;lt;!-- Arbritrary Version Id --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/appengine-web-app&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, update src/gaecms/core.clj&amp;nbsp;with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;ns &lt;/span&gt;&lt;span class="nv"&gt;gaecms.core&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:gen-class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;javax.servlet.http.HttpServlet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:use&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;compojure.core&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring.util.servlet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:only&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;defservice&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure.route&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;route&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cms-public&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;html&amp;gt;&amp;lt;title&amp;gt;GAE CMS&amp;lt;/title&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cms&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;cms-public&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route/not-found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Page not found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; 404 error page&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defservice&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To test this locally,&amp;nbsp;try:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;lein&lt;span class="w"&gt; &lt;/span&gt;deps
$&lt;span class="w"&gt; &lt;/span&gt;lein&lt;span class="w"&gt; &lt;/span&gt;compile
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$GAESDK&lt;/span&gt;/bin/dev_appserver.sh&lt;span class="w"&gt; &lt;/span&gt;war
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Deploying to&amp;nbsp;Google&lt;/h3&gt;
&lt;p&gt;First go to the &lt;a href="https://appengine.google.com/"&gt;&lt;span class="caps"&gt;GAE&lt;/span&gt; console&lt;/a&gt; and create an application. The following
should then&amp;nbsp;work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;lein&lt;span class="w"&gt; &lt;/span&gt;deps
$&lt;span class="w"&gt; &lt;/span&gt;lein&lt;span class="w"&gt; &lt;/span&gt;compile
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$GAESDK&lt;/span&gt;/bin/appcfg.sh&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt; &lt;/span&gt;war
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I&amp;#8217;m still playing with getting it working with Google App Engine. The
above is enough to get &lt;a href="http://cms-clj.appspot.com/"&gt;hello world&lt;/a&gt;&amp;nbsp;working.&lt;/p&gt;
&lt;p&gt;For more details, I suggest you follow the &lt;a href="http://compojureongae.posterous.com"&gt;Compojure on &lt;span class="caps"&gt;GAE&lt;/span&gt;&lt;/a&gt; blog.
Specifically, the article on &lt;a href="http://compojureongae.posterous.com/deploying-to-app-engine"&gt;Deploying to App Engine&lt;/a&gt;is a good&amp;nbsp;overview.&lt;/p&gt;
&lt;p&gt;Next steps include getting &lt;a href="http://compojureongae.posterous.com/getting-interactive-development-to-work-again"&gt;interactive development&lt;/a&gt; working with &lt;span class="caps"&gt;GAE&lt;/span&gt;,
and actually handling &lt;a href="http://compojureongae.posterous.com/accessing-the-app-engine-datastore"&gt;dynamic content&lt;/a&gt;.&lt;/p&gt;</content><category term="programming"></category></entry><entry><title>How to fix online advertising</title><link href="https://pseudofish.com/how-to-fix-online-advertising.html" rel="alternate"></link><published>2010-08-13T15:12:00+02:00</published><updated>2010-08-13T15:12:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-08-13:/how-to-fix-online-advertising.html</id><summary type="html">&lt;p&gt;Fark&amp;#8217;s Drew Curtis is &lt;a href="http://radar.oreilly.com/2010/08/how-to-fix-online-advertising.html"&gt;interviewed&lt;/a&gt; by the O&amp;#8217;Reilly team and has some
good insights on how to succeed with internet&amp;nbsp;advertising.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It&amp;#8217;s not the model. It&amp;#8217;s the pricing.&lt;/strong&gt; That sounds obvious, but it
all comes down to effective sales methods. Digital salespeople are
slowly building a …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;Fark&amp;#8217;s Drew Curtis is &lt;a href="http://radar.oreilly.com/2010/08/how-to-fix-online-advertising.html"&gt;interviewed&lt;/a&gt; by the O&amp;#8217;Reilly team and has some
good insights on how to succeed with internet&amp;nbsp;advertising.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It&amp;#8217;s not the model. It&amp;#8217;s the pricing.&lt;/strong&gt; That sounds obvious, but it
all comes down to effective sales methods. Digital salespeople are
slowly building a narrative that not all ad impressions are equal, and
those that are wrapped around compelling content are more valuable
than, say, impressions that rip by when you poke someone on&amp;nbsp;Facebook.&lt;/p&gt;
&lt;p&gt;&amp;#8230;&lt;/p&gt;
&lt;p&gt;it&amp;#8217;s not really any one metric. It&amp;#8217;s more about what ratio of uniques
to visits to page views is the best. Ideally, &lt;strong&gt;you want a large
number of uniques who visit on a regular basis and consume 3-5 page
views per&amp;nbsp;visit.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And a few ideas on improving&amp;nbsp;sales:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Change the sales narrative &amp;#8212; Not all impressions are created
    equal. Not all audiences have the same&amp;nbsp;value.&lt;/li&gt;
&lt;li&gt;Reduce industry-wide available&amp;nbsp;inventory&lt;/li&gt;
&lt;li&gt;Augment with subscription content of some kind &amp;#8212; Any&amp;nbsp;kind.&lt;/li&gt;
&lt;li&gt;If you have a community, do an annual&amp;nbsp;event.&lt;/li&gt;
&lt;li&gt;If you have a content niche, sell product on&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;Cut overhead dramatically &amp;#8212; Legacy media was used to having
    individual regional monopolies with 40-percent profit&amp;nbsp;margins&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is a lot more in the &lt;a href="http://radar.oreilly.com/2010/08/how-to-fix-online-advertising.html"&gt;article&lt;/a&gt;.&lt;/p&gt;</content><category term="media"></category></entry><entry><title>Agile Retrospectives</title><link href="https://pseudofish.com/agile-retrospectives.html" rel="alternate"></link><published>2010-07-02T16:54:00+02:00</published><updated>2010-07-02T16:54:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-07-02:/agile-retrospectives.html</id><summary type="html">&lt;object width="480" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/qqtPZYigfNI&amp;amp;hl=en_US&amp;amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/qqtPZYigfNI&amp;amp;hl=en_US&amp;amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;p&gt;Presentation from the authors of the book &amp;#8220;&lt;a href="http://www.amazon.com/Agile-Retrospectives-Making-Teams-Great/dp/0977616649/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1278053670&amp;amp;sr=8-1"&gt;Agile Retrospectives&lt;/a&gt; -
Making Good Teams Great&amp;#8221; at Google. Lots of great tips on how to improve
your sprint &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; project&amp;nbsp;retrospectives.&lt;/p&gt;
&lt;p&gt;One tip I picked up on was to ask &amp;#8220;how was the energy for this sprint?&amp;#8221;
rather than the bland &amp;#8220;how are you …&lt;/p&gt;</summary><content type="html">&lt;object width="480" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/qqtPZYigfNI&amp;amp;hl=en_US&amp;amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/qqtPZYigfNI&amp;amp;hl=en_US&amp;amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;p&gt;Presentation from the authors of the book &amp;#8220;&lt;a href="http://www.amazon.com/Agile-Retrospectives-Making-Teams-Great/dp/0977616649/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1278053670&amp;amp;sr=8-1"&gt;Agile Retrospectives&lt;/a&gt; -
Making Good Teams Great&amp;#8221; at Google. Lots of great tips on how to improve
your sprint &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; project&amp;nbsp;retrospectives.&lt;/p&gt;
&lt;p&gt;One tip I picked up on was to ask &amp;#8220;how was the energy for this sprint?&amp;#8221;
rather than the bland &amp;#8220;how are you&amp;nbsp;feeling?&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Their structure for a retrospective&amp;nbsp;is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set the&amp;nbsp;Stage&lt;/li&gt;
&lt;li&gt;Gather&amp;nbsp;Data&lt;/li&gt;
&lt;li&gt;Generate&amp;nbsp;Insights&lt;/li&gt;
&lt;li&gt;Decide What to&amp;nbsp;Do&lt;/li&gt;
&lt;li&gt;Close the&amp;nbsp;Retrospective&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The way to succeed with a process such as agile is through continuous
improvement. The forum for reviewing what needs to be improved and to
decide on how to improve things is the sprint&amp;nbsp;retrospectives.&lt;/p&gt;
&lt;p&gt;Retrospectives are critical for having a successful&amp;nbsp;project.&lt;/p&gt;</content><category term="agile"></category></entry><entry><title>Change Host for a Git Origin Server</title><link href="https://pseudofish.com/change-host-for-a-git-origin-server.html" rel="alternate"></link><published>2010-06-28T21:19:00+02:00</published><updated>2010-06-28T21:19:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-06-28:/change-host-for-a-git-origin-server.html</id><summary type="html">&lt;p&gt;Hopefully this isn&amp;#8217;t something you need to do. The server that I&amp;#8217;ve been
using to collaborate on a few git projects with had the domain name
expire. This meant finding a way of migrating the local repositories to
get back in&amp;nbsp;sync.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Thanks to @&lt;a href="http://twitter.com/mawolf/status/17334075193"&gt;mawolf&lt;/a&gt; for pointing …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hopefully this isn&amp;#8217;t something you need to do. The server that I&amp;#8217;ve been
using to collaborate on a few git projects with had the domain name
expire. This meant finding a way of migrating the local repositories to
get back in&amp;nbsp;sync.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Thanks to @&lt;a href="http://twitter.com/mawolf/status/17334075193"&gt;mawolf&lt;/a&gt; for pointing out there is an easy way
with recent git versions (post Feb,&amp;nbsp;2010):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git remote set-url origin ssh://newhost.com/usr/local/gitroot/myproject.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;See the &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-remote.html"&gt;man page&lt;/a&gt; for&amp;nbsp;details.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re on an older version, then try&amp;nbsp;this:&lt;/p&gt;
&lt;p&gt;As a caveat, this works only as it is the same server, just with
different&amp;nbsp;names.&lt;/p&gt;
&lt;p&gt;Assuming that the new hostname is &amp;#8220;newhost.com&amp;#8221;, and the old one was
&amp;#8220;oldhost.com&amp;#8221;, the change is quite&amp;nbsp;simple.&lt;/p&gt;
&lt;p&gt;Edit the .git/config file in your working directory. You should see
something&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[remote &amp;quot;origin&amp;quot;]&lt;/span&gt;
&lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;+refs/heads/*:refs/remotes/origin/*&lt;/span&gt;
&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ssh://oldhost.com/usr/local/gitroot/myproject.git&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Change &lt;code&gt;oldhost.com&lt;/code&gt; to &lt;code&gt;newhost.com&lt;/code&gt;, save the file and you&amp;#8217;re&amp;nbsp;done.&lt;/p&gt;
&lt;p&gt;From my limited testing (git pull origin; git push origin; gitx)
everything seems in order. And yes, I know it is bad form to mess with
git&amp;nbsp;internals.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>A/B Testing Overview</title><link href="https://pseudofish.com/ab-testing-overview.html" rel="alternate"></link><published>2010-06-25T10:41:00+02:00</published><updated>2010-06-25T10:41:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-06-25:/ab-testing-overview.html</id><summary type="html">&lt;p&gt;A/B Testing is how sites like Amazon, Yahoo, Google, Facebook and others
became the best in the world. They used data to drive decisions about
content, layout, wording and other aspects of their&amp;nbsp;sites.&lt;/p&gt;
&lt;p&gt;Smashing magazine covers the details of A/B testing in &lt;a href="http://www.smashingmagazine.com/2010/06/24/the-ultimate-guide-to-a-b-testing/"&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;At its core …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;A/B Testing is how sites like Amazon, Yahoo, Google, Facebook and others
became the best in the world. They used data to drive decisions about
content, layout, wording and other aspects of their&amp;nbsp;sites.&lt;/p&gt;
&lt;p&gt;Smashing magazine covers the details of A/B testing in &lt;a href="http://www.smashingmagazine.com/2010/06/24/the-ultimate-guide-to-a-b-testing/"&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;At its core, A/B testing is exactly what it sounds like: you have two
versions of an element (A and B) and a metric that defines success. To
determine which version is better, you subject both versions to
experimentation simultaneously. In the end, you measure which version
was more successful and select that version for real-world&amp;nbsp;use.&lt;/p&gt;
&lt;p&gt;37signals tested the headline on its pricing page. It found that
“30-Day Free Trial on All Accounts” generated 30% more sign-ups than
the original “Start a Highrise&amp;nbsp;Account.”&lt;/p&gt;
&lt;p&gt;Dustin found that “You should follow me on Twitter here” worked 173%
better than his control text, “I’m on&amp;nbsp;Twitter.”&lt;/p&gt;
&lt;p&gt;Along with its other A/B tests, CareLogger increased its conversion
rate by 34% simply by changing the color of the sign-up button from
green to&amp;nbsp;red!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;a href="http://www.smashingmagazine.com/2010/06/24/the-ultimate-guide-to-a-b-testing/"&gt;article&lt;/a&gt; covers the results from others of testing, as
well as details on how to get started for your own&amp;nbsp;site.&lt;/p&gt;
&lt;p&gt;What I find interesting is that the tools that used to require
significant investment in time and development are increasingly
available as easy to use, free&amp;nbsp;solutions.&lt;/p&gt;</content><category term="design"></category></entry><entry><title>Using TextMate with Google Docs</title><link href="https://pseudofish.com/using-textmate-with-google-docs.html" rel="alternate"></link><published>2010-06-22T11:19:00+02:00</published><updated>2010-06-22T11:19:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-06-22:/using-textmate-with-google-docs.html</id><summary type="html">&lt;p&gt;The new &lt;a href="http://google-opensource.blogspot.com/2010/06/introducing-google-command-line-tool.html"&gt;Google Command Line&lt;/a&gt; opens up some interesting possibilities.
One that I wanted to explore was using TextMate to edit basic Google&amp;nbsp;Docs.&lt;/p&gt;
&lt;p&gt;First, install Google&amp;#8217;s &lt;a href="http://code.google.com/p/googlecl/wiki/SystemRequirements"&gt;Command Line&lt;/a&gt; tool. Details are on &lt;a href="http://code.google.com/p/googlecl/wiki/SystemRequirements"&gt;their
wiki&lt;/a&gt; for each &lt;span class="caps"&gt;OS&lt;/span&gt;. There are lots of tips in the comments
and even a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The new &lt;a href="http://google-opensource.blogspot.com/2010/06/introducing-google-command-line-tool.html"&gt;Google Command Line&lt;/a&gt; opens up some interesting possibilities.
One that I wanted to explore was using TextMate to edit basic Google&amp;nbsp;Docs.&lt;/p&gt;
&lt;p&gt;First, install Google&amp;#8217;s &lt;a href="http://code.google.com/p/googlecl/wiki/SystemRequirements"&gt;Command Line&lt;/a&gt; tool. Details are on &lt;a href="http://code.google.com/p/googlecl/wiki/SystemRequirements"&gt;their
wiki&lt;/a&gt; for each &lt;span class="caps"&gt;OS&lt;/span&gt;. There are lots of tips in the comments
and even a &lt;a href="https://www.dustin.li/Publish/Software/Entries/2010/6/19_GoogleCL_Mac_OS_X_binary.html"&gt;packaged installer&lt;/a&gt;. (I used &lt;code&gt;port&lt;/code&gt;s to&amp;nbsp;install)&lt;/p&gt;
&lt;p&gt;The next step is to create a symlink from the &amp;#8220;mate&amp;#8221; command to
&amp;#8220;mate_wait&amp;#8221;. What this does is default the wait argument to true. This
is needed for the Google script to detect changes to your&amp;nbsp;document.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ln -s /usr/bin/mate /usr/bin/mate_wait
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can now open a document in&amp;nbsp;TextMate:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;google docs edit --title &amp;quot;Ideas&amp;quot; --editor &amp;quot;mate_wait&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you select a title for a document that doesn&amp;#8217;t exist, it will be
created. Once you close the file in TextMate, control returns to the
shell and the document is updated on Google&amp;#8217;s&amp;nbsp;servers.&lt;/p&gt;
&lt;p&gt;You are only able to edit in text only mode. So it works best on
documents without any&amp;nbsp;formatting.&lt;/p&gt;
&lt;p&gt;To list your existing documents,&amp;nbsp;try:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;google docs list
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="technology"></category></entry><entry><title>RSpec XHTML Validation of Views</title><link href="https://pseudofish.com/rspec-xhtml-validation-of-views.html" rel="alternate"></link><published>2010-06-19T16:02:00+02:00</published><updated>2010-06-19T16:02:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-06-19:/rspec-xhtml-validation-of-views.html</id><summary type="html">&lt;p&gt;A great way to learn is to read other people&amp;#8217;s code. And in that vein,
Chris Lowe has a &lt;a href="http://blog.chrislowis.co.uk/2010/05/31/five-rails-apps-to-study-and-learn-from.html"&gt;great post&lt;/a&gt; on suggested &lt;span class="caps"&gt;OSS&lt;/span&gt; Rails apps to &lt;a href="http://blog.chrislowis.co.uk/2010/05/31/five-rails-apps-to-study-and-learn-from.html"&gt;look
into&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One technique I picked up from [simply_agile][] is to validate the &lt;span class="caps"&gt;HTML&lt;/span&gt;
output by your views. That way, bad &lt;span class="caps"&gt;HTML …&lt;/span&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;A great way to learn is to read other people&amp;#8217;s code. And in that vein,
Chris Lowe has a &lt;a href="http://blog.chrislowis.co.uk/2010/05/31/five-rails-apps-to-study-and-learn-from.html"&gt;great post&lt;/a&gt; on suggested &lt;span class="caps"&gt;OSS&lt;/span&gt; Rails apps to &lt;a href="http://blog.chrislowis.co.uk/2010/05/31/five-rails-apps-to-study-and-learn-from.html"&gt;look
into&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One technique I picked up from [simply_agile][] is to validate the &lt;span class="caps"&gt;HTML&lt;/span&gt;
output by your views. That way, bad &lt;span class="caps"&gt;HTML&lt;/span&gt; isn&amp;#8217;t&amp;nbsp;introduced.&lt;/p&gt;
&lt;p&gt;To start with, you need to install the [assert_valid_xhtml][] plugin
and the libxml-ruby&amp;nbsp;gem.&lt;/p&gt;
&lt;p&gt;In your [spec/spec_helper.rb][] file, add the following inside the
config&amp;nbsp;block:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;config&lt;/span&gt;.&lt;span class="k"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ValidateXhtml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And at the end of the file, outside the config block, include the&amp;nbsp;following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;describe &amp;quot;a standard view&amp;quot;, :shared =&amp;gt; true do
  it &amp;quot;should be successful&amp;quot; do
    response.should be_success
  end
  it &amp;quot;should be valid&amp;quot; do
    response.should be_valid_xhtml
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now in your &lt;a href="http://github.com/camelpunch/simply_agile/tree/master/spec/views"&gt;view specs&lt;/a&gt;, include the following&amp;nbsp;line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;it_should_behave_like &amp;quot;a standard view&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And that&amp;#8217;s it. Now each view will be tested for valid xhtml when you run
your&amp;nbsp;specs.&lt;/p&gt;
&lt;p&gt;There are a lot of other great techniques scattered through the projects
mentioned in the &lt;a href="http://blog.chrislowis.co.uk/2010/05/31/five-rails-apps-to-study-and-learn-from.html"&gt;original post&lt;/a&gt;. And if you want more
details on good practices for RSpec, check out the &lt;a href="http://www.pragprog.com/titles/achbd/the-rspec-book"&gt;RSpec Book&lt;/a&gt;.&lt;/p&gt;</content><category term="programming"></category></entry><entry><title>Learning Chinese - continued</title><link href="https://pseudofish.com/learning-chinese-continued.html" rel="alternate"></link><published>2010-06-18T15:29:00+02:00</published><updated>2010-06-18T15:29:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-06-18:/learning-chinese-continued.html</id><summary type="html">&lt;p&gt;Since my &lt;a href="http://pseudofish.com/blog/2008/12/12/learning-chinese/"&gt;last post&lt;/a&gt;, I&amp;#8217;ve spent a fair bit more time on improving my
Chinese. Some recent changes to my routine have improved the speed at
which I&amp;#8217;ve been&amp;nbsp;learning.&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Great Wall at Badaling, China" src="http://farm4.static.flickr.com/3225/3106536779_0df938e70f.jpg"&gt;][]&lt;/p&gt;
&lt;h3&gt;Lingt&lt;/h3&gt;
&lt;p&gt;I already use flash cards, but am now spending more time using
&lt;a href="http://lingt.com/refer/2091ae7a702db7b"&gt;Lingt.com&lt;/a&gt;. They run an …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Since my &lt;a href="http://pseudofish.com/blog/2008/12/12/learning-chinese/"&gt;last post&lt;/a&gt;, I&amp;#8217;ve spent a fair bit more time on improving my
Chinese. Some recent changes to my routine have improved the speed at
which I&amp;#8217;ve been&amp;nbsp;learning.&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Great Wall at Badaling, China" src="http://farm4.static.flickr.com/3225/3106536779_0df938e70f.jpg"&gt;][]&lt;/p&gt;
&lt;h3&gt;Lingt&lt;/h3&gt;
&lt;p&gt;I already use flash cards, but am now spending more time using
&lt;a href="http://lingt.com/refer/2091ae7a702db7b"&gt;Lingt.com&lt;/a&gt;. They run an online language learning program, that
includes audio and writing. My accuracy is improving on words I swore I
already knew, but turns out I didn&amp;#8217;t know that&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;The site also includes badges and incentives to keep you coming back
each day. They remember what you&amp;#8217;ve been studying and only allow you to
study a certain amount each day, keeping your memory fresh. This is a
key part to their success. They&amp;#8217;ll replay words at the point where you
forget them, increasing the effectiveness of your&amp;nbsp;time.&lt;/p&gt;
&lt;h3&gt;Reading&lt;/h3&gt;
&lt;p&gt;This was so simple I couldn&amp;#8217;t believe it. To get good at reading
Chinese, start reading&amp;nbsp;Chinese.&lt;/p&gt;
&lt;p&gt;It has always been my goal to be able to read Chinese content on the
web. However, I had also believed that my Chinese wasn&amp;#8217;t yet good&amp;nbsp;enough.&lt;/p&gt;
&lt;p&gt;Reading &lt;a href="http://en.wikipedia.org/wiki/Kató_Lomb"&gt;Kató Lomb&lt;/a&gt;&amp;#8216;s &lt;a href="http://tesl-ej.org/ej45/fr1abs.html"&gt;book&lt;/a&gt; was enlightening. She taught herself
more than 16 languages. In her &lt;a href="http://tesl-ej.org/ej45/fr1abs.html"&gt;book&lt;/a&gt;, she outlines her&amp;nbsp;techniques.&lt;/p&gt;
&lt;p&gt;The one that stood out for me was her dedication to reading material in
the desired language, well before you can fully understand it. Instead,
aim for getting the gist of it on the first read. Don&amp;#8217;t look up every
word in a dictionary, rather look up those that re-occur lots. Then
re-read the&amp;nbsp;book.&lt;/p&gt;
&lt;p&gt;For the past few months, I&amp;#8217;ve been trying to read two books in Chinese.
I find both interesting and I&amp;#8217;m learning a lot of Chinese as I go. It
doesn&amp;#8217;t (yet) feel like reading, but more like attempting a crossword&amp;nbsp;puzzle.&lt;/p&gt;
&lt;p&gt;When I started, it would take me around half an hour to muddle through a
paragraph. Now, I can often get through between a half and a full&amp;nbsp;page.&lt;/p&gt;
&lt;p&gt;One caveat, you do need to allocate time to it. I aim for half an hour a
day. Kató suggests that you should be spending at least 12 hours a week
on learning a new&amp;nbsp;language.&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Shopping, Chinatown, Singapore" src="http://farm4.static.flickr.com/3376/3578792744_b7ed624268.jpg"&gt;][]&lt;/p&gt;
&lt;h3&gt;Talking&lt;/h3&gt;
&lt;p&gt;I read a great article recently on &lt;a href="http://www.sinosplice.com/life/archives/2007/05/13/how-i-learned-chinese-part-2"&gt;learning Chinese&lt;/a&gt;. The interesting
part for me was to look at finding Chinese speakers who&amp;#8217;s English is
worse than my Chinese. This makes sense once you think about it; I just
hadn&amp;#8217;t thought about&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;I still have yet to action this particular plan, and am keeping it on my
todo list for&amp;nbsp;now.&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Great Wall at Badaling, China" src="http://farm4.static.flickr.com/3225/3106536779_0df938e70f.jpg"&gt;]: http://www.flickr.com/photos/gmwils/3106536779/
    &amp;#8220;Great Wall at Badaling, China by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Shopping, Chinatown, Singapore" src="http://farm4.static.flickr.com/3376/3578792744_b7ed624268.jpg"&gt;]: http://www.flickr.com/photos/gmwils/3578792744/
    &amp;#8220;Shopping, Chinatown, Singapore by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;</content><category term="chinese"></category></entry><entry><title>Clojure with TextMate on the Mac</title><link href="https://pseudofish.com/clojure-with-textmate-on-the-mac.html" rel="alternate"></link><published>2010-06-17T21:41:00+02:00</published><updated>2010-06-17T21:41:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-06-17:/clojure-with-textmate-on-the-mac.html</id><summary type="html">&lt;p&gt;&lt;a href="http://clojure.org/getting_started"&gt;Clojure&lt;/a&gt; has been getting a bit of press recently, such as prominence
on the ThoughtWorks &lt;a href="http://www.thoughtworks.com/radar/"&gt;Technology Radar&lt;/a&gt;. Having spent some time
learning Lisp in the &lt;a href="http://pseudofish.com/blog/2007/02/14/lisp-in-a-box/"&gt;past&lt;/a&gt;, I thought it could be a good holiday
project to play&amp;nbsp;with.&lt;/p&gt;
&lt;p&gt;This post pulls together some of the resources I found for getting …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://clojure.org/getting_started"&gt;Clojure&lt;/a&gt; has been getting a bit of press recently, such as prominence
on the ThoughtWorks &lt;a href="http://www.thoughtworks.com/radar/"&gt;Technology Radar&lt;/a&gt;. Having spent some time
learning Lisp in the &lt;a href="http://pseudofish.com/blog/2007/02/14/lisp-in-a-box/"&gt;past&lt;/a&gt;, I thought it could be a good holiday
project to play&amp;nbsp;with.&lt;/p&gt;
&lt;p&gt;This post pulls together some of the resources I found for getting
started. I&amp;#8217;m not going to try and sell you on a Lisp dialect that
integrates into the &lt;span class="caps"&gt;JVM&lt;/span&gt;, it should be self&amp;nbsp;evident.&lt;/p&gt;
&lt;h3&gt;TextMate&amp;nbsp;Setup&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt; has a &lt;a href="http://github.com/nullstyle/clojure-tmbundle"&gt;bundle&lt;/a&gt; that makes it very simple to get started.
It includes the clojure runtime, and so you can run clojure code after
installation. To install (assuming you have&amp;nbsp;git):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~/&lt;/span&gt;&lt;span class="n"&gt;Library&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;\&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Support&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;TextMate&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Bundles&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nullstyle&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tmbundle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Clojure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tmbundle&lt;/span&gt;
&lt;span class="n"&gt;osascript&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tell app &amp;quot;TextMate&amp;quot; to reload bundles&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then create a folder, open it in TextMate, create a file (ie.
&lt;code&gt;test.clj&lt;/code&gt;) and put some sample code into&amp;nbsp;it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(+ 1 2 3)
(println &amp;quot;Hello from the console&amp;quot;)
(. javax.swing.JOptionPane (showMessageDialog nil &amp;quot;Hello World&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Put the cursor into one of the expressions and press Apple-R. TextMate
will figure the rest out and show the result. Apple-Shift-R will run all
the&amp;nbsp;expressions.&lt;/p&gt;
&lt;p&gt;(The &lt;a href="http://www.assembla.com/wiki/show/clojure/Getting_Started_with_Vim"&gt;Vim&lt;/a&gt; setup looks really good, but I&amp;#8217;m committed to learning
TextMate at the&amp;nbsp;moment)&lt;/p&gt;
&lt;h3&gt;Tutorials&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;m not going to be exhaustive on this, but thought I&amp;#8217;d include a few
pointers (see also &lt;a href="http://alexandrenotebook.blogspot.com/2009/04/starting-up-clojure-simple-tips.html"&gt;Alexandre&amp;#8217;s summary&lt;/a&gt;). There is a video series
available on &lt;a href="http://www.youtube.com/watch?v=Aoeav_T1ARU&amp;amp;feature=PlayList&amp;amp;p=00D7ACB417C22451&amp;amp;index=0&amp;amp;playnext=1"&gt;YouTube&lt;/a&gt;, and also on &lt;a href="http://clojure.blip.tv/"&gt;BlipTV&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://clojure.org/cheatsheet"&gt;This&lt;/a&gt; is an overview in a cheatsheet, and there is a fairly complete
language reference &lt;a href="http://java.ociweb.com/mark/clojure/article.html"&gt;here&lt;/a&gt; and a longer &lt;a href="http://java.ociweb.com/mark/clojure/"&gt;list of references&lt;/a&gt; as&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;Given that Clojure is Lisp based, it would make sense to understand
Lisp. The best option is a book called &lt;a href="http://www.gigamonkeys.com/book/"&gt;Practical Common Lisp&lt;/a&gt;. This
is available on the web for free, or can be purchased from&amp;nbsp;Amazon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Apparently I was off a bit on the utility of the Common Lisp&amp;nbsp;book.&lt;/p&gt;
&lt;p&gt;From @&lt;a href="https://twitter.com/cemerick/status/16382771631"&gt;cemerick&lt;/a&gt;: @&lt;a href="http://twitter.com/gmwils"&gt;gmwils&lt;/a&gt; &lt;span class="caps"&gt;FYI&lt;/span&gt;, Clojure is a lisp, but has little
to do with Common Lisp. For books, try &lt;a href="http://bit.ly/ccSw2Z"&gt;http://bit.ly/ccSw2Z&lt;/a&gt; or
&lt;a href="http://joyofclojure.com/"&gt;http://joyofclojure.com/&lt;/a&gt;&lt;/p&gt;</content><category term="clojure"></category></entry><entry><title>Quantitative Trading</title><link href="https://pseudofish.com/quantitative-trading.html" rel="alternate"></link><published>2010-05-11T00:36:00+02:00</published><updated>2010-05-11T00:36:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-05-11:/quantitative-trading.html</id><summary type="html">&lt;p&gt;Quantitative trading is something I know almost nothing about, but is a
topic that I find interesting. Mixing computers, math and some luck to
automate trading strategies just sounds&amp;nbsp;fun.&lt;/p&gt;
&lt;p&gt;When a &lt;a href="http://twitter.com/jpburton"&gt;friend&lt;/a&gt; recommended &lt;a href="http://www.amazon.com/Quantitative-Trading-Build-Algorithmic-Business/dp/0470284889/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1273500859&amp;amp;sr=8-1"&gt;Quantitative Trading&lt;/a&gt; by &lt;a href="http://epchan.blogspot.com/"&gt;Ernie
Chan&lt;/a&gt;, I quickly added to my reading list. What surprised me, was …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Quantitative trading is something I know almost nothing about, but is a
topic that I find interesting. Mixing computers, math and some luck to
automate trading strategies just sounds&amp;nbsp;fun.&lt;/p&gt;
&lt;p&gt;When a &lt;a href="http://twitter.com/jpburton"&gt;friend&lt;/a&gt; recommended &lt;a href="http://www.amazon.com/Quantitative-Trading-Build-Algorithmic-Business/dp/0470284889/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1273500859&amp;amp;sr=8-1"&gt;Quantitative Trading&lt;/a&gt; by &lt;a href="http://epchan.blogspot.com/"&gt;Ernie
Chan&lt;/a&gt;, I quickly added to my reading list. What surprised me, was that
I finished the book within 24&amp;nbsp;hours!&lt;/p&gt;
&lt;p&gt;There are a few things to like about this book. Ernie&amp;#8217;s writing style is
very no-nonsense. Every chapter has a logical flow to it, and he is
crystal clear about the material he is&amp;nbsp;introducing.&lt;/p&gt;
&lt;p&gt;The other part I really like is the practical examples. Theory is
introduced only as a way of getting to a measurable outcome. Examples
are provided in both Excel and Matlab, and could easily be extended to
other automation&amp;nbsp;approaches.&lt;/p&gt;
&lt;p&gt;Ernie also covers a the wider business aspects of getting setup as an
independent quant, such as the trade-offs between retail and proprietary
accounts, risk management, finding, tuning and backtesting trading&amp;nbsp;strategies.&lt;/p&gt;
&lt;p&gt;At each point, references are made to further material on each topic,
such as books, research papers, online articles and implementations. I
certainly felt that I had enough knowledge to go about setting up a
simple quantitative trading&amp;nbsp;business.&lt;/p&gt;
&lt;p&gt;Even though I do not intend to actually set up as a trader, I found it
very informative to understand the industry better. It is something I
may come back to in a few&amp;nbsp;years.&lt;/p&gt;</content><category term="business"></category></entry><entry><title>Agile projects – From Concept to Product Backlog</title><link href="https://pseudofish.com/agile-projects-from-concept-to-product-backlog.html" rel="alternate"></link><published>2010-04-30T18:13:00+02:00</published><updated>2010-04-30T18:13:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-04-30:/agile-projects-from-concept-to-product-backlog.html</id><summary type="html">&lt;p&gt;Agile is something that I&amp;#8217;ve previously found to work very well with
in-house R&amp;amp;D projects, and rather more challenging when negotiating
projects with&amp;nbsp;customers.&lt;/p&gt;
&lt;p&gt;The challenge is getting from the sales cycle through to the agile
development iterations, be they sprints or&amp;nbsp;otherwise.&lt;/p&gt;
&lt;p&gt;By using an agile process …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Agile is something that I&amp;#8217;ve previously found to work very well with
in-house R&amp;amp;D projects, and rather more challenging when negotiating
projects with&amp;nbsp;customers.&lt;/p&gt;
&lt;p&gt;The challenge is getting from the sales cycle through to the agile
development iterations, be they sprints or&amp;nbsp;otherwise.&lt;/p&gt;
&lt;p&gt;By using an agile process, the advantage is that many smart people have
been here before. Some of the knowledge is locked up in consultancy
houses, while some of it is&amp;nbsp;shared.&lt;/p&gt;
&lt;p&gt;Gerard Meszaros has a &lt;a href="http://www.infoq.com/presentations/From-Concept-to-Product-Backlog"&gt;good presentation&lt;/a&gt; highlighting some of the
challenges and what often gets missed. The slides are available
&lt;a href="http://concept2backlog.gerardm.com/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The section on adding more time into the &lt;em&gt;Product Planning&lt;/em&gt; phase fits
well with how customers often see projects. By providing scope at the
feature level, it allows boundaries to be placed around time and&amp;nbsp;money.&lt;/p&gt;
&lt;p&gt;This is certainly an area of agile that I would like to understand&amp;nbsp;more.&lt;/p&gt;</content><category term="agile"></category></entry><entry><title>Machinist, AuthLogic &amp; Cucumber</title><link href="https://pseudofish.com/machinist-authlogic-cucumber.html" rel="alternate"></link><published>2010-03-21T02:40:00+01:00</published><updated>2010-03-21T02:40:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-03-21:/machinist-authlogic-cucumber.html</id><summary type="html">&lt;p&gt;For a Rails app, I wanted to define rules about authentication using
&lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; and a bit of &lt;span class="caps"&gt;BDD&lt;/span&gt;. This went well, until I added in
&lt;a href="http://github.com/ianwhite/pickle"&gt;Pickle&lt;/a&gt;, &lt;a href="http://github.com/notahat/machinist"&gt;Machinist&lt;/a&gt;, and &lt;a href="http://github.com/binarylogic/authlogic"&gt;AuthLogic&lt;/a&gt;; a few too many new things
at&amp;nbsp;once.&lt;/p&gt;
&lt;p&gt;I first ran afoul of defining users and then password confirmation. This
is …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For a Rails app, I wanted to define rules about authentication using
&lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; and a bit of &lt;span class="caps"&gt;BDD&lt;/span&gt;. This went well, until I added in
&lt;a href="http://github.com/ianwhite/pickle"&gt;Pickle&lt;/a&gt;, &lt;a href="http://github.com/notahat/machinist"&gt;Machinist&lt;/a&gt;, and &lt;a href="http://github.com/binarylogic/authlogic"&gt;AuthLogic&lt;/a&gt;; a few too many new things
at&amp;nbsp;once.&lt;/p&gt;
&lt;p&gt;I first ran afoul of defining users and then password confirmation. This
is easy to fix, as a Machinist spec is Ruby&amp;nbsp;code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="no"&gt;Sham&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Faker&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Internet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;Sham&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Faker&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Internet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blueprint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;secret&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;password_confirmation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I also created a named admin&amp;nbsp;user:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blueprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Sham&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; -admin-&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I can then add some user specific step definitions for Cucumber using
&lt;a href="http://wiki.github.com/brynary/webrat/"&gt;Webrat&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;admin_user&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="vi"&gt;@admin_user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/login&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;fill_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Username&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;fill_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Password&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;:with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;click_button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Log in&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;logout&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/logout&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sr"&gt;/^I am a logged in user$/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sr"&gt;/^I am logged in as an admin$/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;begin&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;rescue&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;save_and_open_page&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;raise&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sr"&gt;/^I am not logged in$/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;logout&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The three behaviors I want to define are for guest, non-admin and admin
users. This gives me the&amp;nbsp;following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Can&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t see new entry as guest&lt;/span&gt;
&lt;span class="s1"&gt;  Given I am not logged in&lt;/span&gt;
&lt;span class="s1"&gt;  When I go to path &amp;quot;/entries&amp;quot;&lt;/span&gt;
&lt;span class="s1"&gt;  Then I should not see &amp;quot;New entry&amp;quot;&lt;/span&gt;

&lt;span class="s1"&gt;Scenario: Can&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;non&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/entries&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;New entry&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Can&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;an&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/entries&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;New entry&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In writing this blog post, I cleaned up some of the features and found a
few missing authentication paths. One further thing to ponder is what
happens when someone visits your controller directly. I think you should
also add defined behaviours for this, such&amp;nbsp;as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Can&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;non&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;via&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/entries/new&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A big thank you to &lt;a href="http://railscasts.com/"&gt;Railscasts&lt;/a&gt;. Ryan has done several casts on
&lt;a href="http://railscasts.com/episodes?search=cucumber"&gt;Cucumber&lt;/a&gt; and &lt;a href="http://railscasts.com/episodes?search=AuthLogic"&gt;AuthLogic&lt;/a&gt; that really helped get me&amp;nbsp;started.&lt;/p&gt;
&lt;p&gt;If you need to sham a Paperclip file with Machinist, check out &lt;a href="http://openmonkey.com/articles/2009/07/machinist-paperclip"&gt;Tim
Riley&amp;#8217;s blog&lt;/a&gt;. &lt;a href="http://itsignals.cascadia.com.au/?p=30/"&gt;This article&lt;/a&gt;was also useful, although I found after
I had most things&amp;nbsp;working.&lt;/p&gt;</content><category term="programming"></category></entry><entry><title>Strawberry Swing - Amazing Hand Drawn Animation</title><link href="https://pseudofish.com/strawberry-swing-amazing-hand-drawn-animation.html" rel="alternate"></link><published>2010-03-09T16:40:00+01:00</published><updated>2010-03-09T16:40:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-03-09:/strawberry-swing-amazing-hand-drawn-animation.html</id><content type="html">&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/BYtk1Z0UUuE&amp;amp;rel=0&amp;amp;color1=0xb1b1b1&amp;amp;color2=0xcfcfcf&amp;amp;hl=en_US&amp;amp;feature=player_embedded&amp;amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/BYtk1Z0UUuE&amp;amp;rel=0&amp;amp;color1=0xb1b1b1&amp;amp;color2=0xcfcfcf&amp;amp;hl=en_US&amp;amp;feature=player_embedded&amp;amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;p&gt;Read the interview with &lt;a href="http://motionographer.com/theater/shynola-coldplay-strawberry-swing/"&gt;Shynola’s Chris Harding&lt;/a&gt; for some hints on
how they made&amp;nbsp;it.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Learning Ruby on Rails</title><link href="https://pseudofish.com/learning-ruby-on-rails.html" rel="alternate"></link><published>2010-02-15T13:30:00+01:00</published><updated>2010-02-15T13:30:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-02-15:/learning-ruby-on-rails.html</id><summary type="html">&lt;p&gt;This year, my technology goal is to learn Ruby on&amp;nbsp;Rails.&lt;/p&gt;
&lt;p&gt;I often try to learn new programming languages, averaging around one a
year. Sometimes it is a matter of coming back to a language I haven&amp;#8217;t
used in a while, other times it is learning a new&amp;nbsp;framework …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This year, my technology goal is to learn Ruby on&amp;nbsp;Rails.&lt;/p&gt;
&lt;p&gt;I often try to learn new programming languages, averaging around one a
year. Sometimes it is a matter of coming back to a language I haven&amp;#8217;t
used in a while, other times it is learning a new&amp;nbsp;framework.&lt;/p&gt;
&lt;p&gt;After using Ruby for some scripting last year, I decided that Rails was
a good choice to learn as a framework this year. Two things convinced&amp;nbsp;me.&lt;/p&gt;
&lt;p&gt;Firstly, lots of web innovation appears to arise from the Ruby
community. &lt;a href="http://railscasts.com/episodes?search=cucumber"&gt;Cucumber&lt;/a&gt; is one that has particularly caught my&amp;nbsp;interest.&lt;/p&gt;
&lt;p&gt;Secondly is &lt;a href="http://heroku.com/"&gt;Heroku&lt;/a&gt;. This is simply an awesome way to bootstrap a
project. No mess, no fuss, code - deploy - repeat. It means I can launch
an early version of the app with minimal investment of time or&amp;nbsp;funding.&lt;/p&gt;
&lt;p&gt;To dive in deep on a platform like Rails, I&amp;#8217;ve taken a few&amp;nbsp;steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Books&lt;/strong&gt; – Admittedly still on order, I&amp;#8217;m investing in some Rails
    books, as I find books provide broader coverage of topics than blogs&amp;nbsp;alone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blogs&lt;/strong&gt; – My &lt;span class="caps"&gt;RSS&lt;/span&gt; reader is being filled out with Ruby and Rails
    blogs. I subscribed to 20 odd to start with and will curate them
    over&amp;nbsp;time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Podcasts&lt;/strong&gt; – The Rails community is served by a number of great
    podcasts and &lt;a href="http://railscasts.com/"&gt;screencasts&lt;/a&gt;. &lt;a href="http://railscasts.com/"&gt;Railscasts&lt;/a&gt; is a great
    entry point and I added others for broader&amp;nbsp;coverage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Twitter&lt;/strong&gt; – Where I find bloggers or people that are influential
    in the Rails community, I add them to my Twitter &lt;a href="http://twitter.com/gmwils/ruby"&gt;list&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Friends&lt;/strong&gt; – To start the process, I also asked a few friends who
    were Rails experts for suggestions of where to start. Pete put
    together quite a &lt;a href="http://blog.notahat.com/posts/40"&gt;good list&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools&lt;/strong&gt; – Installing Rails was a good start. I also added TextMate
    to my tool collection. There are some nice features that may cause
    me to make changes to my .vimrc one&amp;nbsp;day.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of that is the easy part. The next step is to actually write a bunch
of Rails code. So far I&amp;#8217;m tinkering with example code. However, I do
have a larger project in mind which should provide the incentive to
carry through. Details on that are for a later&amp;nbsp;date.&lt;/p&gt;
&lt;p&gt;If there are sources of good Rails info that you can recommend, please
let me know either in comments, &lt;a href="http://twitter.com/gmwils"&gt;Twitter&lt;/a&gt; or&amp;nbsp;email.&lt;/p&gt;</content><category term="programming"></category></entry><entry><title>Top 10 Photos of 2009</title><link href="https://pseudofish.com/top-10-photos-of-2009.html" rel="alternate"></link><published>2010-01-24T16:20:00+01:00</published><updated>2010-01-24T16:20:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2010-01-24:/top-10-photos-of-2009.html</id><summary type="html">&lt;p&gt;With much consideration, this is my selection of my top 10 photos from
2009. (in no particular&amp;nbsp;order)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3451714283/in/set-72157622820342473"&gt;Canoes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Canoes" src="http://farm4.static.flickr.com/3644/3451714283_a6c35bcf2c_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/4084397069/in/set-72157622820342473/"&gt;Conspiracies&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Conspiracies – Fi &amp;amp; Benn Wedding" src="http://farm4.static.flickr.com/3059/4084397069_a949a7d40e_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/4034941248/in/set-72157622820342473/"&gt;Tulip Festival –&amp;nbsp;1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Tulip Festival – 1" src="http://farm3.static.flickr.com/2471/4034941248_2093dc96a0_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3417231719/in/set-72157622820342473/"&gt;Karen &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;&amp;nbsp;Phil&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Karen &amp;amp; Phil" src="http://farm4.static.flickr.com/3416/3417231719_5b11e6cd5a_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/4146401689/in/set-72157622820342473/"&gt;Issabella&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Issabella" src="http://farm3.static.flickr.com/2551/4146401689_5506a36d2f_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3762032574/in/set-72157622820342473/"&gt;Cupcakes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Cupcakes" src="http://farm3.static.flickr.com/2615/3762032574_258fa28aa4_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3286185687/in/set-72157622820342473/"&gt;Banff, Alberta,&amp;nbsp;Canada&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Banff, Alberta, Canada" src="http://farm4.static.flickr.com/3274/3286185687_ee9f7b6009_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3824998303/in/set-72157622820342473/"&gt;Waiting&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Waiting" src="http://farm3.static.flickr.com/2604/3824998303_a641090806_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/4299713026/in/set-72157622820342473/"&gt;Parisian&amp;nbsp;Light&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Parisian Light" src="http://farm3.static.flickr.com/2724/4299713026_45b4df12d0_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/4157139687/in/set-72157622820342473/"&gt;Gingerbread Christmas&amp;nbsp;Trees&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Gingerbread Christmas Trees" src="http://farm3.static.flickr.com/2498/4157139687_7fb14f9db4_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;The larger selection of my favourite images from 2009 is on &lt;a href="http://www.flickr.com/photos/gmwils/sets/72157622820342473/"&gt;Flickr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For comparison …&lt;/p&gt;</summary><content type="html">&lt;p&gt;With much consideration, this is my selection of my top 10 photos from
2009. (in no particular&amp;nbsp;order)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3451714283/in/set-72157622820342473"&gt;Canoes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Canoes" src="http://farm4.static.flickr.com/3644/3451714283_a6c35bcf2c_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/4084397069/in/set-72157622820342473/"&gt;Conspiracies&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Conspiracies – Fi &amp;amp; Benn Wedding" src="http://farm4.static.flickr.com/3059/4084397069_a949a7d40e_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/4034941248/in/set-72157622820342473/"&gt;Tulip Festival –&amp;nbsp;1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Tulip Festival – 1" src="http://farm3.static.flickr.com/2471/4034941248_2093dc96a0_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3417231719/in/set-72157622820342473/"&gt;Karen &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;&amp;nbsp;Phil&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Karen &amp;amp; Phil" src="http://farm4.static.flickr.com/3416/3417231719_5b11e6cd5a_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/4146401689/in/set-72157622820342473/"&gt;Issabella&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Issabella" src="http://farm3.static.flickr.com/2551/4146401689_5506a36d2f_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3762032574/in/set-72157622820342473/"&gt;Cupcakes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Cupcakes" src="http://farm3.static.flickr.com/2615/3762032574_258fa28aa4_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3286185687/in/set-72157622820342473/"&gt;Banff, Alberta,&amp;nbsp;Canada&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Banff, Alberta, Canada" src="http://farm4.static.flickr.com/3274/3286185687_ee9f7b6009_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3824998303/in/set-72157622820342473/"&gt;Waiting&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Waiting" src="http://farm3.static.flickr.com/2604/3824998303_a641090806_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/4299713026/in/set-72157622820342473/"&gt;Parisian&amp;nbsp;Light&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Parisian Light" src="http://farm3.static.flickr.com/2724/4299713026_45b4df12d0_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/4157139687/in/set-72157622820342473/"&gt;Gingerbread Christmas&amp;nbsp;Trees&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Gingerbread Christmas Trees" src="http://farm3.static.flickr.com/2498/4157139687_7fb14f9db4_m.jpg"&gt;][]&lt;/p&gt;
&lt;p&gt;The larger selection of my favourite images from 2009 is on &lt;a href="http://www.flickr.com/photos/gmwils/sets/72157622820342473/"&gt;Flickr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For comparison, last year&amp;#8217;s photos are &lt;a href="http://pseudofish.com/blog/2009/01/27/top-10-photos-of-2008/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Canoes" src="http://farm4.static.flickr.com/3644/3451714283_a6c35bcf2c_m.jpg"&gt;]: http://www.flickr.com/photos/gmwils/3451714283/
    &amp;#8220;Canoes by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Conspiracies – Fi &amp;amp; Benn Wedding" src="http://farm4.static.flickr.com/3059/4084397069_a949a7d40e_m.jpg"&gt;]: http://www.flickr.com/photos/gmwils/4084397069/
    &amp;#8220;Conspiracies – Fi &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Benn Wedding by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Tulip Festival – 1" src="http://farm3.static.flickr.com/2471/4034941248_2093dc96a0_m.jpg"&gt;]: http://www.flickr.com/photos/gmwils/4034941248/
    &amp;#8220;Tulip Festival – 1 by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Karen &amp;amp; Phil" src="http://farm4.static.flickr.com/3416/3417231719_5b11e6cd5a_m.jpg"&gt;]: http://www.flickr.com/photos/gmwils/3417231719/
    &amp;#8220;Karen &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Phil by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Issabella" src="http://farm3.static.flickr.com/2551/4146401689_5506a36d2f_m.jpg"&gt;]: http://www.flickr.com/photos/gmwils/4146401689/
    &amp;#8220;Issabella by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Cupcakes" src="http://farm3.static.flickr.com/2615/3762032574_258fa28aa4_m.jpg"&gt;]: http://www.flickr.com/photos/gmwils/3762032574/
    &amp;#8220;Cupcakes by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Banff, Alberta, Canada" src="http://farm4.static.flickr.com/3274/3286185687_ee9f7b6009_m.jpg"&gt;]: http://www.flickr.com/photos/gmwils/3286185687/
    &amp;#8220;Banff, Alberta, Canada by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Waiting" src="http://farm3.static.flickr.com/2604/3824998303_a641090806_m.jpg"&gt;]: http://www.flickr.com/photos/gmwils/3824998303/
    &amp;#8220;Waiting by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Parisian Light" src="http://farm3.static.flickr.com/2724/4299713026_45b4df12d0_m.jpg"&gt;]: http://www.flickr.com/photos/gmwils/4299713026/
    &amp;#8220;Parisian Light by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="Gingerbread Christmas Trees" src="http://farm3.static.flickr.com/2498/4157139687_7fb14f9db4_m.jpg"&gt;]: http://www.flickr.com/photos/gmwils/4157139687/
    &amp;#8220;Gingerbread Christmas Trees by gmwils, on&amp;nbsp;Flickr&amp;#8221;&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Online Training with Lynda.com</title><link href="https://pseudofish.com/online-training-with-lyndacom.html" rel="alternate"></link><published>2009-09-07T16:41:00+02:00</published><updated>2009-09-07T16:41:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-09-07:/online-training-with-lyndacom.html</id><summary type="html">&lt;p&gt;With my &lt;span class="caps"&gt;CS4&lt;/span&gt; registration, Adobe gave me one month of a &lt;a href="http://www.lynda.com/"&gt;Lynda.com&lt;/a&gt;
subscription. I didn&amp;#8217;t think this would be useful, and was expecting to
learn a few things. Turns out, it&amp;#8217;s been immensely&amp;nbsp;useful.&lt;/p&gt;
&lt;p&gt;I recommend trying it for a month. My current plan is to buy …&lt;/p&gt;</summary><content type="html">&lt;p&gt;With my &lt;span class="caps"&gt;CS4&lt;/span&gt; registration, Adobe gave me one month of a &lt;a href="http://www.lynda.com/"&gt;Lynda.com&lt;/a&gt;
subscription. I didn&amp;#8217;t think this would be useful, and was expecting to
learn a few things. Turns out, it&amp;#8217;s been immensely&amp;nbsp;useful.&lt;/p&gt;
&lt;p&gt;I recommend trying it for a month. My current plan is to buy a month
subscription one every year or so. Or maybe every six&amp;nbsp;months.&lt;/p&gt;
&lt;p&gt;I consider myself reasonably effective with Photoshop and the digital
darkroom, yet still learnt many new processes and techniques for
producing a completed photograph. The following courses were interesting
or&amp;nbsp;inspirational:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.lynda.com/home/DisplayCourse.aspx?lpk2=605"&gt;Douglas Kirkland: Creative&amp;nbsp;Inspiration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.lynda.com/home/DisplayCourse.aspx?lpk2=46312"&gt;Photoshop &lt;span class="caps"&gt;CS4&lt;/span&gt; Retouching: Fashion Photography&amp;nbsp;Projects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.lynda.com/home/DisplayCourse.aspx?lpk2=600"&gt;Beyond Skin: Going Deeper with Photoshop &lt;span class="caps"&gt;CS3&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also updated a few other Adobe applications, such as InDesign and
learnt some Flash basics&amp;nbsp;too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.lynda.com/home/DisplayCourse.aspx?lpk2=46818"&gt;Designing a Magazine Layout Hands-On&amp;nbsp;Workshop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.lynda.com/home/DisplayCourse.aspx?lpk2=47760"&gt;InDesign &lt;span class="caps"&gt;CS4&lt;/span&gt;: 10 Habits of Highly Effective&amp;nbsp;Pros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.lynda.com/home/DisplayCourse.aspx?lpk2=660"&gt;Flash &lt;span class="caps"&gt;CS4&lt;/span&gt; Professional Essential&amp;nbsp;Training&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are other online video learning sites, such as &lt;a href="http://www.kelbytraining.com/"&gt;Kelby Training&lt;/a&gt;,
that are also worth a look. The important bit is to keep updating your
skills and improving your&amp;nbsp;workflow.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Two New Blogs</title><link href="https://pseudofish.com/two-new-blogs.html" rel="alternate"></link><published>2009-07-23T22:07:00+02:00</published><updated>2009-07-23T22:07:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-07-23:/two-new-blogs.html</id><summary type="html">&lt;p&gt;M &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; I are starting a food blog here: &lt;a href="http://dreamingofwinter.blogspot.com/"&gt;Dreaming of Winter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After spending the start of this year doing lots of wonderful cooking
and shooting a bunch of photos to go with it, turning the passion into a
blog made lots of&amp;nbsp;sense.&lt;/p&gt;
&lt;p&gt;The theme is based on our mutual …&lt;/p&gt;</summary><content type="html">&lt;p&gt;M &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; I are starting a food blog here: &lt;a href="http://dreamingofwinter.blogspot.com/"&gt;Dreaming of Winter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After spending the start of this year doing lots of wonderful cooking
and shooting a bunch of photos to go with it, turning the passion into a
blog made lots of&amp;nbsp;sense.&lt;/p&gt;
&lt;p&gt;The theme is based on our mutual love of winter. Hearty winter soups,
rich roast meats and delightful desserts. There may be some lighter
summer fare, but don&amp;#8217;t count on&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;I also started another &lt;a href="http://gmwils.blogspot.com/"&gt;photography blog&lt;/a&gt; where I intend to post about
recent shoots, something I&amp;#8217;ve avoided going into too much detail with on
this&amp;nbsp;blog.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>The Man in the High Castle</title><link href="https://pseudofish.com/the-man-in-the-high-castle.html" rel="alternate"></link><published>2009-06-28T16:02:00+02:00</published><updated>2009-06-28T16:02:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-06-28:/the-man-in-the-high-castle.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;Dilemma of civilized man; body mobilized, but danger&amp;nbsp;obscure&lt;/p&gt;
&lt;p&gt;&lt;small&gt; - page 161&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While on holidays I finished Phillip K Dick&amp;#8217;s book, &lt;a href="http://www.amazon.com/exec/obidos/asin/0141186674/ref=nosim/pseudofish-20"&gt;The Man in the High
Castle&lt;/a&gt;, a story of how the world might look if the Allies lost the
war. Like all great science fiction, this is a biting …&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;Dilemma of civilized man; body mobilized, but danger&amp;nbsp;obscure&lt;/p&gt;
&lt;p&gt;&lt;small&gt; - page 161&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While on holidays I finished Phillip K Dick&amp;#8217;s book, &lt;a href="http://www.amazon.com/exec/obidos/asin/0141186674/ref=nosim/pseudofish-20"&gt;The Man in the High
Castle&lt;/a&gt;, a story of how the world might look if the Allies lost the
war. Like all great science fiction, this is a biting commentary on our
own culture. Well worth a&amp;nbsp;read.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>External Accessories on iPhone 3.0</title><link href="https://pseudofish.com/external-accessories-on-iphone-30.html" rel="alternate"></link><published>2009-06-19T19:54:00+02:00</published><updated>2009-06-19T19:54:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-06-19:/external-accessories-on-iphone-30.html</id><summary type="html">&lt;p&gt;My initial reaction to the &lt;a href="http://developer.apple.com/iphone/program/sdk/accessories.html"&gt;teasers&lt;/a&gt; for 3.0 was excitement. My
understanding of the opening up of the accessory port to developers
would allow for fun innovation. I was&amp;nbsp;wrong.&lt;/p&gt;
&lt;p&gt;The dream I had was to be able to connect my iPhone, via &lt;span class="caps"&gt;USB&lt;/span&gt;, to my
camera(s). This …&lt;/p&gt;</summary><content type="html">&lt;p&gt;My initial reaction to the &lt;a href="http://developer.apple.com/iphone/program/sdk/accessories.html"&gt;teasers&lt;/a&gt; for 3.0 was excitement. My
understanding of the opening up of the accessory port to developers
would allow for fun innovation. I was&amp;nbsp;wrong.&lt;/p&gt;
&lt;p&gt;The dream I had was to be able to connect my iPhone, via &lt;span class="caps"&gt;USB&lt;/span&gt;, to my
camera(s). This would allow my phone to act as a remote control, and as
an external screen for photos &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; video. The &lt;a href="http://www.gphoto.org/"&gt;gPhoto&lt;/a&gt; libraries looked
like they could provide a starting&amp;nbsp;point.&lt;/p&gt;
&lt;p&gt;What is actually provided doesn&amp;#8217;t allow for straight &lt;span class="caps"&gt;USB&lt;/span&gt;&amp;nbsp;connectivity.&lt;/p&gt;
&lt;p&gt;The External Accessory support requires a validated accessory, with
appropriate hardware protocols, to work. You also need to be a member of
two programs, iPhone Developer and the &lt;a href="http://developer.apple.com/ipod/index.html"&gt;Made for iPod program&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I can&amp;#8217;t see Canon or Nikon releasing cameras with iPod dock connectors
or&amp;nbsp;protocols.&lt;/p&gt;
&lt;p&gt;This doesn&amp;#8217;t leave many options. One is to build a hardware device that
is &lt;span class="caps"&gt;USB&lt;/span&gt; in one end and a custom protocol out the other. This gets tricky
fast as the hardware device needs to figure out the camera support. And
I really liked the idea of a simple cable connection being all that is&amp;nbsp;required.&lt;/p&gt;
&lt;p&gt;The second option still has some merit: WiFi. There are a few downsides.
Firstly, you need a camera that supports WiFi or an expensive adaptor.
This limits the audience for the app. Secondly, you need a wireless
network available and to also manage pairing between your iPhone and
your camera. This starts to be more equipment than&amp;nbsp;desirable.&lt;/p&gt;
&lt;p&gt;If you have a laptop lying around, onOne software &lt;a href="http://www.ononesoftware.com/blog/2009/05/15/iphone-app-from-onone/"&gt;released&lt;/a&gt; such an
&lt;a href="http://www.ononesoftware.com/detail.php?prodLine_id=38"&gt;iPhone app&lt;/a&gt;.&lt;/p&gt;</content><category term="apple"></category></entry><entry><title>Life in the 21st Century</title><link href="https://pseudofish.com/life-in-the-21st-century.html" rel="alternate"></link><published>2009-06-02T09:29:00+02:00</published><updated>2009-06-02T09:29:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-06-02:/life-in-the-21st-century.html</id><summary type="html">&lt;ul&gt;
&lt;li&gt;On the flight, I get to watch lectures on iPhone development from
    &lt;a href="http://arstechnica.com/apple/news/2009/04/stanford-iphone-developer-course-available-free-via-itunes-u.ars"&gt;Stanford&lt;/a&gt;, along with talks from a &lt;a href="http://www.ted.com/talks"&gt;conference&lt;/a&gt; in&amp;nbsp;California.&lt;/li&gt;
&lt;li&gt;Catch up with family and friends in Singapore, as a result of
    sharing my location on&amp;nbsp;Facebook.&lt;/li&gt;
&lt;li&gt;Photos I took of &lt;a href="http://www.flickr.com/photos/gmwils/tags/singapore"&gt;Singapore&lt;/a&gt; are instantly shared with other
    friends and …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;On the flight, I get to watch lectures on iPhone development from
    &lt;a href="http://arstechnica.com/apple/news/2009/04/stanford-iphone-developer-course-available-free-via-itunes-u.ars"&gt;Stanford&lt;/a&gt;, along with talks from a &lt;a href="http://www.ted.com/talks"&gt;conference&lt;/a&gt; in&amp;nbsp;California.&lt;/li&gt;
&lt;li&gt;Catch up with family and friends in Singapore, as a result of
    sharing my location on&amp;nbsp;Facebook.&lt;/li&gt;
&lt;li&gt;Photos I took of &lt;a href="http://www.flickr.com/photos/gmwils/tags/singapore"&gt;Singapore&lt;/a&gt; are instantly shared with other
    friends and family around the&amp;nbsp;world.&lt;/li&gt;
&lt;li&gt;I keep in touch with my girlfriend back home using free telephony
    via the internet (thanks&amp;nbsp;Skype).&lt;/li&gt;
&lt;li&gt;A friend at work recommends a book to me, and I order it from
    America to arrive at my Melbourne office, along with some other
    recommended books to&amp;nbsp;read.&lt;/li&gt;
&lt;li&gt;Reviews, freely published on the internet, guide me through a tricky
    lens purchase. Global warranty allows me to haggle in Singapore&amp;#8217;s
    Chinatown for a lower price than back&amp;nbsp;home.&lt;/li&gt;
&lt;li&gt;Hear about a new album by &lt;a href="http://www.fatfreddysdrop.com/index.php"&gt;Fat Freddy&amp;#8217;s Drop&lt;/a&gt;, a New Zealand band,
    on Twitter on my phone, purchase the album and instantly(ish)
    download via wireless&amp;nbsp;internet&lt;/li&gt;
&lt;li&gt;My camera (5D2) gets updated with new features today, via the
    internet, making it more video&amp;nbsp;capable.&lt;/li&gt;
&lt;li&gt;Subscriptions via &lt;a href="http://www.newsgator.com/individuals/netnewswireiphone/default.aspx"&gt;NetNewsWire&lt;/a&gt; and &lt;a href="http://www.atebits.com/tweetie-iphone/"&gt;Tweetie&lt;/a&gt; on the iPhone
    guide me through the bankruptcy intricacies as two 20th Century car
    companies fall&amp;nbsp;apart.&lt;/li&gt;
&lt;li&gt;I can share this with you, as publishing is freely&amp;nbsp;available.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thinking back only a few decades, most of this would seem science
fiction. I&amp;#8217;m looking forward to the next&amp;nbsp;few!&lt;/p&gt;
&lt;p&gt;ps. I still hold out hope for personal flying devices in my&amp;nbsp;lifetime.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>Twitter &amp; The Modern News Cycle</title><link href="https://pseudofish.com/twitter-the-modern-news-cycle.html" rel="alternate"></link><published>2009-05-19T08:50:00+02:00</published><updated>2009-05-19T08:50:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-05-19:/twitter-the-modern-news-cycle.html</id><summary type="html">&lt;p&gt;Yesterday, Monday 18th May, an earthquake measuring 5 on the richter
scale struck&amp;nbsp;California.&lt;/p&gt;
&lt;p&gt;I first heard about the quake from John Grey (@[jg_rat][]), the editor
of &lt;a href="http://www.news.com.au/couriermail/"&gt;couriermail.com.au&lt;/a&gt;. He posted the&amp;nbsp;following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;RT&lt;/span&gt; @bartman6: &lt;span class="caps"&gt;FLASH&lt;/span&gt;: Quake hits &lt;span class="caps"&gt;LA&lt;/span&gt; &lt;a href="http://bit.ly/jtA6M"&gt;http://bit.ly/jtA6M&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Courier Mail site published a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Yesterday, Monday 18th May, an earthquake measuring 5 on the richter
scale struck&amp;nbsp;California.&lt;/p&gt;
&lt;p&gt;I first heard about the quake from John Grey (@[jg_rat][]), the editor
of &lt;a href="http://www.news.com.au/couriermail/"&gt;couriermail.com.au&lt;/a&gt;. He posted the&amp;nbsp;following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;RT&lt;/span&gt; @bartman6: &lt;span class="caps"&gt;FLASH&lt;/span&gt;: Quake hits &lt;span class="caps"&gt;LA&lt;/span&gt; &lt;a href="http://bit.ly/jtA6M"&gt;http://bit.ly/jtA6M&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Courier Mail site published a small teaser with a few paragraphs of
text and a map of the areas affected. The site also included a reference
to this content at the top of their&amp;nbsp;homepage.&lt;/p&gt;
&lt;p&gt;As the story unfolded, the article was expanded to include more&amp;nbsp;information.&lt;/p&gt;
&lt;p&gt;The article was the first mention in Australian press of the earthquake.
John&amp;#8217;s team beat the other major news sites, including &lt;span class="caps"&gt;ABC&lt;/span&gt;.com.au,
&lt;span class="caps"&gt;SMH&lt;/span&gt;.com.au and even their parent site, news.com.au. At the time of
posting, even &lt;span class="caps"&gt;CNN&lt;/span&gt; had not updated their site with news of the&amp;nbsp;earthquake.&lt;/p&gt;
&lt;p&gt;I asked John why his team got the news out so&amp;nbsp;early:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;@[jg_rat][]: @&lt;a href="http://twitter.com/gmwils"&gt;gmwils&lt;/a&gt; The answer is Twitter. And a fast, smart,
connected news&amp;nbsp;team.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;LA&lt;/span&gt; Times was also quick to respond to the story. Their first post, in
addition to their own copy, included a link to a Twitter search for
&lt;em&gt;earthquake&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Twitter is adding a lot of value to the breaking news gathering and
publishing&amp;nbsp;processes.&lt;/p&gt;</content><category term="media"></category></entry><entry><title>High Tea in Sorrento</title><link href="https://pseudofish.com/high-tea-in-sorrento.html" rel="alternate"></link><published>2009-05-18T09:24:00+02:00</published><updated>2009-05-18T09:24:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-05-18:/high-tea-in-sorrento.html</id><summary type="html">&lt;p&gt;After being overly busy with work, a weekend in Melbourne allowed for
relaxing travel. Michelle and I went down to Sorrento to visit a friend
for high&amp;nbsp;tea.&lt;/p&gt;
&lt;p&gt;Lots and lots of cakes, some beautiful sandwiches and then more cakes.
All mixed in with a wide variety of tea. Conversations …&lt;/p&gt;</summary><content type="html">&lt;p&gt;After being overly busy with work, a weekend in Melbourne allowed for
relaxing travel. Michelle and I went down to Sorrento to visit a friend
for high&amp;nbsp;tea.&lt;/p&gt;
&lt;p&gt;Lots and lots of cakes, some beautiful sandwiches and then more cakes.
All mixed in with a wide variety of tea. Conversations were diverse and
drifted between deep and&amp;nbsp;idyllic.&lt;/p&gt;
&lt;p&gt;A wonderful way to&amp;nbsp;unwind.&lt;/p&gt;
&lt;p&gt;It was also a good opportunity to play more with my new camera. I am
really pleased with the results. The colors out of camera are more
inspiring than from my old&amp;nbsp;camera.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/97356053@N00/3540728256" title="View'Cakes' on Flickr.com"&gt;&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
 &lt;img
  src="http://farm4.static.flickr.com/3393/3540728256_9a063b196a.jpg"
   alt="Cakes" border="0" width="400" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/97356053@N00/3540728234"
 title="View 'High Tea, Sorrento' on Flickr.com"&gt;&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;img
 src="http://farm3.static.flickr.com/2021/3540728234_dacd7655a2.jpg"
 alt="High Tea, Sorrento" border="0" width="400" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/97356053@N00/3540728224"
 title="View 'Point King Beach' on Flickr.com"&gt;&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;img
 src="http://farm3.static.flickr.com/2417/3540728224_4bd7d30d45.jpg"
 alt="Point King Beach" border="0" width="400"  /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are a few more on my &lt;a href="http://www.flickr.com/photos/gmwils/"&gt;Flickr&lt;/a&gt;&amp;nbsp;page.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>A New Theory on Brains</title><link href="https://pseudofish.com/a-new-theory-on-brains.html" rel="alternate"></link><published>2009-05-09T16:02:00+02:00</published><updated>2009-05-09T16:02:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-05-09:/a-new-theory-on-brains.html</id><summary type="html">&lt;p&gt;&lt;a href="http://www.ted.com/talks/view/id/125"&gt;Jeff Hawkins&lt;/a&gt;&amp;#8216; &lt;span class="caps"&gt;TED&lt;/span&gt; talk on brain science got me thinking. He posits
that the act of thinking is about predicting, rather than about
behavior. This model of reasoning makes sense, and will simplify the
computer modeling of&amp;nbsp;thought.&lt;/p&gt;
&lt;p&gt;What I find interesting is that our own brian is not great …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.ted.com/talks/view/id/125"&gt;Jeff Hawkins&lt;/a&gt;&amp;#8216; &lt;span class="caps"&gt;TED&lt;/span&gt; talk on brain science got me thinking. He posits
that the act of thinking is about predicting, rather than about
behavior. This model of reasoning makes sense, and will simplify the
computer modeling of&amp;nbsp;thought.&lt;/p&gt;
&lt;p&gt;What I find interesting is that our own brian is not great at
prediction. We are making progress in the study of our own biases and
their impact on prediction and decision&amp;nbsp;making.&lt;/p&gt;
&lt;p&gt;For discussion, &amp;#8220;&lt;a href="http://www.amazon.com/exec/obidos/asin/0521284147/ref=nosim/pseudofish-20"&gt;Judgement under Uncertainty&lt;/a&gt;&amp;#8221; is a must read; a
collection of papers on our known&amp;nbsp;biases.&lt;/p&gt;
&lt;p&gt;When we computerize this model, do we introduce the same or similar
biases? Does it make sense in silicon, to recreate our own limitations?
What happens when we invent a new form of consciousness with bias&amp;nbsp;removed?&lt;/p&gt;
&lt;p&gt;Jeff&amp;#8217;s talk is &lt;a href="http://www.ted.com/talks/view/id/125"&gt;here&lt;/a&gt;:&lt;/p&gt;
&lt;object width="446" height="326"&gt;&lt;param name="movie" value="http://video.ted.com/assets/player/swf/EmbedPlayer.swf"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;param name="bgColor" value="#ffffff"&gt;&lt;/param&gt;
&lt;param name="flashvars" value="vu=http://video.ted.com/talks/embed/JeffHawkins_2003-embed_high.flv&amp;amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/JeffHawkins-2003.embed_thumbnail.jpg&amp;amp;vw=432&amp;amp;vh=240&amp;amp;ap=0&amp;amp;ti=125"&gt;&lt;/param&gt;&lt;embed src="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" pluginspace="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="transparent" bgcolor="#ffffff" width="446" height="326" allowfullscreen="true" flashvars="vu=http://video.ted.com/talks/embed/JeffHawkins_2003-embed_high.flv&amp;amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/JeffHawkins-2003.embed_thumbnail.jpg&amp;amp;vw=432&amp;amp;vh=240&amp;amp;ap=0&amp;amp;ti=125"&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;p&gt;ps. &lt;a href="http://www.ted.com/index.php/talks"&gt;&lt;span class="caps"&gt;TED&lt;/span&gt; talks&lt;/a&gt; are a great way to pass time on&amp;nbsp;flights.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>An Experience Economy</title><link href="https://pseudofish.com/an-experience-economy.html" rel="alternate"></link><published>2009-03-30T18:00:00+02:00</published><updated>2009-03-30T18:00:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-03-30:/an-experience-economy.html</id><summary type="html">&lt;p&gt;Joseph Pine&amp;#8217;s &lt;a href="http://www.ted.com/index.php/talks/joseph_pine_on_what_consumers_want.html"&gt;talk&lt;/a&gt; at &lt;span class="caps"&gt;TED&lt;/span&gt; really has me&amp;nbsp;thinking.&lt;/p&gt;
&lt;p&gt;This is a table outlining the difference between the types of economic
output, using the example of&amp;nbsp;coffee.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Economic Output&lt;/th&gt;
&lt;th&gt;Business Imperative&lt;/th&gt;
&lt;th&gt;Consumer Sensitivity&lt;/th&gt;
&lt;th&gt;Coffee Example&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Experience&lt;/td&gt;
&lt;td&gt;Render&lt;/td&gt;
&lt;td&gt;Authenticity&lt;/td&gt;
&lt;td&gt;$5.00 per cup (*Starbucks*)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;td&gt;Improve&lt;/td&gt;
&lt;td&gt;Quality&lt;/td&gt;
&lt;td&gt;$1.00 per …&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary><content type="html">&lt;p&gt;Joseph Pine&amp;#8217;s &lt;a href="http://www.ted.com/index.php/talks/joseph_pine_on_what_consumers_want.html"&gt;talk&lt;/a&gt; at &lt;span class="caps"&gt;TED&lt;/span&gt; really has me&amp;nbsp;thinking.&lt;/p&gt;
&lt;p&gt;This is a table outlining the difference between the types of economic
output, using the example of&amp;nbsp;coffee.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Economic Output&lt;/th&gt;
&lt;th&gt;Business Imperative&lt;/th&gt;
&lt;th&gt;Consumer Sensitivity&lt;/th&gt;
&lt;th&gt;Coffee Example&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Experience&lt;/td&gt;
&lt;td&gt;Render&lt;/td&gt;
&lt;td&gt;Authenticity&lt;/td&gt;
&lt;td&gt;$5.00 per cup (*Starbucks*)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;td&gt;Improve&lt;/td&gt;
&lt;td&gt;Quality&lt;/td&gt;
&lt;td&gt;$1.00 per cup (*coffee shop*)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Goods&lt;/td&gt;
&lt;td&gt;Control&lt;/td&gt;
&lt;td&gt;Costs&lt;/td&gt;
&lt;td&gt;$0.10 per cup (*supermarket*)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commodity&lt;/td&gt;
&lt;td&gt;Supply&lt;/td&gt;
&lt;td&gt;Availability&lt;/td&gt;
&lt;td&gt;$0.02 per cup (*coffee beans*)&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;The drive to software-as-a-service makes the software industry jump to
service. It takes Apple to move it to an experience. Disney is another
example of experience based&amp;nbsp;economics.&lt;/p&gt;
&lt;p&gt;I like this framework for thinking about what business I am working in.
The trick will be to figure out how move up the ladder to render an
authentic&amp;nbsp;experience.&lt;/p&gt;
&lt;p&gt;His &lt;a href="http://www.amazon.com/exec/obidos/asin/0875848192/ref=nosim/pseudofish-20"&gt;book&lt;/a&gt; is now on my to-read&amp;nbsp;list.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>50 Years of Style</title><link href="https://pseudofish.com/50-years-of-style.html" rel="alternate"></link><published>2009-03-25T08:17:00+01:00</published><updated>2009-03-25T08:17:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-03-25:/50-years-of-style.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;Strunk and White&amp;#8217;s The Elements of Style&amp;#8221; has sold more than 10
million copies since its initial publication in April&amp;nbsp;1959.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="http://www.newsday.com/news/local/wire/newyork/ny-bc-ny--goldenstrunkampwhit0320mar20,0,4092190.story"&gt;Newsday&lt;/a&gt; highlights the 50&lt;sup&gt;th&lt;/sup&gt; anniversary of the classic text on
English grammar and writing&amp;nbsp;style.&lt;/p&gt;
&lt;p&gt;This is &lt;em&gt;the&lt;/em&gt; book on the&amp;nbsp;subject.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The best book of writing …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;Strunk and White&amp;#8217;s The Elements of Style&amp;#8221; has sold more than 10
million copies since its initial publication in April&amp;nbsp;1959.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="http://www.newsday.com/news/local/wire/newyork/ny-bc-ny--goldenstrunkampwhit0320mar20,0,4092190.story"&gt;Newsday&lt;/a&gt; highlights the 50&lt;sup&gt;th&lt;/sup&gt; anniversary of the classic text on
English grammar and writing&amp;nbsp;style.&lt;/p&gt;
&lt;p&gt;This is &lt;em&gt;the&lt;/em&gt; book on the&amp;nbsp;subject.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The best book of writing advice I’ve ever read. I read it
cover-to-cover about once a&amp;nbsp;year.&lt;/p&gt;
&lt;p&gt;&lt;small&gt; – &lt;a href="http://daringfireball.net/linked/2009/03/23/strunk-and-white"&gt;John Gruber&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I considered offering my copy out for loan. However, I would not be
happy without a copy in my possession. It is a &lt;a href="http://amazon.com/exec/obidos/asin/0205632645/ref=nosim/pseudofish-20"&gt;small book&lt;/a&gt;, and you
owe yourself an &lt;a href="http://amazon.com/exec/obidos/asin/020530902X/ref=nosim/pseudofish-20"&gt;edition&lt;/a&gt; of&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;It saddens me that writing style seems a fading art. This book is not
read&amp;nbsp;enough.&lt;/p&gt;</content><category term="design"></category></entry><entry><title>Orbis Ring Flash for Events</title><link href="https://pseudofish.com/orbis-ring-flash-for-events.html" rel="alternate"></link><published>2009-03-03T22:18:00+01:00</published><updated>2009-03-03T22:18:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-03-03:/orbis-ring-flash-for-events.html</id><summary type="html">&lt;p&gt;The &lt;a href="http://www.orbisflash.com/"&gt;Orbis Ring flash&lt;/a&gt; is a low budget option for using portable
strobes to power a ring flash. There are two big advantages to the
Orbis: light &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; cheap. That said, the build quality is very solid and
more than I was&amp;nbsp;expecting.&lt;/p&gt;
&lt;p&gt;I decided to try mine out at a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The &lt;a href="http://www.orbisflash.com/"&gt;Orbis Ring flash&lt;/a&gt; is a low budget option for using portable
strobes to power a ring flash. There are two big advantages to the
Orbis: light &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; cheap. That said, the build quality is very solid and
more than I was&amp;nbsp;expecting.&lt;/p&gt;
&lt;p&gt;I decided to try mine out at a friend&amp;#8217;s housewarming. This was the&amp;nbsp;result:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/97356053@N00/3325692416" title="View 'Housewarming' on Flickr.com"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
![Housewarming][]

&lt;/div&gt;
&lt;p&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To shoot with, it was a breeze. My &lt;span class="caps"&gt;SB&lt;/span&gt;-24 mounted snug in the adaptor. An
old sync cord linked my 5D2 to the flash and I was away. The results
were&amp;nbsp;impressive.&lt;/p&gt;
&lt;p&gt;For shooting an event, such as a party or a wedding, the ring flash
gives a nice fall off of light without too much in the way of
highlights. For candid portraits, it was simply&amp;nbsp;wow.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m looking forward to trying it out in a more staged environment. There
are a few lighting options I&amp;#8217;d like to try, such as using it for fill or
using it from&amp;nbsp;off-axis.&lt;/p&gt;
&lt;p&gt;The Orbis team has put a few videos on &lt;a href="http://www.youtube.com/watch?v=dUA7keRbNT4"&gt;YouTube&lt;/a&gt;, and there is a group
of &lt;a href="http://www.flickr.com/groups/orbisringflash/pool/"&gt;Flickr&lt;/a&gt; showing what people are doing with&amp;nbsp;it.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Gestalt Theory &amp; Photography</title><link href="https://pseudofish.com/gestalt-theory-photography.html" rel="alternate"></link><published>2009-02-24T19:28:00+01:00</published><updated>2009-02-24T19:28:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-02-24:/gestalt-theory-photography.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;The Gestalt effect refers to the form-forming capability of our senses
(the word Gestalt in German literally means &amp;#8220;shape&amp;#8221; or &amp;#8220;figure&amp;#8221;),
particularly with respect to the visual recognition of figures and
whole forms instead of just a collection of simple lines and&amp;nbsp;curves.&lt;/p&gt;
&lt;p&gt;&lt;small&gt;from &lt;a href="http://en.wikipedia.org/wiki/Gestalt_psychology"&gt;Wikipedia&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Basically, a bunch of psychologists …&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;The Gestalt effect refers to the form-forming capability of our senses
(the word Gestalt in German literally means &amp;#8220;shape&amp;#8221; or &amp;#8220;figure&amp;#8221;),
particularly with respect to the visual recognition of figures and
whole forms instead of just a collection of simple lines and&amp;nbsp;curves.&lt;/p&gt;
&lt;p&gt;&lt;small&gt;from &lt;a href="http://en.wikipedia.org/wiki/Gestalt_psychology"&gt;Wikipedia&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Basically, a bunch of psychologists spent lots of research to figure out
how we view images and derive meaning from&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;Turns out, this research is very useful for thinking about photography.
Jeff Curto put together two podcasts explaining the&amp;nbsp;connections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go With the Gestalt (&lt;a href="http://www.cameraposition.com/archives/180"&gt;part 1&lt;/a&gt;, &lt;a href="http://www.cameraposition.com/archives/187"&gt;part 2&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The four main visual ideas to add meaning to your photos&amp;nbsp;are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Closure&lt;/li&gt;
&lt;li&gt;Continuance&lt;/li&gt;
&lt;li&gt;Similarity&lt;/li&gt;
&lt;li&gt;Proximity&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reading the &lt;a href="http://en.wikipedia.org/wiki/Gestalt_psychology"&gt;wikipedia article&lt;/a&gt; with a view to photographic
composition can help open up some visual opportunities. &lt;a href="http://www.cameraposition.com/"&gt;Jeff&amp;#8217;s
podcast&lt;/a&gt; is very useful for thinking about the creative side of&amp;nbsp;photography.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Photo Editing Workflow</title><link href="https://pseudofish.com/photo-editing-workflow.html" rel="alternate"></link><published>2009-02-19T15:52:00+01:00</published><updated>2009-02-19T15:52:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-02-19:/photo-editing-workflow.html</id><summary type="html">&lt;p&gt;Pressing the shutter on the camera is the simple bit. Once the photo is
taken there are a large number of options around workflow. This is my
current&amp;nbsp;process.&lt;/p&gt;
&lt;h4&gt;Transferring the&amp;nbsp;Photos&lt;/h4&gt;
&lt;p&gt;The obvious way to get photos from the camera to the computer is via &lt;span class="caps"&gt;USB&lt;/span&gt;
cable. I don …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Pressing the shutter on the camera is the simple bit. Once the photo is
taken there are a large number of options around workflow. This is my
current&amp;nbsp;process.&lt;/p&gt;
&lt;h4&gt;Transferring the&amp;nbsp;Photos&lt;/h4&gt;
&lt;p&gt;The obvious way to get photos from the camera to the computer is via &lt;span class="caps"&gt;USB&lt;/span&gt;
cable. I don&amp;#8217;t like doing this for a few reasons. One is that it drains
the camera battery, the other is that it can be&amp;nbsp;slow.&lt;/p&gt;
&lt;p&gt;I use a card reader to mount the memory card on my computer and then use
&lt;a href="http://www.adobe.com/products/photoshoplightroom/"&gt;Lightroom&lt;/a&gt; (&lt;span class="caps"&gt;LR&lt;/span&gt;) to copy the files&amp;nbsp;across.&lt;/p&gt;
&lt;p&gt;Depending on my camera or the shoot, I may assign a pre-set on import.
This matters more on my Point &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Shoot (P&amp;amp;S) cameras, as the default
processing is fairly bleh. Adobe&amp;#8217;s defaults for my Canon SLRs is usually
pretty good as a starting point. I also have a metadata pre-set that
assigns various contact &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; copyright information to the image. I add
additional metadata, such as keywords, as I&amp;nbsp;import.&lt;/p&gt;
&lt;p&gt;With folder structures, I&amp;#8217;ve been through a few. My current layout is to
place everything from one &amp;#8220;Event&amp;#8221; into a date prefixed folder. This can
be assigned in the Import dialog. For example, if I went to Banff, it
would be &amp;#8220;2009-02-15 Banff&amp;#8221;. The date indicates when I off loaded the
photos, so the folder can span multiple days for an event. I can also
have multiple folders per&amp;nbsp;day.&lt;/p&gt;
&lt;p&gt;The advantage of this layout is that if I stop using Lightroom, I still
have a vague chance of figuring out where a particular photo is. When it
was just by date, there wasn&amp;#8217;t enough information in the file system to
be&amp;nbsp;helpful.&lt;/p&gt;
&lt;h4&gt;Initial&amp;nbsp;Edit&lt;/h4&gt;
&lt;p&gt;After &lt;span class="caps"&gt;LR&lt;/span&gt; has built the previews, and sometimes while it is, I will do an
initial edit. At this point, I&amp;#8217;m viewing the photos for the first time
on a computer. If I consider an image acceptable, it gets one star (&amp;#8216;1&amp;#8217;
on the keyboard). If a photo is beyond usable, such as bad focus or lens
cap on, I&amp;#8217;ll set it as a reject (&amp;#8216;x&amp;#8217;). Depending on the shoot, I&amp;#8217;ll
delete the rejects from disk (Ctrl-Backspace / Cmd-Delete).
Occasionally, if I really like an image on first viewing, I will give it
two stars&amp;nbsp;(&amp;#8216;2&amp;#8217;).&lt;/p&gt;
&lt;p&gt;From this point, I use the filtering in &lt;span class="caps"&gt;LR&lt;/span&gt; so that I will only see 1
star photos or higher&amp;nbsp;ratings.&lt;/p&gt;
&lt;h4&gt;Second&amp;nbsp;Edit&lt;/h4&gt;
&lt;p&gt;The second time through, I&amp;#8217;m more critical of the photos. Each much be
interesting in its own right to receive two stars (&amp;#8216;2&amp;#8217;). While I&amp;#8217;m
viewing the photos I&amp;#8217;m in the Loupe view (&amp;#8216;e&amp;#8217;). I typically have &lt;span class="caps"&gt;LR&lt;/span&gt;
maximized (&amp;#8216;f&amp;#8217;) and with the sidebars hidden (Shift-Tab). I also darken
the user interface. I set the dim level in preferences to 50% and use
this to hide most of the &lt;span class="caps"&gt;UI&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;When there are several images that are very similar, such as in a
portrait or sports shoot, I&amp;#8217;ll use the compare (&amp;#8216;c&amp;#8217;) mode so I can see
images side by side. Pressing the up key while in this mode promotes an
image to the left, while allowing you to continue through. Promoted
images will get two&amp;nbsp;stars.&lt;/p&gt;
&lt;p&gt;If I want to see more than two images at once, I use the survey view
(&amp;#8216;n&amp;#8217;) after selecting the images from the grid&amp;nbsp;(&amp;#8216;g&amp;#8217;).&lt;/p&gt;
&lt;h4&gt;Post&amp;nbsp;Production&lt;/h4&gt;
&lt;p&gt;After filtering down to two star images, I start to consider candidates
for post-production. It is very rare that I&amp;#8217;ll output an image without
some level of post. Much of this I now do in &lt;span class="caps"&gt;LR&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Still with dim set, I switch to the Develop module (&amp;#8216;d&amp;#8217;) and start
applying corrections in &lt;span class="caps"&gt;LR&lt;/span&gt;. This can include things like fine tuning
white balance, exposure, saturation, sharpening or applying subtle
vignettes. Much of this I save in pre-sets, so can apply with a single
click and preview before applying. Sometimes I use pre-sets from &lt;a href="http://www.lightroomkillertips.com/archives/presets/"&gt;other
sites&lt;/a&gt; to try out different&amp;nbsp;looks.&lt;/p&gt;
&lt;p&gt;If I have a series of similar photos, I&amp;#8217;ll use &lt;span class="caps"&gt;LR&lt;/span&gt; to adjust one of them
and then sync the settings to the other photos in the shoot. I do this
often to set the white balance from a gray card (or by eye) and then
make it the same for all the&amp;nbsp;shots.&lt;/p&gt;
&lt;p&gt;With the adjustment brush and gradient filter in &lt;span class="caps"&gt;LR2&lt;/span&gt;, there is much less
time I spend in Photoshop (&lt;span class="caps"&gt;PS&lt;/span&gt;). There are still some images that I&amp;#8217;ll
finish in &lt;span class="caps"&gt;PS&lt;/span&gt;. These are typically composites, or portraits that require
more retouching. I use &lt;span class="caps"&gt;LR&lt;/span&gt; to manage the &lt;span class="caps"&gt;PS&lt;/span&gt; files and to group the &lt;span class="caps"&gt;PS&lt;/span&gt;
file in a stack with the original&amp;nbsp;image.&lt;/p&gt;
&lt;p&gt;Once I finish in Photoshop, I&amp;#8217;ll occasionally re-adjust things further
in Lightroom. At this point, I consider the image&amp;nbsp;done.&lt;/p&gt;
&lt;h4&gt;Final Edit &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;&amp;nbsp;Presentation&lt;/h4&gt;
&lt;p&gt;Once post is complete I try to leave some time before doing a final
edit. At this point I&amp;#8217;ve spent too long with the photos and am not very
objective. I find more clarity after a night&amp;#8217;s sleep. The images that
are in my mind when I wake are often the stand out ones. Editing right
away often means that the one I spent the most time on is foremost in my
mind, and may not be the best&amp;nbsp;image.&lt;/p&gt;
&lt;p&gt;In the final edit, I&amp;#8217;ll assign three star images (&amp;#8216;3&amp;#8217;). These are ones
that I consider the best of the&amp;nbsp;shoot.&lt;/p&gt;
&lt;p&gt;If I want to group images for export to a particular destination, I&amp;#8217;ll
use one of the colour labels (&amp;#8216;6&amp;#8217;) or the Quick Collection (&amp;#8216;b&amp;#8217;) to
select them. Then I can filter based on these properties and export to
external systems or print. Flickr, Gallery or Facebook all have plug-ins
for &lt;span class="caps"&gt;LR&lt;/span&gt;, so can be configured as export pre-sets. Make sure to set the
colour space to sRGB and set the appropriate size and sharpening for the
destination. Having the destination web site re-size and (not) sharpen
results in less great&amp;nbsp;images.&lt;/p&gt;
&lt;p&gt;I also have some pre-sets for exporting with the right file format and
colour space for the print&amp;nbsp;labs.&lt;/p&gt;
&lt;p&gt;Now that I have a photo printer at home, I will often print a proof
before sending to an external lab. This allows me to see what the photo
will look like printed. It is a different experience to hold the photo
in your hands than see it on the screen, and I&amp;#8217;ll often go back to post
and make&amp;nbsp;changes.&lt;/p&gt;
&lt;h4&gt;Archival&lt;/h4&gt;
&lt;p&gt;Up until this point, the workflow has been carried out on one of my
laptops. I have two copies of the image (one on the card, one on the
computer). As I use the camera to format the cards prior to shooting,
this gives me some redundancy. However, the images need to be&amp;nbsp;archived.&lt;/p&gt;
&lt;p&gt;This is an area that I can improve. My simple strategy is to copy across
to an external &lt;span class="caps"&gt;USB&lt;/span&gt; mounted hard drive. Ideally, I should backup to a
second hard drive and/or burn to &lt;span class="caps"&gt;DVD&lt;/span&gt;.&lt;/p&gt;
&lt;h4&gt;Future&amp;nbsp;Usage&lt;/h4&gt;
&lt;p&gt;My pictures now are easy to find using Smart Collections. Any long term
projects that I&amp;#8217;m working on get specific keywords assigned and turn up
in a specific Smart Collection that searches for the keyword and a
particular star rating. I also have some collections based on &lt;a href="http://pseudofish.com/blog/2009/01/27/top-10-photos-of-2008/"&gt;year&lt;/a&gt;,
so I can see how I&amp;#8217;m&amp;nbsp;progressing.&lt;/p&gt;
&lt;p&gt;I can use search to locate images for particular projects, or select
images for trying out a new Photoshop &lt;a href="http://www.flickr.com/photos/gmwils/3256933254/"&gt;technique&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ever few months, I&amp;#8217;ll go back over my 3 star images to consider
candidates for 4 stars. The 4 star images are ones I would consider for
portfolio usage or fine art sale. To date, I have less than a handful of
5 star images. These are ones that I consider&amp;nbsp;&amp;#8216;wow&amp;#8217;.&lt;/p&gt;
&lt;p&gt;My aim is to shoot more images that make it to 5&amp;nbsp;stars.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Media 09 Conference - Summary</title><link href="https://pseudofish.com/media-09-conference-summary.html" rel="alternate"></link><published>2009-02-18T12:56:00+01:00</published><updated>2009-02-18T12:56:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-02-18:/media-09-conference-summary.html</id><summary type="html">&lt;p&gt;&lt;a href="http://www.media09.com/program.html"&gt;Media 09&lt;/a&gt; is a new media conference held in Sydney. I attended last
year&amp;#8217;s, and missed this year due to being in Canada. Fortunately, Brad
from &lt;a href="http://lagrangepoint.typepad.com/"&gt;lagrangepoint&lt;/a&gt; was there and blogged many of the&amp;nbsp;talks.&lt;/p&gt;
&lt;p&gt;Below are some of the highlights from his coverage (click through for
full&amp;nbsp;articles …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.media09.com/program.html"&gt;Media 09&lt;/a&gt; is a new media conference held in Sydney. I attended last
year&amp;#8217;s, and missed this year due to being in Canada. Fortunately, Brad
from &lt;a href="http://lagrangepoint.typepad.com/"&gt;lagrangepoint&lt;/a&gt; was there and blogged many of the&amp;nbsp;talks.&lt;/p&gt;
&lt;p&gt;Below are some of the highlights from his coverage (click through for
full&amp;nbsp;articles):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://lagrangepoint.typepad.com/lagrange/2009/02/live-from-media-09.html"&gt;Brian McCarthy&lt;/a&gt;&lt;/strong&gt;, Fairfax &lt;span class="caps"&gt;CEO&lt;/span&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In discussing the media environment, he pointed out the differences
between the &lt;span class="caps"&gt;US&lt;/span&gt; and Australia, including the greater investment in
colour printing and the more discreet geographic distribution of our
population that has protected Australian&amp;nbsp;publishers.&lt;/p&gt;
&lt;p&gt;He also reiterated his faith in content - and &lt;strong&gt;quality journalism&lt;/strong&gt; -
being the key to survival, as the company continues to &lt;strong&gt;merge its
print and online&lt;/strong&gt; offerings and diversify into new&amp;nbsp;markets&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://lagrangepoint.typepad.com/lagrange/2009/02/media-09-caroline-little.html"&gt;Caroline Little&lt;/a&gt;&lt;/strong&gt;, from The Guardian News and Media &lt;span class="caps"&gt;USA&lt;/span&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The role of the newspaper as a record of &lt;strong&gt;yesterday&amp;#8217;s news&lt;/strong&gt; has
gone, and newsrooms need to&amp;nbsp;adapt.&lt;/p&gt;
&lt;p&gt;The newspaper is now no longer the most effective means for an
advertiser to reach an audience, with the market becoming &lt;strong&gt;more
fragmented&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;She said there are four key areas - multimedia storytelling, database
journalism, reader engagement and citizen journalism. Fear of failure
must not hold proprietors&amp;nbsp;back.&lt;/p&gt;
&lt;p&gt;Understanding &lt;strong&gt;Twitter&lt;/strong&gt; and &lt;strong&gt;Facebook&lt;/strong&gt; are vital for understanding
engagement and their viral nature, and it is important to understand
how content is being distributed away from the publisher&amp;#8217;s&amp;nbsp;website.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://lagrangepoint.typepad.com/lagrange/2009/02/media-09-nic-newman.html"&gt;Nic Newman&lt;/a&gt;&lt;/strong&gt;, &lt;span class="caps"&gt;BBC&lt;/span&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Content must also be made sharable, within the boudaries of content
rights, via widgets and other portals so that content gets to where
the audience actually&amp;nbsp;is.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://lagrangepoint.typepad.com/lagrange/2009/02/media-09-ben-self.html"&gt;Ben Self&lt;/a&gt;&lt;/strong&gt;, used social media for the Obama&amp;nbsp;campaign:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There were more than 1800 videos distributed to supporters, and 50
million views of this content. 68 million Americans were reached
either online or in person throughout the campaign. More than &lt;span class="caps"&gt;US&lt;/span&gt;$770
million was raised - &lt;span class="caps"&gt;US&lt;/span&gt;$500 million raised&amp;nbsp;online.&lt;/p&gt;
&lt;p&gt;He said that having a dynamic and interesting &lt;strong&gt;email&lt;/strong&gt; program &lt;strong&gt;was
crucial&lt;/strong&gt;, with more than 13 million on the distribution list by the
end of the campaign. They also made it easier for people to
communicate themselves through the web&amp;nbsp;site.&lt;/p&gt;
&lt;p&gt;He also looked at tools to &lt;strong&gt;target&lt;/strong&gt; and organise voters
&lt;strong&gt;geographically&lt;/strong&gt;, to help get people in neighbourhoods together who
want to be part of the&amp;nbsp;campaign.
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://lagrangepoint.typepad.com/lagrange/2009/02/meg-pickard-head-of-communities-and-user-experience-at-the-guardian.html"&gt;Meg Pickard&lt;/a&gt;&lt;/strong&gt;, The Guardian Community&amp;nbsp;manager:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;We didnt make any money, but we generated an enormous amount of
&lt;strong&gt;goodwill&lt;/strong&gt;,&amp;#8221; Pickard said. &amp;#8220;We sold several hundred, but we had
seveal thousand people linking to it on &lt;strong&gt;Facebook&lt;/strong&gt;.&amp;#8221;&lt;/p&gt;
&lt;p&gt;There is a wholly trinity of &lt;strong&gt;technology, people and editorial&lt;/strong&gt;. She
also talked about the transition from casual users to connected users,
committed users and finally &lt;strong&gt;catalysts&lt;/strong&gt; - the final category being
the ones who represented less than 1 percent of the audience, but are
blogging and twittering about you, saving stories on del.ico.us and
creating pages on Facebook, that you need to find a way to engage&amp;nbsp;with.
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://lagrangepoint.typepad.com/lagrange/2009/02/media-09-richard-cardran.html"&gt;Richard Cardran&lt;/a&gt;,&lt;/strong&gt; Emmy award winner for his work in digital&amp;nbsp;media:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Cardran says we have reached a point of maturity, to the point where
if a business doesn&amp;#8217;t have strategies in business for Facebook,
MySpace or mobile, then they really should, because all it takes now
is&amp;nbsp;willpower.&lt;/p&gt;
&lt;p&gt;Cardran says you need a strategy for &lt;strong&gt;ecosystem&lt;/strong&gt; and for
&lt;strong&gt;syndication&lt;/strong&gt;, and that leads to a meta strategy. He spoke about
creating value around an object, service or presence, not the object,
service or presence&amp;nbsp;itself.&lt;/p&gt;
&lt;p&gt;End users should be allowed to design custom &lt;strong&gt;virtual newspapers and
magazines&lt;/strong&gt;, and they should be able to virally distribute their
custom publications. He says newspapers should also create
&lt;strong&gt;hyper-localised&lt;/strong&gt; applications to exploit &lt;strong&gt;local advertising
revenue&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;</content><category term="media"></category></entry><entry><title>Browser Wars Hot Up; Who Cares?</title><link href="https://pseudofish.com/browser-wars-hot-up-who-cares.html" rel="alternate"></link><published>2009-02-03T06:38:00+01:00</published><updated>2009-02-03T06:38:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-02-03:/browser-wars-hot-up-who-cares.html</id><summary type="html">&lt;p&gt;&lt;a href="http://news.cnet.com/8301-1023_3-10154447-93.html"&gt;Recent reports&lt;/a&gt; highlight Internet Explorer&amp;#8217;s drop in percentage of
internet users. Given the huge war between Mozilla and &lt;span class="caps"&gt;IE&lt;/span&gt;, it sounds
like big news, but is&amp;nbsp;it?&lt;/p&gt;
&lt;p&gt;These days I don&amp;#8217;t think browsers are as important. The innovation in
one is rapidly copied to another. The &lt;span class="caps"&gt;UI&lt;/span&gt; differences …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://news.cnet.com/8301-1023_3-10154447-93.html"&gt;Recent reports&lt;/a&gt; highlight Internet Explorer&amp;#8217;s drop in percentage of
internet users. Given the huge war between Mozilla and &lt;span class="caps"&gt;IE&lt;/span&gt;, it sounds
like big news, but is&amp;nbsp;it?&lt;/p&gt;
&lt;p&gt;These days I don&amp;#8217;t think browsers are as important. The innovation in
one is rapidly copied to another. The &lt;span class="caps"&gt;UI&lt;/span&gt; differences between Firefox,
&lt;span class="caps"&gt;IE&lt;/span&gt;, Safari and Chrome are minimal. Each of them does a good job of
rendering standards based &lt;span class="caps"&gt;HTML&lt;/span&gt;, &lt;span class="caps"&gt;CSS&lt;/span&gt; and&amp;nbsp;Javascript.&lt;/p&gt;
&lt;p&gt;Each vendor has a use for their browser. Microsoft has a component
version of &lt;span class="caps"&gt;IE&lt;/span&gt; it can embed in most of Windows. Apple has a component
version of Safari that it can use across Mac &lt;span class="caps"&gt;OS&lt;/span&gt; X and iPhone &lt;span class="caps"&gt;OS&lt;/span&gt;.
Google&amp;#8217;s browser is optimized to run Google&amp;#8217;s style of application.
Firefox is a great platform for building browsers, while also being a&amp;nbsp;browser.&lt;/p&gt;
&lt;p&gt;The important thing today is to own a destination worth browsing to. And
that is a much harder&amp;nbsp;challenge.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>Top 10 Photos of 2008</title><link href="https://pseudofish.com/top-10-photos-of-2008.html" rel="alternate"></link><published>2009-01-27T20:56:00+01:00</published><updated>2009-01-27T20:56:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-01-27:/top-10-photos-of-2008.html</id><summary type="html">&lt;p&gt;After several hours of editing, these are my top 10 from&amp;nbsp;2008.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2261853139/" title="Sunrise, Torquay by gmwils, on Flickr"&gt;Sunrise,&amp;nbsp;Torquay&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2261853139/" title="Sunrise, Torquay by gmwils, on Flickr"&gt;&lt;img alt="Sunrise, Torquay" src="http://farm3.static.flickr.com/2074/2261853139_cfdf85be9c_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2634151781/" title="Classic Portrait by gmwils, on Flickr"&gt;Classic&amp;nbsp;Portrait&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2634151781/" title="Classic Portrait by gmwils, on Flickr"&gt;&lt;img alt="Classic Portrait" src="http://farm4.static.flickr.com/3173/2634151781_9c68b8a1aa_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2237062575/" title="Winter afternoon, Saskatoon by gmwils, on Flickr"&gt;Winter&amp;nbsp;afternoon&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2237062575/" title="Winter afternoon, Saskatoon by gmwils, on Flickr"&gt;&lt;img alt="Winter afternoon, Saskatoon" src="http://farm3.static.flickr.com/2308/2237062575_4969fbbb78_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2814316742/" title="Big Air, Falls Creek by gmwils, on Flickr"&gt;Big Air, Falls&amp;nbsp;Creek&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2814316742/" title="Big Air, Falls Creek by gmwils, on Flickr"&gt;&lt;img alt="Big Air, Falls Creek" src="http://farm4.static.flickr.com/3245/2814316742_1a2242c4c1_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3107368514/" title="Great Wall at Badaling, China by gmwils, on Flickr"&gt;Great Wall at&amp;nbsp;Badaling&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3107368514/" title="Great Wall at Badaling, China by gmwils, on Flickr"&gt;&lt;img alt="Great Wall at Badaling, China" src="http://farm4.static.flickr.com/3269/3107368514_9c244d8e0e_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3055883266/" title="Maheno Wreck, Fraser Island by gmwils, on Flickr"&gt;Maheno Wreck, Fraser&amp;nbsp;Island&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3055883266/" title="Maheno Wreck, Fraser Island by gmwils, on Flickr"&gt;&lt;img alt="Maheno Wreck, Fraser Island" src="http://farm4.static.flickr.com/3197/3055883266_03b41722a2_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2980633604/" title="Creek by gmwils, on Flickr"&gt;Creek&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2980633604/" title="Creek by gmwils, on Flickr"&gt;&lt;img alt="Creek" src="http://farm4.static.flickr.com/3175/2980633604_276437832e_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2188569983/" title="Grain by gmwils, on Flickr"&gt;Grain&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2188569983/" title="Grain by gmwils, on Flickr"&gt;&lt;img alt="Grain" src="http://farm3.static.flickr.com/2385/2188569983_07be92804a_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2516276626/" title="Milton, Brisbane by gmwils, on Flickr"&gt;Milton,&amp;nbsp;Brisbane&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2516276626/" title="Milton, Brisbane by gmwils, on Flickr"&gt;&lt;img alt="Milton, Brisbane" src="http://farm3.static.flickr.com/2065/2516276626_8813aaf559_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3062092145/" title="Red Car, Parkville by gmwils, on Flickr"&gt;Red Car,&amp;nbsp;Parkville&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3062092145/" title="Red Car, Parkville by gmwils, on Flickr"&gt;&lt;img alt="Red Car, Parkville" src="http://farm4.static.flickr.com/3135/3062092145_a0f21487cf_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The candidates for my best pictures of 2008 are in &lt;a href="http://www.flickr.com/photos/gmwils/sets/72157612999484965/"&gt;this set&lt;/a&gt;; lots …&lt;/p&gt;</summary><content type="html">&lt;p&gt;After several hours of editing, these are my top 10 from&amp;nbsp;2008.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2261853139/" title="Sunrise, Torquay by gmwils, on Flickr"&gt;Sunrise,&amp;nbsp;Torquay&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2261853139/" title="Sunrise, Torquay by gmwils, on Flickr"&gt;&lt;img alt="Sunrise, Torquay" src="http://farm3.static.flickr.com/2074/2261853139_cfdf85be9c_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2634151781/" title="Classic Portrait by gmwils, on Flickr"&gt;Classic&amp;nbsp;Portrait&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2634151781/" title="Classic Portrait by gmwils, on Flickr"&gt;&lt;img alt="Classic Portrait" src="http://farm4.static.flickr.com/3173/2634151781_9c68b8a1aa_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2237062575/" title="Winter afternoon, Saskatoon by gmwils, on Flickr"&gt;Winter&amp;nbsp;afternoon&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2237062575/" title="Winter afternoon, Saskatoon by gmwils, on Flickr"&gt;&lt;img alt="Winter afternoon, Saskatoon" src="http://farm3.static.flickr.com/2308/2237062575_4969fbbb78_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2814316742/" title="Big Air, Falls Creek by gmwils, on Flickr"&gt;Big Air, Falls&amp;nbsp;Creek&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2814316742/" title="Big Air, Falls Creek by gmwils, on Flickr"&gt;&lt;img alt="Big Air, Falls Creek" src="http://farm4.static.flickr.com/3245/2814316742_1a2242c4c1_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3107368514/" title="Great Wall at Badaling, China by gmwils, on Flickr"&gt;Great Wall at&amp;nbsp;Badaling&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3107368514/" title="Great Wall at Badaling, China by gmwils, on Flickr"&gt;&lt;img alt="Great Wall at Badaling, China" src="http://farm4.static.flickr.com/3269/3107368514_9c244d8e0e_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3055883266/" title="Maheno Wreck, Fraser Island by gmwils, on Flickr"&gt;Maheno Wreck, Fraser&amp;nbsp;Island&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3055883266/" title="Maheno Wreck, Fraser Island by gmwils, on Flickr"&gt;&lt;img alt="Maheno Wreck, Fraser Island" src="http://farm4.static.flickr.com/3197/3055883266_03b41722a2_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2980633604/" title="Creek by gmwils, on Flickr"&gt;Creek&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2980633604/" title="Creek by gmwils, on Flickr"&gt;&lt;img alt="Creek" src="http://farm4.static.flickr.com/3175/2980633604_276437832e_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2188569983/" title="Grain by gmwils, on Flickr"&gt;Grain&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2188569983/" title="Grain by gmwils, on Flickr"&gt;&lt;img alt="Grain" src="http://farm3.static.flickr.com/2385/2188569983_07be92804a_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2516276626/" title="Milton, Brisbane by gmwils, on Flickr"&gt;Milton,&amp;nbsp;Brisbane&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/2516276626/" title="Milton, Brisbane by gmwils, on Flickr"&gt;&lt;img alt="Milton, Brisbane" src="http://farm3.static.flickr.com/2065/2516276626_8813aaf559_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3062092145/" title="Red Car, Parkville by gmwils, on Flickr"&gt;Red Car,&amp;nbsp;Parkville&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/gmwils/3062092145/" title="Red Car, Parkville by gmwils, on Flickr"&gt;&lt;img alt="Red Car, Parkville" src="http://farm4.static.flickr.com/3135/3062092145_a0f21487cf_m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The candidates for my best pictures of 2008 are in &lt;a href="http://www.flickr.com/photos/gmwils/sets/72157612999484965/"&gt;this set&lt;/a&gt;; lots of
depth from a photographic&amp;nbsp;year.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Published in the Age</title><link href="https://pseudofish.com/published-in-the-age.html" rel="alternate"></link><published>2009-01-22T20:51:00+01:00</published><updated>2009-01-22T20:51:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-01-22:/published-in-the-age.html</id><summary type="html">&lt;p&gt;&lt;a href="http://www.flickr.com/photos/97356053@N00/3217585642"
  title="View 'Livewire, The Age, 2009-01-22' on Flickr.com"&gt;&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;img
  src="http://farm4.static.flickr.com/3468/3217585642_d9cb780a86.jpg"
  alt="Livewire, The Age, 2009-01-22" border="0" width="350" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I was lucky and in the right place at the right time with a&amp;nbsp;camera.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.philhart.com/"&gt;Phil&lt;/a&gt; needed a portrait submitted to the Age for an article about
Astronomy. While we were down at &lt;a href="http://www.campcooinda.asn.au/"&gt;camp&lt;/a&gt; last week, I took the
opportunity to make a few of&amp;nbsp;him.&lt;/p&gt;
&lt;p&gt;We tried out a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.flickr.com/photos/97356053@N00/3217585642"
  title="View 'Livewire, The Age, 2009-01-22' on Flickr.com"&gt;&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;img
  src="http://farm4.static.flickr.com/3468/3217585642_d9cb780a86.jpg"
  alt="Livewire, The Age, 2009-01-22" border="0" width="350" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I was lucky and in the right place at the right time with a&amp;nbsp;camera.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.philhart.com/"&gt;Phil&lt;/a&gt; needed a portrait submitted to the Age for an article about
Astronomy. While we were down at &lt;a href="http://www.campcooinda.asn.au/"&gt;camp&lt;/a&gt; last week, I took the
opportunity to make a few of&amp;nbsp;him.&lt;/p&gt;
&lt;p&gt;We tried out a few styles, and the photo that ran didn&amp;#8217;t make it into my
final selects. But then I wasn&amp;#8217;t looking at the portrait purely for an
editorial&amp;nbsp;piece.&lt;/p&gt;
&lt;p&gt;This is the photo&amp;nbsp;used:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/97356053@N00/3216722321"
 title="View 'Phil Hart' on Flickr.com"&gt;&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;img
  src="http://farm4.static.flickr.com/3301/3216722321_7bb385f8e1_m.jpg"
  alt="Phil Hart" border="0" width="240" height="160" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;These are my two favorites from the&amp;nbsp;shoot:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/97356053@N00/3209643394"
 title="View 'Phil Hart' on Flickr.com"&gt;&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
 &lt;img
  src="http://farm4.static.flickr.com/3301/3209643394_79f979edbe_m.jpg"
  alt="Phil Hart" border="0" width="240" height="160" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/97356053@N00/3209643662"
title="View 'Phil Hart' on Flickr.com"&gt;&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
  &lt;img
   src="http://farm4.static.flickr.com/3456/3209643662_c4409356af_m.jpg"
   alt="Phil Hart" border="0" width="160" height="240" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/a&gt;&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Timelapsed Tents</title><link href="https://pseudofish.com/timelapsed-tents.html" rel="alternate"></link><published>2009-01-21T21:06:00+01:00</published><updated>2009-01-21T21:06:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2009-01-21:/timelapsed-tents.html</id><summary type="html">&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/llJY1nFnmz4&amp;amp;hl=en&amp;amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/llJY1nFnmz4&amp;amp;hl=en&amp;amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;p&gt;My challenge for 2009 is to become better at video production. So far
I&amp;#8217;ve spent a bunch of time learning to use Final Cut Pro, and reading up
on editing techniques. However, the best way to learn is to&amp;nbsp;try.&lt;/p&gt;
&lt;p&gt;The video above is the result of a bit …&lt;/p&gt;</summary><content type="html">&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/llJY1nFnmz4&amp;amp;hl=en&amp;amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/llJY1nFnmz4&amp;amp;hl=en&amp;amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;p&gt;My challenge for 2009 is to become better at video production. So far
I&amp;#8217;ve spent a bunch of time learning to use Final Cut Pro, and reading up
on editing techniques. However, the best way to learn is to&amp;nbsp;try.&lt;/p&gt;
&lt;p&gt;The video above is the result of a bit of an&amp;nbsp;experiment.&lt;/p&gt;
&lt;p&gt;For &lt;a href="http://www.campcooinda.asn.an/"&gt;camp&lt;/a&gt;, we pitched 9 large A-Frame tents. This seemed a good event
to try out some timelapse&amp;nbsp;photography.&lt;/p&gt;
&lt;p&gt;Three still cameras were used to capture the footage. My Ricoh &lt;span class="caps"&gt;GX100&lt;/span&gt; was
set to take the wide angle at a rate of two frames per minute. This was
let run for the entire event. &lt;a href="http://www.philhart.com/"&gt;Phil&lt;/a&gt; took the close up video with a
Canon G9. It captures time lapse video straight to Quicktime. I also
used my &lt;span class="caps"&gt;DSLR&lt;/span&gt; to capture some&amp;nbsp;stills.&lt;/p&gt;
&lt;p&gt;The wide angle stills were processed in Lightroom to improve the colour,
add a vignette and crop slightly. Exported to &lt;span class="caps"&gt;JPG&lt;/span&gt; and imported into a
&lt;span class="caps"&gt;FCP&lt;/span&gt; with 2s per frame. The G9 footage was cut in over the top, along
with the still&amp;nbsp;frames.&lt;/p&gt;
&lt;p&gt;To tie it together, transitions were added to each cut and motion added
to the stills to create a sense of movement. The final image includes a
text overlay created using Title 3D. Compressor then rendered the final
output, that YouTube then&amp;nbsp;crushes.&lt;/p&gt;
&lt;p&gt;&lt;a href="/illustrations/2009/tenttimeline.jpg"&gt;&lt;img alt="image" src="/illustrations/2009/tenttimeline.jpg"&gt;&lt;/a&gt;&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Beijing Restaurants ( 北京饭馆 )</title><link href="https://pseudofish.com/beijing-restaurants-bei-jing-fan-guan.html" rel="alternate"></link><published>2008-12-14T23:25:00+01:00</published><updated>2008-12-14T23:25:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-12-14:/beijing-restaurants-bei-jing-fan-guan.html</id><summary type="html">&lt;p&gt;While in Beijing, I did a lot of dining out. There were some great
experiences and one questionable&amp;nbsp;one.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.bestfoodinchina.net/node/101"&gt;Huajia Yiyuan Restaurant&lt;/a&gt; - frequented by Cathay Pacific flight
    crews when in Beijing, this restaurant is close to the top of my
    list for Beijing. With a wide variety of food on …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;While in Beijing, I did a lot of dining out. There were some great
experiences and one questionable&amp;nbsp;one.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.bestfoodinchina.net/node/101"&gt;Huajia Yiyuan Restaurant&lt;/a&gt; - frequented by Cathay Pacific flight
    crews when in Beijing, this restaurant is close to the top of my
    list for Beijing. With a wide variety of food on the menu and a tea
    list longer than most wine lists, there is much to like. The
    atmosphere is wonderful, nestled in the midst of Ghost Street,
    without succumbing to the surrounding&amp;nbsp;commercialism.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://travel.nytimes.com/travel/guides/asia/china/beijing/restaurant-detail.html?vid=1194723840271"&gt;Da Dong&lt;/a&gt; - Modern way to experience Peking Duck, Beijing style.
    The mini &amp;#8220;hamburger&amp;#8221; variant was interesting to try, with its heavy
    garlic. The classic duck was classic. Extensive menu allows for a
    wide array of choice for accompanying dishes, beautifully
    photographed. I considered enquiring to buy a copy of their menu,
    given the print quality, typography and photo budget; it bordered on
    food&amp;nbsp;porn.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.quanjude.com.cn/e_about.html"&gt;Quanjude&lt;/a&gt; - Classic roast duck. The most famous in Beijing and
    for a good reason. Established over 130 years ago, this is where
    government officials go to eat, with many private rooms available,
    if you book in advance. We had a set menu that included just about
    every part of the duck. Duck hearts were the big surprise in how
    tasty they were. Duck feet were edible, but not quite to my taste.
    The roast duck itself was classic and&amp;nbsp;delicious.&lt;/li&gt;
&lt;li&gt;Sichuan Restaurant - if you&amp;#8217;re staying near the Hard Rock Cafe in
    Beijing, keep walking. There is a great Sichuan style restaurant
    just around the corner from it. They have English menus (with
    pictures), but not much English for the staff. Very good food
    considering the lack of price. The staff were fascinated by Super
    Monkey Ball, which was playing on my iPhone while I waited for my
    meal. Not sure of the name of it though, so may be tricky to&amp;nbsp;find.&lt;/li&gt;
&lt;li&gt;Local food - there were many local food places I dined at that had
    wonderful food. Requires a bit of enthusiasm to try some of it, but
    many more hits than misses. Don&amp;#8217;t turn your nose up at something
    without at least trying it first. You may find something you really&amp;nbsp;love.&lt;/li&gt;
&lt;li&gt;Hard Rock Cafe - ok, so I caved on my last night in Beijing. After
    many hours walking around the Great Wall, I was not feeling
    adventurous. I regret this decision. I thought a burger would cure
    my woes. The burger was average and overpriced. The service was
    classic American style; not a good thing. I was interrupted three
    times while trying to eat, each time to ask if my meal was okay.
    Certainly wasn&amp;#8217;t improved by hassling me about&amp;nbsp;it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#8217;m open to suggestions for future visits. I&amp;#8217;m not staying in Ningbo
long enough to write too much about it, although I did stumble across a
place with traditional local food that struck me as quite strange; they
did not serve tea! The food here is quite good from the little I&amp;#8217;ve
tried. I am not holding out much expectation for Shenzhen; hopefully I
will be&amp;nbsp;surprised.&lt;/p&gt;</content><category term="chinese"></category></entry><entry><title>Learning Chinese</title><link href="https://pseudofish.com/learning-chinese.html" rel="alternate"></link><published>2008-12-12T02:18:00+01:00</published><updated>2008-12-12T02:18:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-12-12:/learning-chinese.html</id><summary type="html">&lt;p&gt;After almost two years of study, there are many different approaches
I&amp;#8217;ve tried for learning Chinese. These are the ones that stuck the most.
I&amp;#8217;m putting them into order of terms effectiveness, however I do get
excited about ones I most recently discovered. My aim is to be …&lt;/p&gt;</summary><content type="html">&lt;p&gt;After almost two years of study, there are many different approaches
I&amp;#8217;ve tried for learning Chinese. These are the ones that stuck the most.
I&amp;#8217;m putting them into order of terms effectiveness, however I do get
excited about ones I most recently discovered. My aim is to be able to
speak Chinese via &lt;span class="caps"&gt;MSN&lt;/span&gt; with friends. This is going to take&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;I am biased towards the iPhone for software. Access to a dictionary, to
learn on the go, is&amp;nbsp;invaluable.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://home.vicnet.net.au/~accs/MELTMETBL.html"&gt;&lt;span class="caps"&gt;ACCS&lt;/span&gt;&lt;/a&gt; - I recommend attending class. It helps for motivation. It
    helps to learn with a teacher. It helps to be encouraged by peer
    pressure if you fall behind your classmates. &lt;span class="caps"&gt;ACCS&lt;/span&gt; helps me learn to
    speak and to learn how to read &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; write characters. Try and find a
    class in your local&amp;nbsp;area.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://chinesepod.com/"&gt;ChinesePod&lt;/a&gt; - useful for both their regular podcast and forums.
    The best podcast on the internet, although now mostly hidden behind
    a paid wall. I&amp;#8217;m yet to consider paying as am still working through
    their back catalogue. &lt;a href="http://56minus1.com/2008/11/chats-jenny-zhu/"&gt;Jenny&lt;/a&gt; and Ken provide a lively dynamic
    that make learning&amp;nbsp;fun.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.dianhuadictionary.com/"&gt;Dianhua Dictionary&lt;/a&gt; - comprehensive Chinese/English dictionary on
    a phone for free. Hard not to like. Combined with native input
    methods and can search using pinyin or by drawing characters. I also
    use a hard copy Oxford Chinese/English dictionary on occasion, but
    it mostly stays on the&amp;nbsp;shelf.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphone.chbeer.de/iVocabulary/iVocabulary.html"&gt;iVocabulary&lt;/a&gt; / ProVoc - flash card system with a Mac based
    desktop app(free) and an iPhone client. Creating paper flash cards
    was never going to happen. Putting this on the computer helped.
    Getting it to my phone means I actually&amp;nbsp;study.&lt;/li&gt;
&lt;li&gt;Visiting China - at the moment I feel quite swamped by almost
    everything being in Chinese. That said, two weeks in China is doing
    great things for my Chinese. Hopefully, it provides motivation to
    continue. Spending time without a translator helps&amp;nbsp;too.&lt;/li&gt;
&lt;li&gt;Chinese movies - watch many, in Mandarin. If you&amp;#8217;re enthusiastic,
    watch with Mandarin subtitles instead of English. You understand
    less of the film, but learn more of the&amp;nbsp;language.&lt;/li&gt;
&lt;li&gt;Chinese books / newspapers / etc - Aim to read something written by
    native speakers that doesn&amp;#8217;t live in a text book or language course.
    I find the educational material can be&amp;nbsp;contrived.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.italki.com/"&gt;italki.com&lt;/a&gt; - social networking site for meeting people to
    exchange language with. Still not fully sure of the usefulness, but
    seems to be an easy way to meet people who want to learn English and
    are native Chinese speakers. There are other sites that offer
    similar&amp;nbsp;features.&lt;/li&gt;
&lt;li&gt;Lonely Planet - phrase book is helpful, iPhone app is useful if
    you&amp;#8217;re stranded or forget the basics. To be honest though, I rarely
    refer to it&amp;nbsp;anymore.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/gmwils"&gt;Twitter&lt;/a&gt; - Adding people from China is helpful, but hasn&amp;#8217;t led to
    as much learning of language as I had thought. That said, I&amp;#8217;m
    learning a heap about culture and current events. Try following
    &lt;a href="http://twitter.com/YoukuBuzz"&gt;@YoukuBuzz&lt;/a&gt; for video&amp;nbsp;content.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note: I just found some &lt;a href="http://www.core.org.cn/OcwWeb/Foreign-Languages-and-Literatures/index.htm"&gt;&lt;span class="caps"&gt;MIT&lt;/span&gt; courses&lt;/a&gt; that are published online that
include a few with Chinese. One even comes with a &lt;a href="http://www.core.org.cn/OcwWeb/Foreign-Languages-and-Literatures/21F-101Spring-2006/Readings/index.htm#Lesson"&gt;free text book&lt;/a&gt; in
&lt;span class="caps"&gt;PDF&lt;/span&gt; form. I have not spent much time with it, but it looks&amp;nbsp;promising.&lt;/p&gt;
&lt;p&gt;Some of the resources will be useful for whichever language you are
learning. If you aren&amp;#8217;t learning a language other than your own, ask
yourself why not? Learning a language will teach you a new culture and
broaden your horizons. Worth the time. My challenge is not getting
confused between English, German and&amp;nbsp;Chinese.&lt;/p&gt;
&lt;p&gt;See&amp;nbsp;also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://pseudofish.com/blog/2007/11/20/china-road/"&gt;China&amp;nbsp;Road&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pseudofish.com/blog/2008/03/25/language-bots-in-im/"&gt;Language Bots in &lt;span class="caps"&gt;IM&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pseudofish.com/blog/2008/05/01/programming-fonts-revisited/"&gt;Programming Fonts&amp;nbsp;Revisited&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="chinese"></category></entry><entry><title>Off to China</title><link href="https://pseudofish.com/off-to-china.html" rel="alternate"></link><published>2008-12-08T08:35:00+01:00</published><updated>2008-12-08T08:35:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-12-08:/off-to-china.html</id><summary type="html">&lt;p&gt;I start a two week trip through China today; mostly for business, and
mostly not sharable in public (pesky NDAs again). However, I will post a
bunch of things as I&amp;nbsp;go.&lt;/p&gt;
&lt;p&gt;We start in Beijing for a week. Since I was here two years ago, things
have changed. Arriving …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I start a two week trip through China today; mostly for business, and
mostly not sharable in public (pesky NDAs again). However, I will post a
bunch of things as I&amp;nbsp;go.&lt;/p&gt;
&lt;p&gt;We start in Beijing for a week. Since I was here two years ago, things
have changed. Arriving last night into the new terminal at the airport
was an experience of space and light. Two things missing during the
construction going on during 2006. The new structure is vast and
impressive, however does invite comparison to Hong Kong and Singapore
airports. Not a bad thing, given those are two of my&amp;nbsp;favourite.&lt;/p&gt;
&lt;p&gt;After meeting with a colleague from &lt;span class="caps"&gt;HK&lt;/span&gt;, we grabbed a late dinner at a &lt;span class="caps"&gt;HK&lt;/span&gt;
diner near the hotel. It felt good to taste &lt;span class="caps"&gt;HK&lt;/span&gt; food again, especially
milk tea. Not really a China experience, but it reminds me of many trips
to Hong Kong visiting friends and working with &lt;span class="caps"&gt;SCMP&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The flight over was long, but not too long. As always, Cathay makes for
a pleasant flight. Dragon Air was a bit more chaotic to Beijing, but was
at least on time unlike anything Qantas can do of&amp;nbsp;late.&lt;/p&gt;
&lt;p&gt;Trying to stay awake, I lasted through four&amp;nbsp;films:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.imdb.com/title/tt0364970/"&gt;Babylon &lt;span class="caps"&gt;AD&lt;/span&gt;&lt;/a&gt; - Good distopian future action romp. Nice sci-fi
    trappings, and good byplay between the characters. More than I was
    expecting from the trailer. Vin Diesel &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Michelle Yeoh work well
    together. Reminded me a bit of a flashier Children of&amp;nbsp;Men.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.imdb.com/title/tt0910970/"&gt;Wall-E&lt;/a&gt; - Unhappy watching this film. I missed it at the cinemas
    and now regret it. Absolutely brilliant. Classic Pixar and well
    worth a watch. Amazing what happens when film makers take risks. A
    feature film with limited dialogue? Yes, it absolutely&amp;nbsp;works.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.imdb.com/title/tt1287843/"&gt;Kung Fu Hip Hop&lt;/a&gt; - Good filler on a plane, but not that great by
    &lt;span class="caps"&gt;HK&lt;/span&gt; film standards. An odd mix of the recent American dance type
    movies with a classic &lt;span class="caps"&gt;HK&lt;/span&gt; style kung fu&amp;nbsp;movie.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.imdb.com/title/tt0811138/"&gt;The Love Guru&lt;/a&gt; - Mike Myers has done better. Felt a little too
    much like his previous films, which made for entertaining filler but
    no real brilliance. Go watch an old Austin Powers movie&amp;nbsp;instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Internet connects work, with obvious firewall fun. Might be good to skip
Facebook for a week. My Australian mobile also works, although I&amp;#8217;ll get
a local &lt;span class="caps"&gt;SIM&lt;/span&gt; card today. Not sure if I get internet with a local &lt;span class="caps"&gt;SIM&lt;/span&gt;, so
&lt;a href="http://twitter.com/gmwils"&gt;Twitter&lt;/a&gt; updates are likely to be more&amp;nbsp;sporadic.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>How to be an Innovator for Life</title><link href="https://pseudofish.com/how-to-be-an-innovator-for-life.html" rel="alternate"></link><published>2008-11-27T14:24:00+01:00</published><updated>2008-11-27T14:24:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-11-27:/how-to-be-an-innovator-for-life.html</id><summary type="html">&lt;p&gt;&lt;a href="http://www.leighbureau.com/speaker.asp?id=97"&gt;Tom Kelly&lt;/a&gt;, of the design and development firm &lt;span class="caps"&gt;IDEO&lt;/span&gt;, gives a
brilliant speech at Stanford&amp;#8217;s &lt;a href="http://etl.stanford.edu/"&gt;&lt;span class="caps"&gt;ETL&lt;/span&gt; program&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;He breaks innovation down into five&amp;nbsp;habits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Think like a traveller; be child like with a sense of wonder &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;&amp;nbsp;exploration.&lt;/li&gt;
&lt;li&gt;Treat life as an experiment; be willing to fail provided learning is …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.leighbureau.com/speaker.asp?id=97"&gt;Tom Kelly&lt;/a&gt;, of the design and development firm &lt;span class="caps"&gt;IDEO&lt;/span&gt;, gives a
brilliant speech at Stanford&amp;#8217;s &lt;a href="http://etl.stanford.edu/"&gt;&lt;span class="caps"&gt;ETL&lt;/span&gt; program&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;He breaks innovation down into five&amp;nbsp;habits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Think like a traveller; be child like with a sense of wonder &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;&amp;nbsp;exploration.&lt;/li&gt;
&lt;li&gt;Treat life as an experiment; be willing to fail provided learning is&amp;nbsp;attached.&lt;/li&gt;
&lt;li&gt;Nurture an attitude of&amp;nbsp;wisdom.&lt;/li&gt;
&lt;li&gt;Use your whole brain (and your tortoise&amp;nbsp;mind).&lt;/li&gt;
&lt;li&gt;Follow your&amp;nbsp;passions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;span class="caps"&gt;ETL&lt;/span&gt; series is available as a podcast on iTunes and continues to be a
valuable&amp;nbsp;resource.&lt;/p&gt;</content><category term="design"></category></entry><entry><title>5D Mark II Shipping Today, Somewhere</title><link href="https://pseudofish.com/5d-mark-ii-shipping-today-somewhere.html" rel="alternate"></link><published>2008-11-26T08:15:00+01:00</published><updated>2008-11-26T08:15:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-11-26:/5d-mark-ii-shipping-today-somewhere.html</id><summary type="html">&lt;p&gt;Canon&amp;#8217;s new &lt;a href="http://www.amazon.com/exec/obidos/asin/B001G5ZTLS/ref=nosim/pseudofish-20"&gt;5D&lt;/a&gt; has &lt;a href="http://www.robgalbraith.com/bins/content_page.asp?cid=7-9318-9765"&gt;started shipping&lt;/a&gt; in the &lt;span class="caps"&gt;US&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.mathewpacker.com/2008/11/25/canon-australia-confirmed-the-date-for-the-5d-mkii-release/"&gt;Australian shipping&lt;/a&gt; is a bit of a guess. Rumor is for the end of the
week (28^th^ Nov). Mine is on pre-order from &lt;a href="https://www.camerasdirect.com.au/index.php/cameras/dslr-cameras/canon/eos-5d-mark-ii-new.html"&gt;Cameras Direct&lt;/a&gt;. They
stopped taking any more pre-orders. Hopefully, they are close with Canon
and can …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Canon&amp;#8217;s new &lt;a href="http://www.amazon.com/exec/obidos/asin/B001G5ZTLS/ref=nosim/pseudofish-20"&gt;5D&lt;/a&gt; has &lt;a href="http://www.robgalbraith.com/bins/content_page.asp?cid=7-9318-9765"&gt;started shipping&lt;/a&gt; in the &lt;span class="caps"&gt;US&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.mathewpacker.com/2008/11/25/canon-australia-confirmed-the-date-for-the-5d-mkii-release/"&gt;Australian shipping&lt;/a&gt; is a bit of a guess. Rumor is for the end of the
week (28^th^ Nov). Mine is on pre-order from &lt;a href="https://www.camerasdirect.com.au/index.php/cameras/dslr-cameras/canon/eos-5d-mark-ii-new.html"&gt;Cameras Direct&lt;/a&gt;. They
stopped taking any more pre-orders. Hopefully, they are close with Canon
and can ship this&amp;nbsp;week.&lt;/p&gt;
&lt;p&gt;China is a bit luckier, as it is &lt;a href="http://www.engadget.com/2008/11/22/canon-eos-5d-mark-ii-spotted-for-sale-in-the-wilds-of-shanghai"&gt;already available&lt;/a&gt; in selected
camera&amp;nbsp;stores.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Bonus:&lt;/em&gt; Video editing tutorials for &lt;span class="caps"&gt;FCP&lt;/span&gt; and the&amp;nbsp;5D.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://petersalvia.wordpress.com/2008/10/07/fcprose-editing-eos-5d-mark-ii-footage/"&gt;Editing 5D&amp;nbsp;footage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://petersalvia.wordpress.com/2008/10/15/fcprose-episode-3-color-grading-5dmarkii-footage/"&gt;Color Grading 5D&amp;nbsp;footage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://petersalvia.wordpress.com/2008/10/18/fcprose-episode-4-cut-color-compress-5dmarkii-footage/"&gt;Cut Color Compress 5D&amp;nbsp;footage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adobe has also updated &lt;a href="http://blogs.adobe.com/jnack/2008/11/camera_raw_52_p.html"&gt;Camera Raw&lt;/a&gt; to support the 5D Mark &lt;span class="caps"&gt;II&lt;/span&gt;.
Lightroom update to follow in&amp;nbsp;December.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Financial Crisis and Blogging</title><link href="https://pseudofish.com/financial-crisis-and-blogging.html" rel="alternate"></link><published>2008-11-21T19:57:00+01:00</published><updated>2008-11-21T19:57:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-11-21:/financial-crisis-and-blogging.html</id><content type="html">&lt;p&gt;&lt;a href="http://thisisindexed.com/2008/11/time-to-look-busy/"&gt;&lt;img alt="image" src="http://thisisindexed.com/wp-content/uploads/2008/11/card1922-372x231.jpg" title="card1922"&gt;&lt;/p&gt;
&lt;p&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;From the delightful &lt;a href="http://thisisindexed.com/"&gt;Indexed&lt;/a&gt;&amp;nbsp;blog.&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>Web 2.0 and the Newspapers</title><link href="https://pseudofish.com/web-20-and-the-newspapers.html" rel="alternate"></link><published>2008-10-31T20:02:00+01:00</published><updated>2008-10-31T20:02:00+01:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-10-31:/web-20-and-the-newspapers.html</id><summary type="html">&lt;p&gt;&lt;em&gt;(Based on my &lt;a href="http://video.google.com/videoplay?docid=2479082270718303529&amp;amp;hl=en"&gt;speech&lt;/a&gt; at &lt;a href="http://www.panpa.org.au/"&gt;&lt;span class="caps"&gt;PANPA&lt;/span&gt;&lt;/a&gt; this&amp;nbsp;year)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Twitter – Web 2.0&amp;#8217;s Poster&amp;nbsp;Child&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Web_2.0"&gt;Web 2.0&lt;/a&gt; was coined at an O&amp;#8217;Reilly conference back in 2004. The aim
was to capture the trend of new web applications that were emerging.
Things like &lt;a href="http://www.flickr.com/"&gt;Flickr&lt;/a&gt;, &lt;a href="http://maps.google.com/"&gt;Google Maps&lt;/a&gt;, &lt;a href="http://delicious.com/"&gt;Delicious&lt;/a&gt; and many …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;(Based on my &lt;a href="http://video.google.com/videoplay?docid=2479082270718303529&amp;amp;hl=en"&gt;speech&lt;/a&gt; at &lt;a href="http://www.panpa.org.au/"&gt;&lt;span class="caps"&gt;PANPA&lt;/span&gt;&lt;/a&gt; this&amp;nbsp;year)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Twitter – Web 2.0&amp;#8217;s Poster&amp;nbsp;Child&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Web_2.0"&gt;Web 2.0&lt;/a&gt; was coined at an O&amp;#8217;Reilly conference back in 2004. The aim
was to capture the trend of new web applications that were emerging.
Things like &lt;a href="http://www.flickr.com/"&gt;Flickr&lt;/a&gt;, &lt;a href="http://maps.google.com/"&gt;Google Maps&lt;/a&gt;, &lt;a href="http://delicious.com/"&gt;Delicious&lt;/a&gt; and many&amp;nbsp;others.&lt;/p&gt;
&lt;p&gt;At its core, Web 2.0 is not about new technology. It is about using
existing technologies to provide a richer, more interactive experience
on the web for&amp;nbsp;consumers.&lt;/p&gt;
&lt;p&gt;The poster child for this new interaction is the web service,
&lt;a href="http://twitter.com/"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A simple concept. Let people broadcast a 140 character message. Didn&amp;#8217;t
sound new. Didn&amp;#8217;t sound all that interesting. Yet, it has taken the
content world by storm.&amp;nbsp;Why?&lt;/p&gt;
&lt;p&gt;It started with blogs. Blogs opened up publishing to the masses. They
made it easy to regularly publish content. Joined with &lt;span class="caps"&gt;RSS&lt;/span&gt; to allow
consumers to subscribe to the content in a way that is convenient for
them, the blogosphere exploded. Suddenly, anyone could have a voice
online. Google helped, driving traffic to the micro&amp;nbsp;sites.&lt;/p&gt;
&lt;p&gt;A person blogging from their bedroom could be ranked higher in Google
than a major newspaper for specific&amp;nbsp;topics.&lt;/p&gt;
&lt;p&gt;Competition&amp;nbsp;resounded.&lt;/p&gt;
&lt;p&gt;Now, some blog networks gather more traffic than major &lt;span class="caps"&gt;US&lt;/span&gt; newspaper&amp;nbsp;sites.&lt;/p&gt;
&lt;h3&gt;Conversation – An Old&amp;nbsp;Idea&lt;/h3&gt;
&lt;p&gt;The secret of their success?&amp;nbsp;Conversation.&lt;/p&gt;
&lt;p&gt;Blogs provide for conversation in two major forms. The original approach
was between blogs. Responses to a post were posted on another blog. This
led to &lt;em&gt;trackbacks&lt;/em&gt;, and support in blogging platforms for tracking&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;The view was that everyone who wanted to respond could have their own
blog. The reality is that most people don&amp;#8217;t. This led to comments on the
blog post&amp;nbsp;itself.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.avc.com/"&gt;Fred Wilson&lt;/a&gt;, a Silicon Valley venture capitalist claims that the
highest quality content on his site is the comments; the conversation
between him and his readers and amongst his readers&amp;nbsp;themselves.&lt;/p&gt;
&lt;p&gt;Think about that. One of the most successful bloggers claims that his
content is not the best on his site. That is game changing. He is no
longer pushing content to readers, he is creating a&amp;nbsp;conversation.&lt;/p&gt;
&lt;h3&gt;Twitter&lt;/h3&gt;
&lt;p&gt;Twitter is a micro-blogging platform, only this time, everyone can blog.
To post content, you write a message that is no more than 140 characters
long. This is an arbitrary limit imposed by the system. This creates a
social dynamic that keeps content brief and to the&amp;nbsp;point.&lt;/p&gt;
&lt;p&gt;The key to Twitter is that there is no difference between posting
content and posting a comment. To comment on someone else, you reply to
them with content of your own. This has led to everyone on Twitter being
a content creator as well as a participant in a&amp;nbsp;conversation.&lt;/p&gt;
&lt;p&gt;One of the other smart things Twitter did was move beyond the web. Web
2.0 in its purest is about two way interaction with your audience in a
way that suits&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;Twitter gets less than &lt;strong&gt;a tenth&lt;/strong&gt; of its traffic from its website.
Other use comes from mobile devices, from third party applications, from
its open &lt;span class="caps"&gt;API&lt;/span&gt;. Twitter goes out of its way to provide open access to the
conversation between its&amp;nbsp;participants.&lt;/p&gt;
&lt;h3&gt;Newspapers &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Web&amp;nbsp;2.0&lt;/h3&gt;
&lt;p&gt;If this is the kind of audience interaction that is working on the
internet, how do newspapers&amp;nbsp;compare?&lt;/p&gt;
&lt;p&gt;Not&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;Recent statistics suggest that newspaper blogs fail to increase the
public dialogue; the conversation. When hosted by a newspaper, 80
percent of bloggers do not respond to comments. If content is about
conversations, this is not a good&amp;nbsp;statistic.&lt;/p&gt;
&lt;p&gt;Think about your own newsroom. If your web site allows comments, does
the original reporter see&amp;nbsp;them?&lt;/p&gt;
&lt;p&gt;The early print only newspapers tried very hard to solicit feedback from
their readers. This shows up in the Letters to the Editor page. There is
an overhead to filter down the feedback and select which nuggets are
suitable for print in the next&amp;nbsp;edition.&lt;/p&gt;
&lt;p&gt;However, the lead time is slow. Responding can take days or weeks,
depending on publication&amp;nbsp;schedule.&lt;/p&gt;
&lt;p&gt;The web lets you take letters not just to the editor, but to any
journalist. And you don&amp;#8217;t need to wait for the next publication date to
publish the letter or to respond. It can happen in an instant. Comments
are a natural part of getting consumers involved
in the news process, and they need to be included into your newsroom&amp;nbsp;process.&lt;/p&gt;
&lt;p&gt;Newspapers have generally seen the web as another distribution channel
for content. A pure push. The stories, once vetted by the subs, were
mass published to the site and then not&amp;nbsp;altered.&lt;/p&gt;
&lt;p&gt;Much has been done to enhance this new output channel. However, from the
newsroom it is still that: an output channel. Not many have feedback
from the web site back to the&amp;nbsp;newsroom.&lt;/p&gt;
&lt;h3&gt;Newsrooms with a Web 2.0&amp;nbsp;Future&lt;/h3&gt;
&lt;p&gt;Let me describe a newsroom of the future, and how content should&amp;nbsp;integrate.&lt;/p&gt;
&lt;p&gt;I receive the stream of comments from the article into an Inbox,
allowing me to comment on them. The system gathers information about
which other sites are linking to my story. Are other news outlets
picking it up? Has the blogosphere started reporting
on it? This information is freely available by blog search engines such
as &lt;a href="http://technorati.com/"&gt;Technorati&lt;/a&gt;. If a competitor publication or a small site wrote a
response I can continue the conversation, by posting a comment on their
site, or by writing a follow-up story linked
to my original story and their&amp;nbsp;response.&lt;/p&gt;
&lt;p&gt;Now that I have a number of conversations, this feeds my news gathering
process. The web provides metrics on how popular my content is. How many
people have read the story, how many people have commented, how many
other sites are linked in to my&amp;nbsp;content.&lt;/p&gt;
&lt;p&gt;This gives me a finger on the pulse of what my audience is interested in
and assists in selecting new topics for research and&amp;nbsp;discussion.&lt;/p&gt;
&lt;p&gt;My newsroom also provides me with up to date information on topics that
I&amp;#8217;m interested in. This includes not only feeds from wire services,
filtered by my topics, but also feeds from bloggers, interactions with
leads and contacts via instant messages or
social services such as Twitter. This allows me to copy taste a stream
of information tailored to the kinds of stories I am reporting&amp;nbsp;on.&lt;/p&gt;
&lt;p&gt;If a story breaks half way around the world, my desktop provides me a
stream of official content from the location as well as citizen
journalists and general participants&amp;#8217; contributions. This allows for me
to gather quotes and research background&amp;nbsp;information.&lt;/p&gt;
&lt;p&gt;I can quickly publish to the web and alert other journalists in my
organization of the story. I can start to gather additional media such
as images and video to build up my story package. I&amp;#8217;m still receiving
comments on the story I&amp;#8217;ve just posted, allowing
me to continue to update the story with new and relevant&amp;nbsp;information.&lt;/p&gt;
&lt;p&gt;No longer a single publishing event for the story, it is now an ongoing
news event; a&amp;nbsp;conversation.&lt;/p&gt;
&lt;h3&gt;Expanding Your&amp;nbsp;Reach&lt;/h3&gt;
&lt;p&gt;Similar to Twitter&amp;#8217;s &lt;span class="caps"&gt;API&lt;/span&gt; support, news content is being repurposed
across multiple channels. Some of these are purely web based, such as
portal sites integrating headlines and summaries or Google News. Others
are becoming more diverse. The iPhone is showcasing
what is possible for a mobile device. eReaders such as the Kindle in the
&lt;span class="caps"&gt;US&lt;/span&gt;, the Sony &lt;span class="caps"&gt;PRS&lt;/span&gt; eReader or the iRex iLiad provide for a different
reading&amp;nbsp;experience.&lt;/p&gt;
&lt;p&gt;This leads to more opportunities to syndicate your content, more options
for expanding the conversation, but also a much more complex media&amp;nbsp;landscape.&lt;/p&gt;
&lt;p&gt;Reuters has led the way, providing an open &lt;span class="caps"&gt;API&lt;/span&gt; allowing third parties to
remix its content into innovative ways of presentation and&amp;nbsp;distribution.&lt;/p&gt;
&lt;h3&gt;The new&amp;nbsp;audience&lt;/h3&gt;
&lt;p&gt;There is no single audience that can be reasoned about in aggregate.
Instead there is a collection of participants in a series of
conversations. What works for one may not work for&amp;nbsp;another.&lt;/p&gt;
&lt;p&gt;One approach is personalization: Allowing the reader to customize the
site to their needs. This is something the portal providers, such as
Yahoo, have focused on. Their theory is that if they can provide a one
stop shop for the consumer, then they will
see more of the traffic. They not only integrate their own content, but
provide summaries and links to third party content. This gives the user
a dashboard of what is hot in their version of the&amp;nbsp;internet.&lt;/p&gt;
&lt;p&gt;This becomes more interesting is when this information can be inferred.
Say that I&amp;#8217;ve been reading the newspaper site for the last year. The web
platform can track what I&amp;#8217;ve been reading and start to build a profile
to infer what else I&amp;#8217;m interested&amp;nbsp;in.&lt;/p&gt;
&lt;p&gt;Amazon leads the way in this inference approach. They know which
products I&amp;#8217;ve bought, which products I&amp;#8217;ve browsed and serve up
suggestions as to what kind of products I might like to&amp;nbsp;consider.&lt;/p&gt;
&lt;p&gt;There is no reason that a content site cannot do the&amp;nbsp;same.&lt;/p&gt;
&lt;h3&gt;Metrics&lt;/h3&gt;
&lt;p&gt;In the current incarnation of the print newspaper, we go out of our way
to track circulation metrics to determine our audience. On the web, this
can be handed to us but we&amp;#8217;ve not been asking for&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;A good web platform can track an individual reader of your site and
infer what kinds of content they are interested&amp;nbsp;in.&lt;/p&gt;
&lt;p&gt;This impacts the newsroom in several ways. Firstly by requiring a more
interactive approach to content. Secondly, by providing more specific
and targeted content. The niche is in. Have journalists specialize and
allow consumers access to that&amp;nbsp;specialty.&lt;/p&gt;
&lt;h3&gt;Classification&lt;/h3&gt;
&lt;p&gt;Consumers are used to being their own editors on the web. Their own copy
tasters. They mix together content from multiple sources, from
newspapers, from blogs, from their friends, from companies to produce a
stream of information relevant for them. The content you produce needs
to be able to fit into this new model. And it is about producing
content. Not selecting content. Your readers can do that for you, and
want to do it for&amp;nbsp;themselves.&lt;/p&gt;
&lt;p&gt;Google News is popular not because of their journalists, but because it
provides access to content in a way the consumer can&amp;nbsp;shape.&lt;/p&gt;
&lt;h3&gt;Caveats&lt;/h3&gt;
&lt;p&gt;Be wary of your readers&amp;#8217; trust. Newspapers are brands that are trusted.
It is trust that has been built up over generations. It is a trust that
can be rapidly&amp;nbsp;lost.&lt;/p&gt;
&lt;p&gt;Make sure that you are open with what you are trying, why you are trying
it and what implications it has for your users. There are no secrets on
the&amp;nbsp;web.&lt;/p&gt;
&lt;p&gt;The other concern is that of quality. This I have no easy answer for as
there is a trade&amp;nbsp;off.&lt;/p&gt;
&lt;p&gt;Bloggers have solved this by swinging to the conversation side. The
tendency is to post often and be involved in the discussion, although
with spelling and grammar errors that would make a newspaper&amp;nbsp;cringe.&lt;/p&gt;
&lt;p&gt;Newspapers have historically gone the other way. Pushing content to the
web and not being involved in the conversation. There is space in the&amp;nbsp;middle.&lt;/p&gt;
&lt;h3&gt;Recommendations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Web 2.0 is a &lt;strong&gt;two-way&lt;/strong&gt; medium. Print ways don&amp;#8217;t always work on the&amp;nbsp;web.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some other things to think&amp;nbsp;about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is all about &lt;strong&gt;conversation&lt;/strong&gt;. Engage your readers in&amp;nbsp;discussion.&lt;/li&gt;
&lt;li&gt;Try new &lt;strong&gt;channels&lt;/strong&gt; for hosting the conversation. Mobile. APIs.&amp;nbsp;Devices.&lt;/li&gt;
&lt;li&gt;Let your readers &lt;strong&gt;personalize&lt;/strong&gt; their experience with your&amp;nbsp;content.&lt;/li&gt;
&lt;li&gt;Make use of the rich &lt;strong&gt;metrics&lt;/strong&gt; available to drive editorial&amp;nbsp;decisions.&lt;/li&gt;
&lt;/ul&gt;</content><category term="media"></category></entry><entry><title>Tracking Technology Trends</title><link href="https://pseudofish.com/tracking-technology-trends.html" rel="alternate"></link><published>2008-10-13T12:41:00+02:00</published><updated>2008-10-13T12:41:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-10-13:/tracking-technology-trends.html</id><summary type="html">&lt;p&gt;&lt;a href="http://scobleizer.com/"&gt;Robert Scoble&lt;/a&gt; recently posted his &lt;a href="http://scobleizer.com/2008/09/26/the-scoble-top-tech-bloggerfriendfeedsocial-media-list/"&gt;top list&lt;/a&gt; of interesting people
for technology. He is a vocal advocate for &lt;a href="http://friendfeed.com"&gt;Friend Feed&lt;/a&gt;. It got me
thinking about how I go about tracking technology&amp;nbsp;news.&lt;/p&gt;
&lt;p&gt;I joined Friend Feed a while ago and added a few of the usual suspects.
With Scoble&amp;#8217;s …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://scobleizer.com/"&gt;Robert Scoble&lt;/a&gt; recently posted his &lt;a href="http://scobleizer.com/2008/09/26/the-scoble-top-tech-bloggerfriendfeedsocial-media-list/"&gt;top list&lt;/a&gt; of interesting people
for technology. He is a vocal advocate for &lt;a href="http://friendfeed.com"&gt;Friend Feed&lt;/a&gt;. It got me
thinking about how I go about tracking technology&amp;nbsp;news.&lt;/p&gt;
&lt;p&gt;I joined Friend Feed a while ago and added a few of the usual suspects.
With Scoble&amp;#8217;s list, I set out to add many more to my feed. Using the
filtering on the site, I&amp;#8217;ve grouped them into a few&amp;nbsp;categories.&lt;/p&gt;
&lt;p&gt;I can see the theory behind Friend Feed. Aggregate all these sources,
allow comments on items, and provide basic voting. I also like how it
will show me interesting items from friends of friends. It is now about
improving the signal to noise ratio to get me back more&amp;nbsp;often.&lt;/p&gt;
&lt;p&gt;Most of my news still comes in the old fashioned way:&amp;nbsp;blogs.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.newsgator.com/"&gt;Newsgator&lt;/a&gt; does the magic of keeping them in sync between my Macs,
iPhone &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; PCs. I&amp;#8217;ve found it useful to subscribe to some developer&amp;#8217;s
&lt;a href="http://delicious.com/gmwils/"&gt;Delicious&lt;/a&gt; feeds; more reliable than waiting for a blog&amp;nbsp;post.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m also a big fan of &lt;a href="http://twitter.com/gmwils"&gt;Twitter&lt;/a&gt; for ad-hoc discovery and &lt;a href="http://techmeme.com/"&gt;Techmeme&lt;/a&gt;
for following the overall&amp;nbsp;industry.&lt;/p&gt;
&lt;p&gt;Things off my radar? Newspapers and dedicated media outlets. This is a
big shift from a few years ago, when I used to read the Green Guide (a
section of &lt;a href="http://www.theage.com.au/"&gt;the Age&lt;/a&gt;) and &lt;a href="http://arstechnica.com/index.ars"&gt;Ars Technica&lt;/a&gt;&amp;nbsp;religiously.&lt;/p&gt;
&lt;p&gt;Thus my consumption of news shifts further towards being personal and&amp;nbsp;aggregated.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>Become a more effective leader</title><link href="https://pseudofish.com/become-a-more-effective-leader.html" rel="alternate"></link><published>2008-10-08T21:22:00+02:00</published><updated>2008-10-08T21:22:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-10-08:/become-a-more-effective-leader.html</id><summary type="html">&lt;p&gt;&lt;a href="http://www.manager-tools.com/"&gt;Manager Tools&lt;/a&gt; (&lt;span class="caps"&gt;MT&lt;/span&gt;) is a weekly podcast that provides free training
on how to be a more effective manager and leader. The hosts have an
extensive background in coaching managers and&amp;nbsp;executives.&lt;/p&gt;
&lt;p&gt;Management is a skill and it can be learned. Typically it is not taught
well, if at all …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.manager-tools.com/"&gt;Manager Tools&lt;/a&gt; (&lt;span class="caps"&gt;MT&lt;/span&gt;) is a weekly podcast that provides free training
on how to be a more effective manager and leader. The hosts have an
extensive background in coaching managers and&amp;nbsp;executives.&lt;/p&gt;
&lt;p&gt;Management is a skill and it can be learned. Typically it is not taught
well, if at all; &lt;span class="caps"&gt;MT&lt;/span&gt; teaches it&amp;nbsp;effectively.&lt;/p&gt;
&lt;p&gt;If you’re thinking, “but I’m not a manager, I won’t benefit”, then you’d
be wrong. Even if you don’t manage other people, you manage your own
time and interact into a larger organization. The skills taught by &lt;span class="caps"&gt;MT&lt;/span&gt;
are beneficial to anyone who works for a&amp;nbsp;corporation.&lt;/p&gt;
&lt;p&gt;These guys have been podcasting since 2005. There is some benefit to
going right back to the start, but if you want to catch up there is a
subset of casts that are considered “&lt;a href="http://www.manager-tools.com/manager-tools-basics/"&gt;core&lt;/a&gt;”.&lt;/p&gt;
&lt;p&gt;I’ve found this podcast to be the best source of on-going knowledge
about management, leadership, and communication. Each cast is designed
to teach specific actions you can take&amp;nbsp;today.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;MT&lt;/span&gt; was originally recommended to me be a &lt;a href="http://www.sgi.nu/diary/"&gt;friend&lt;/a&gt; at &lt;span class="caps"&gt;CSIRO&lt;/span&gt;. Since then
I&amp;#8217;ve listened to most of the episodes. It is that&amp;nbsp;good.&lt;/p&gt;</content><category term="management"></category></entry><entry><title>Vanity and Rupert</title><link href="https://pseudofish.com/vanity-and-rupert.html" rel="alternate"></link><published>2008-10-06T08:17:00+02:00</published><updated>2008-10-06T08:17:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-10-06:/vanity-and-rupert.html</id><summary type="html">&lt;p&gt;&lt;a href="http://www.vanityfair.com/culture/features/2008/10/wolff200810?printable=true&amp;amp;currentPage=all"&gt;Rupert Murdoch&lt;/a&gt; opens up to Vanity Fair&amp;#8217;s Michael Wolff as background
for an upcoming biography. The &lt;a href="http://www.vanityfair.com/culture/features/2008/10/wolff200810?printable=true&amp;amp;currentPage=all"&gt;article&lt;/a&gt; provides great
insight to the man and, by proxy, the companies he&amp;nbsp;runs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But his odd lack of seductiveness or felicitousness—contributing to
his aura of villainy—became after a while alluring …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.vanityfair.com/culture/features/2008/10/wolff200810?printable=true&amp;amp;currentPage=all"&gt;Rupert Murdoch&lt;/a&gt; opens up to Vanity Fair&amp;#8217;s Michael Wolff as background
for an upcoming biography. The &lt;a href="http://www.vanityfair.com/culture/features/2008/10/wolff200810?printable=true&amp;amp;currentPage=all"&gt;article&lt;/a&gt; provides great
insight to the man and, by proxy, the companies he&amp;nbsp;runs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But his odd lack of seductiveness or felicitousness—contributing to
his aura of villainy—became after a while alluring in itself. There’s
no spin, because he really can’t explain himself. Rather, what you see
is what you get. He’s transparent. The nature of the beast is entirely&amp;nbsp;evident.&lt;/p&gt;
&lt;p&gt;&amp;#8230;&lt;/p&gt;
&lt;p&gt;There is at News Corp. never a discussion of Murdoch’s exit. It is
referred to only as “in 30 or 40 years,” when he is gone—which may
have started as an amusing locution, but is now a practiced and even
official one. His existential predicament is, in other words, his&amp;nbsp;own.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;a href="http://www.guardian.co.uk/media/2008/sep/28/newscorporation.wallstreetjournal"&gt;Guardian&lt;/a&gt; also has a good &lt;a href="http://www.guardian.co.uk/media/2008/sep/28/newscorporation.wallstreetjournal"&gt;piece&lt;/a&gt; on the &lt;em&gt;Battle
Royale&lt;/em&gt; that is brewing between the new &lt;span class="caps"&gt;WSJ&lt;/span&gt; and the New York Times, and
why it may no longer&amp;nbsp;matter.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Murdoch fell into conversation with Arthur Sulzberger, publisher of
the Journal&amp;#8217;s arch-rival, the New York Times. By buying the Journal,
Murdoch had parked his tanks directly on the &lt;span class="caps"&gt;NYT&lt;/span&gt;&amp;#8217;s lawn. What, people
wondered, would the two make of each&amp;nbsp;other?&lt;/p&gt;
&lt;/blockquote&gt;</content><category term="media"></category></entry><entry><title>Canon 5D Mark II And Wow</title><link href="https://pseudofish.com/canon-5d-mark-ii-and-wow.html" rel="alternate"></link><published>2008-09-18T21:29:00+02:00</published><updated>2008-09-18T21:29:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-09-18:/canon-5d-mark-ii-and-wow.html</id><summary type="html">&lt;p&gt;&lt;img alt="image" src="/illustrations/20080917_loRes_5dmkii_3q.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The 5D Mark &lt;span class="caps"&gt;II&lt;/span&gt; is one heck of a camera and puts Canon back in the game
at the semi-pro&amp;nbsp;level.&lt;/p&gt;
&lt;p&gt;I was all set to buy the original 5D after its price dropped with the
release of the new one. I also considered selling all my Canon gear to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;img alt="image" src="/illustrations/20080917_loRes_5dmkii_3q.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The 5D Mark &lt;span class="caps"&gt;II&lt;/span&gt; is one heck of a camera and puts Canon back in the game
at the semi-pro&amp;nbsp;level.&lt;/p&gt;
&lt;p&gt;I was all set to buy the original 5D after its price dropped with the
release of the new one. I also considered selling all my Canon gear to
get the D700. I&amp;#8217;m glad I&amp;nbsp;waited.&lt;/p&gt;
&lt;p&gt;The new revision has some grand&amp;nbsp;features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;21 megapixel, full-frame &lt;span class="caps"&gt;CMOS&lt;/span&gt;&amp;nbsp;sensor&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;ISO&lt;/span&gt; 100 - 6400 (extendable to &lt;span class="caps"&gt;ISO&lt;/span&gt; 50 -&amp;nbsp;25600)&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;HD&lt;/span&gt; Movie recording and &lt;span class="caps"&gt;HDMI&lt;/span&gt;&amp;nbsp;out&lt;/li&gt;
&lt;li&gt;3.9 frames per second continuous&amp;nbsp;shooting&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The addition that would have been nice is an improved max sync speed.
1/200 is a bit slow. &lt;span class="caps"&gt;ISO&lt;/span&gt; 50 helps, but it would be even better if max
sync could get to 1/250 or&amp;nbsp;1/320.&lt;/p&gt;
&lt;p&gt;External&amp;nbsp;links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.usa.canon.com/templatedata/pressrelease/20080917_5dmkii.html"&gt;Canon Press&amp;nbsp;Release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.dpreview.com/previews/canoneos5dmarkII/"&gt;DPReview Hands-on&amp;nbsp;Preview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.nicephotomag.com/the-latest/sample-hd-video-from-the-new-canon-5d-markii"&gt;Sample Video&amp;nbsp;Footage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://prolost.blogspot.com/2008/09/so-close-canon.html"&gt;Not quite pro for&amp;nbsp;video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The video samples are not exciting, but are beautiful quality. If only
&lt;a href="http://blog.chasejarvis.com/blog/2008/08/chase-jarvis-raw-advance-testing-nikon.html"&gt;Chase Jarvis&lt;/a&gt; was shooting Canon gear. Not that it matters, the new
5D will sell by the truck&amp;nbsp;load.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Olympics in Pictures</title><link href="https://pseudofish.com/olympics-in-pictures.html" rel="alternate"></link><published>2008-08-16T22:18:00+02:00</published><updated>2008-08-16T22:18:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-08-16:/olympics-in-pictures.html</id><summary type="html">&lt;p&gt;I wasn&amp;#8217;t hugely interested in the Olympics from a sporting perspective.
I&amp;#8217;m more a Winter Olympics kinda guy. However, I&amp;#8217;ve found myself
enthralled by the lengths taken by photographers to capture the&amp;nbsp;games.&lt;/p&gt;
&lt;p&gt;The main entry point is &lt;a href="http://vincentlaforet.wordpress.com/"&gt;Vincent Laforet&lt;/a&gt;&amp;#8216;s blog. He&amp;#8217;s an experienced
photographer …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I wasn&amp;#8217;t hugely interested in the Olympics from a sporting perspective.
I&amp;#8217;m more a Winter Olympics kinda guy. However, I&amp;#8217;ve found myself
enthralled by the lengths taken by photographers to capture the&amp;nbsp;games.&lt;/p&gt;
&lt;p&gt;The main entry point is &lt;a href="http://vincentlaforet.wordpress.com/"&gt;Vincent Laforet&lt;/a&gt;&amp;#8216;s blog. He&amp;#8217;s an experienced
photographer and is sharing his thought processes as he covers the games
for&amp;nbsp;Newsweek.&lt;/p&gt;
&lt;p&gt;Newsweek have taken an interesting approach and sent three photographers
to shot the games and to blog about it. Their combined blog is &lt;a href="http://blog.newsweek.com/blogs/olympicpix/"&gt;here&lt;/a&gt;.
&lt;a href="http://blog.newsweek.com/blogs/olympicpix/archive/2008/08/15/world-records-seen-from-above.aspx"&gt;This article&lt;/a&gt; is a good example of the kinds of information being
posted. The editor also selects a photo for the&amp;nbsp;day.&lt;/p&gt;
&lt;p&gt;Reuter&amp;#8217;s &lt;a href="http://blogs.reuters.com/photo/"&gt;photo blog&lt;/a&gt; is also featuring an Olympic photo of the day
from their&amp;nbsp;photographers.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m learning a lot about sport photography and photography in general by
reading through these, especially Vincent&amp;#8217;s musings. I now have
enthusiasm for the&amp;nbsp;Olympics.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>VMWare Movie Capture &amp; Conversion</title><link href="https://pseudofish.com/vmware-movie-capture-conversion.html" rel="alternate"></link><published>2008-08-01T10:11:00+02:00</published><updated>2008-08-01T10:11:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-08-01:/vmware-movie-capture-conversion.html</id><summary type="html">&lt;p&gt;On a &lt;span class="caps"&gt;PC&lt;/span&gt;, I want to be able to easily capture screencasts for the
products we use at work. The ulterior motive is to be able to show a
video rather than repeat the demo hundreds of&amp;nbsp;times.&lt;/p&gt;
&lt;p&gt;VMWare gives a tantalizing option: &lt;em&gt;Capture&amp;nbsp;Movie&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is under the &lt;span class="caps"&gt;VM …&lt;/span&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;On a &lt;span class="caps"&gt;PC&lt;/span&gt;, I want to be able to easily capture screencasts for the
products we use at work. The ulterior motive is to be able to show a
video rather than repeat the demo hundreds of&amp;nbsp;times.&lt;/p&gt;
&lt;p&gt;VMWare gives a tantalizing option: &lt;em&gt;Capture&amp;nbsp;Movie&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is under the &lt;span class="caps"&gt;VM&lt;/span&gt; menu in the menu bar. Prompts for a filename and
you&amp;#8217;re&amp;nbsp;away.&lt;/p&gt;
&lt;p&gt;Slight catch. Playing back the movie that is recorded leads to not much
but trouble. Turns out that VMWare encodes the movie into a non-standard
video format. Details of it are &lt;a href="http://wiki.multimedia.cx/index.php?title=VMware_Video"&gt;here&lt;/a&gt;. (It is using the &lt;span class="caps"&gt;VNC&lt;/span&gt; protocol
to encode the video with some &lt;span class="caps"&gt;VM&lt;/span&gt; specific&amp;nbsp;headers)&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;ve installed Workstation, the decoder for the codec is included.
Otherwise, you can download the codec &lt;a href="http://www.moviecodec.com/downloads/400d.html"&gt;here&lt;/a&gt;. I found you need to use
Microsoft Media Player to actually play&amp;nbsp;back.&lt;/p&gt;
&lt;p&gt;That still leaves the problem of editing the video. With the video
recorded and the codec installed, you can convert the video into a
suitable format. I used Prism&amp;#8217;s &lt;a href="http://www.nchsoftware.com/prism/index.html"&gt;conversion program&lt;/a&gt; to produce an &lt;span class="caps"&gt;AVI&lt;/span&gt;
that can be read by Final Cut&amp;nbsp;Pro.&lt;/p&gt;
&lt;p&gt;Final Cut Pro took a bit of effort, but produced a very slick result.
You can use simpler options for the video editing&amp;nbsp;piece.&lt;/p&gt;
&lt;p&gt;The result is that I can now capture video of demonstrations that are
run in a VMWare environment, and re-mix them into various&amp;nbsp;screencasts.&lt;/p&gt;</content><category term="technology"></category></entry><entry><title>Photography Marketing Tips</title><link href="https://pseudofish.com/photography-marketing-tips.html" rel="alternate"></link><published>2008-07-14T09:25:00+02:00</published><updated>2008-07-14T09:25:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-07-14:/photography-marketing-tips.html</id><summary type="html">&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Be&amp;nbsp;Aggressive&lt;/li&gt;
&lt;li&gt;Diversify&lt;/li&gt;
&lt;li&gt;Look for new resources for finding&amp;nbsp;customers&lt;/li&gt;
&lt;li&gt;Pay attention to your primary message — don&amp;#8217;t let it get&amp;nbsp;lost&lt;/li&gt;
&lt;li&gt;Look for new promotional&amp;nbsp;partners&lt;/li&gt;
&lt;li&gt;Build your&amp;nbsp;brand&lt;/li&gt;
&lt;li&gt;Pay attention to your&amp;nbsp;website&lt;/li&gt;
&lt;li&gt;Use your own work for your holiday cards and&amp;nbsp;stationary&lt;/li&gt;
&lt;li&gt;Look for new promotional&amp;nbsp;opportunities …&lt;/li&gt;&lt;/ol&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Be&amp;nbsp;Aggressive&lt;/li&gt;
&lt;li&gt;Diversify&lt;/li&gt;
&lt;li&gt;Look for new resources for finding&amp;nbsp;customers&lt;/li&gt;
&lt;li&gt;Pay attention to your primary message — don&amp;#8217;t let it get&amp;nbsp;lost&lt;/li&gt;
&lt;li&gt;Look for new promotional&amp;nbsp;partners&lt;/li&gt;
&lt;li&gt;Build your&amp;nbsp;brand&lt;/li&gt;
&lt;li&gt;Pay attention to your&amp;nbsp;website&lt;/li&gt;
&lt;li&gt;Use your own work for your holiday cards and&amp;nbsp;stationary&lt;/li&gt;
&lt;li&gt;Look for new promotional&amp;nbsp;opportunities&lt;/li&gt;
&lt;li&gt;Stay on top of&amp;nbsp;technology&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is a very short synopsis of Skips’ normal four-hour&amp;nbsp;presentation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;From &lt;a href="http://skip.wedshooter.com/"&gt;Skip Cohen&lt;/a&gt; (via &lt;a href="http://blogs.msdn.com/prophoto/archive/2008/07/10/microsoft-pro-photo-summit-day-2-2.aspx"&gt;Jeff Greene&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I started out in photography as I love taking photographs. I&amp;#8217;m sticking
with photography as there is so much to learn; business strategy,
marketing, technology &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;&amp;nbsp;more.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Melbourne Pro Photo Labs</title><link href="https://pseudofish.com/melbourne-pro-photo-labs.html" rel="alternate"></link><published>2008-07-08T23:18:00+02:00</published><updated>2008-07-08T23:18:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-07-08:/melbourne-pro-photo-labs.html</id><summary type="html">&lt;p&gt;I&amp;#8217;m recently become quite excited about printing my photos. So much so
that I&amp;#8217;ve bought an A4 photo printer for &amp;#8220;proofing&amp;#8221;. For high quality
prints, I&amp;#8217;d rather outsource to a professional lab. The information on
which ones are in Melbourne is a bit scattered, thus this&amp;nbsp;list …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;m recently become quite excited about printing my photos. So much so
that I&amp;#8217;ve bought an A4 photo printer for &amp;#8220;proofing&amp;#8221;. For high quality
prints, I&amp;#8217;d rather outsource to a professional lab. The information on
which ones are in Melbourne is a bit scattered, thus this&amp;nbsp;list.&lt;/p&gt;
&lt;p&gt;Melbourne&amp;nbsp;labs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.bondimaging.com/"&gt;Bond Imaging&lt;/a&gt; – Richmond (&lt;em&gt;quote on request&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.cpldigital.com.au/"&gt;&lt;span class="caps"&gt;CPL&lt;/span&gt; Digital&lt;/a&gt; – St Kilda (&lt;a href="http://www.cpldigital.com.au/frontier.html"&gt;price list&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.digitalworks.net.au/"&gt;Digital Works&lt;/a&gt; – Hallam (&lt;a href="http://hub-au.realpix.net/hub/comms/printv2.asp?job=wcViewPrices&amp;amp;storeID=au-digitalworks3803&amp;amp;promocode="&gt;price list&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.labx.com.au/"&gt;Lab X&lt;/a&gt; – St Kilda (&lt;a href="http://www.labx.com.au/LabXPriceList.htm"&gt;price list&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nulab.com.au/"&gt;NuLab&lt;/a&gt; – Braeside (&lt;em&gt;price list on registration&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.vanbar.com.au/"&gt;Vanbar Imaging&lt;/a&gt; – Carlton / North Melbourne (&lt;a href="http://www.vanbar.com.au/shopping_lab1/lab_login.php"&gt;price list&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To get the most out of a good photo lab, or any photo lab, you need to
be using a colour managed workflow. This should include proofing in
Photoshop based on the colour profile of the print device. If the lab
can not supply a way of colour matching to their printer, you may want
to consider another&amp;nbsp;lab.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt;: I&amp;#8217;m not affiliated with any of these labs. I actually
haven&amp;#8217;t used most of them, so if you have recommendations, please leave
a&amp;nbsp;comment.&lt;/p&gt;</content><category term="photography"></category></entry><entry><title>Extreme Photographing</title><link href="https://pseudofish.com/extreme-photographing.html" rel="alternate"></link><published>2008-06-13T08:50:00+02:00</published><updated>2008-06-13T08:50:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-06-13:/extreme-photographing.html</id><summary type="html">&lt;p&gt;&lt;a href="http://www.michaelclarkphoto.com/spring_2008.pdf"&gt;This edition&lt;/a&gt; of &lt;a href="http://www.michaelclarkphoto.com/backissues.htm"&gt;Michael Clark&lt;/a&gt;&amp;#8216;s newsletter is a doozie. Aside
from reminding me of my annoyance with Canon for not having a decent
competitor to the D300, he has an inspiring article on shooting the
&lt;a href="http://www.patagoniaexpeditionrace.com/"&gt;Patagonia Expedition Race&lt;/a&gt;. This is&amp;nbsp;wow.&lt;/p&gt;
&lt;p&gt;The race is described on the official site …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.michaelclarkphoto.com/spring_2008.pdf"&gt;This edition&lt;/a&gt; of &lt;a href="http://www.michaelclarkphoto.com/backissues.htm"&gt;Michael Clark&lt;/a&gt;&amp;#8216;s newsletter is a doozie. Aside
from reminding me of my annoyance with Canon for not having a decent
competitor to the D300, he has an inspiring article on shooting the
&lt;a href="http://www.patagoniaexpeditionrace.com/"&gt;Patagonia Expedition Race&lt;/a&gt;. This is&amp;nbsp;wow.&lt;/p&gt;
&lt;p&gt;The race is described on the official site&amp;nbsp;as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is a journey to the end of the world, to the unknown, a trip to a
virgin and wild territory, to southern Patagonia, the tip of the
American continent. It is a race marked by the mystique of
exploration, of discovery and facing the untamable Mother Nature. It
is an adventure at the end of the&amp;nbsp;world&amp;#8230;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Reading that in isolation, I&amp;#8217;m thinking &amp;#8220;yeah, sure&amp;#8221;. Reading that after
Michael&amp;#8217;s story and seeing his photos, I&amp;#8217;m thinking &amp;#8220;wow,&amp;nbsp;Wow!&amp;#8221;.&lt;/p&gt;
&lt;p&gt;He quotes Kent Kobersteen, a famed photo editor from National&amp;nbsp;Geographic:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The really strong photos come from those situations where the last
thing you want to do is take pictures – where everything is going to
hell, where the storms are raging and everyone is trying to hang&amp;nbsp;on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They were definitely in the right&amp;nbsp;place:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;And we were in an alpine jungle with trees so dense that not even a
helicopter could find us in this&amp;nbsp;valley.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well worth a &lt;a href="http://www.michaelclarkphoto.com/spring_2008.pdf"&gt;read&lt;/a&gt; (pdf). Or even just a download to look
at the&amp;nbsp;pictures!&lt;/p&gt;
&lt;p&gt;A closing&amp;nbsp;thought:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are two basic ways to find inspiration. One is to go on a trip
and the other is to put the camera down for a&amp;nbsp;while.&lt;/p&gt;
&lt;p&gt;&lt;small&gt;– Jay Maisel, page 20&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content><category term="photography"></category></entry><entry><title>Favorite Things</title><link href="https://pseudofish.com/favorite-things.html" rel="alternate"></link><published>2008-05-25T23:02:00+02:00</published><updated>2008-05-25T23:02:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-05-25:/favorite-things.html</id><content type="html">&lt;object width="384" height="288" id="movieclip" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" align="middle"&gt;&lt;param name="movie" value="http://video.mpora.com/fmp.swf?vid=TplUU8H0l"&gt;&lt;/param&gt;&lt;param name="menu" value="false"&gt;&lt;/param&gt;&lt;param name="quality" value="high"&gt;&lt;/param&gt;&lt;param name="bgcolor" value="#000000"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="flashvars" value="file=http%3A%2F%2Fvx2%2Empora%2Ecom%2F%2Fplay%2Fvideo%2FTplUU8H0l&amp;amp;title=Snowboarders%2C%20a%20Subaru%20Impreza%20and%20lots%20of%20money%2E%2E%2E&amp;amp;id=TplUU8H0l"&gt;&lt;/param&gt;&lt;embed src="http://video.mpora.com/fmp.swf?vid=TplUU8H0l" menu="false" quality="high" bgcolor="#000000" width="384" height="288" name="movieclip" align="middle" allowfullscreen="true" flashvars="file=http%3A%2F%2Fvx2%2Empora%2Ecom%2F%2Fplay%2Fvideo%2FTplUU8H0l&amp;amp;title=Snowboarders%2C%20a%20Subaru%20Impreza%20and%20lots%20of%20money%2E%2E%2E&amp;amp;id=TplUU8H0l" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;p&gt;Snowboarding, rally driving and Primus. &lt;a href="http://video.mpora.com/watch/TplUU8H0l/"&gt;Too&amp;nbsp;good!&lt;/a&gt;&lt;/p&gt;</content><category term="musings"></category></entry><entry><title>HaskellDB Performance</title><link href="https://pseudofish.com/haskelldb-performance.html" rel="alternate"></link><published>2008-05-18T23:47:00+02:00</published><updated>2008-05-18T23:47:00+02:00</updated><author><name>gmwils</name></author><id>tag:pseudofish.com,2008-05-18:/haskelldb-performance.html</id><summary type="html">&lt;p&gt;Things did not go well with HaskellDB when I ran my query across a large
data set. MySQL as a query optimizer, sucked. Postgres seems to be doing&amp;nbsp;better.&lt;/p&gt;
&lt;p&gt;I started with a mysql database containing 11 years of day &lt;a href="http://www.float.com.au/scgi-bin/prod/dl.cgi"&gt;data&lt;/a&gt; from
the &lt;span class="caps"&gt;ASX&lt;/span&gt;. This includes the closing price (and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Things did not go well with HaskellDB when I ran my query across a large
data set. MySQL as a query optimizer, sucked. Postgres seems to be doing&amp;nbsp;better.&lt;/p&gt;
&lt;p&gt;I started with a mysql database containing 11 years of day &lt;a href="http://www.float.com.au/scgi-bin/prod/dl.cgi"&gt;data&lt;/a&gt; from
the &lt;span class="caps"&gt;ASX&lt;/span&gt;. This includes the closing price (and some other info) of all
stocks traded on the Australian Stock Exchange (&lt;span class="caps"&gt;ASX&lt;/span&gt;) since&amp;nbsp;1997.&lt;/p&gt;
&lt;p&gt;The tables are organized with unique keys and, based on some testing,
include appropriate indexes.Things still ran&amp;nbsp;slowly.&lt;/p&gt;
&lt;p&gt;I tried &lt;a href="http://www.day32.com/MySQL/"&gt;tuning mysql&lt;/a&gt;. Then, based on the slow queries logged, tried
running them by hand to see if I was missing any indexes. No such luck.
The query just didn&amp;#8217;t&amp;nbsp;perform.&lt;/p&gt;
&lt;p&gt;I simplified the query and ran it again (see below). Now it ran fast,
but doesn&amp;#8217;t help with the generated query. Looks like MySQL&amp;#8217;s optimizer
doesn&amp;#8217;t optimize&amp;nbsp;enough.&lt;/p&gt;
&lt;p&gt;MySQL&amp;nbsp;timing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query 1: &lt;strong&gt;6.25s&lt;/strong&gt; (anywhere from 24s -&amp;nbsp;6s)&lt;/li&gt;
&lt;li&gt;Query 2:&amp;nbsp;0.15s&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next step. Install&amp;nbsp;Postgres.&lt;/p&gt;
&lt;p&gt;Postgres&amp;nbsp;timing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query 1:&amp;nbsp;0.03s&lt;/li&gt;
&lt;li&gt;Query 2:&amp;nbsp;0.03s&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To avoid the cache impacting the results, both servers were stopped and
re-started between each query run. With caching, Postgres gets down to
0.2s. MySQL will still have 6s/0.3s. Tests were run on a MacBook with
2Gb of&amp;nbsp;memory.&lt;/p&gt;
&lt;p&gt;Both queries were run with the command line tool of the respective
database engines, mysql and psql. The end_of_day table has 4,749,025
records and the stock table has 25,863&amp;nbsp;records.&lt;/p&gt;
&lt;p&gt;Query 1 – HaskellDB&amp;nbsp;generated&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;closing_price2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;closing_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="n"&gt;trade_date2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;trade_date&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stock_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stock_id2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;trade_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;trade_date2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;closing_price&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;closing_price2&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end_of_day&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stock_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stock_id1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ticker1&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T2&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stock_id1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stock_id2&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ticker1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;FXJ&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NWS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WAN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;trade_date2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2008-02-14 00:00:00&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Query 2 – Hand&amp;nbsp;written&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;closing_price&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;closing_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trade_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;trade_date&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end_of_day&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stock_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stock_id&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;FXJ&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NWS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WAN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trade_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2008-02-14 00:00:00&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So don&amp;#8217;t use HaskellDB and MySQL if you are doing joins across large
tables. Use Postgres&amp;nbsp;instead.&lt;/p&gt;
&lt;p&gt;The Haskell&amp;nbsp;query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;indexStock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tkrs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stockDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;S&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stock&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;E&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_of_day&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;restrict&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;S&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stock_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.==.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;E&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stock_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&amp;amp;&amp;amp;.&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;S&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;_in&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tickers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&amp;amp;&amp;amp;.&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;E&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trade_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.==.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;constant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stockDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;closing_price&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;E&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;closing_price&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;trade_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;E&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trade_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;tickers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tkrs&lt;/span&gt;
&lt;span class="nf"&gt;rs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;
&lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;\\&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;closing_price&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="haskell"></category></entry></feed>