<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>Tapdancing Goats</title>
	
	<link>http://www.tapdancinggoats.com</link>
	<description>A parfait of physics, Linux, LaTeX, and coding tips large and small.</description>
	<lastBuildDate>Mon, 25 Mar 2013 01:30:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Tapdancinggoats" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="tapdancinggoats" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Haskell Life With Repa Part 2: Parsing Framework</title>
		<link>http://www.tapdancinggoats.com/haskell-life-repa-parsers1.htm</link>
		<comments>http://www.tapdancinggoats.com/haskell-life-repa-parsers1.htm#comments</comments>
		<pubDate>Sun, 09 Dec 2012 05:51:35 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[life]]></category>
		<category><![CDATA[repa]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=1161</guid>
		<description><![CDATA[In the last post, we built a simulator for Conway's Life in Haskell using repa and OpenGL. In this post, I'll build a framework for parsing life patterns from files.]]></description>
			<content:encoded><![CDATA[<div id="attachment_1162" class="wp-caption alignright" style="width: 310px"><a href="http://conwaylife.com/wiki/Gunstar"><img src="http://www.tapdancinggoats.com/wp-content/uploads/2012/12/gunstar.png" alt="Conway&#039;s Life - Gunstar" title="Conway&#039;s Life - Gunstar" width="300" height="300" class="size-full wp-image-1162" /></a><p class="wp-caption-text">Life Pattern - Gunstar</p></div>

<p>In <a href="http://www.tapdancinggoats.com/haskell-life-repa.htm">the last post</a>, we built a simulator for <a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life">Conway&#8217;s Life</a> in <a href="http://haskell.org/">Haskell</a> using <a href="http://hackage.haskell.org/package/repa">repa</a> and OpenGL. The initial life pattern in that implementation was hard coded. In this post, I&#8217;ll build a framework for parsing patterns from files.</p>

<p><span id="more-1161"></span></p>

<p>Broadly, a pattern parser needs to read a set of live cell positions from a file and make those available for the grid initialization. It should also support reading some metadata that is common between different file formats. The <a href="http://conwaylife.com/wiki/Category:File_formats">common file formats</a> are documented on LifeWiki. They all have similar metadata that we can easily support: pattern name, comments or description, and a pattern offset position. The file formats can also define alternate rules for how the cells evolve, but this version won&#8217;t support any rules other than the standard Life.</p>

<p>The grid initializer needs a function that determines if each position in the grid is alive or dead, given a pattern. The type of that function should look something like this:</p>

<p><code></code></p>

<div class="dean_ch" style="white-space: wrap;">isCellLive :: LifePattern -&gt; <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Int"><span class="kw4">Int</span></a>, <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Int"><span class="kw4">Int</span></a><span class="br0">&#41;</span> -&gt; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Bool"><span class="kw4">Bool</span></a></div>

<p></p>

<p>I chose to use a <code>Set</code> that holds the positions of the live cells, so the implementation of this function is just a thin wrapper around <code>Set.member</code> that takes the pattern offset into account. The <code>LifePattern</code> type holds the set and other metadata read from the file.  Look at <a href="https://bitbucket.org/shadwstalkr/repa-life/src/cd69867c9f87/src/LifePattern.hs?at=v0.2.0.0">LifePattern.hs</a> for the full definition.</p>

<p>The next abstraction we can make is converting a file into a <code>LifePattern</code>. All of the formats, except <a href="http://conwaylife.com/wiki/Small_object_format">small object</a>, only have one pattern per file, and each format can be distinguished by the file extension. LifeWiki doesn&#8217;t have many small object format files, so we can ignore those for now and assume one pattern per file. The client of the parsing framework shouldn&#8217;t have to care about file formats, so the API should expose one function which accepts a file path and returns either a pattern or an error. The framework will detect the format automatically and apply the correct parser. Let&#8217;s break that down into a working design.</p>

<p>Given a file name, we need to check if the extension matches each parser. If one of the parsers matches, run it on the file and return the result. The result of applying this process to each parser is encoded in the type <code>PatternParseResult</code>.
<code></code></p>

<div class="dean_ch" style="white-space: wrap;"><span class="kw1">data</span> PatternParseResult = SuccessfulParse LifePattern<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | ParseError <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:String"><span class="kw4">String</span></a> P.ParseError<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | UnknownFormat <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:String"><span class="kw4">String</span></a><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | FileError <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IOException"><span class="kw5">IOException</span></a><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | IncorrectFormat<br />
&nbsp;</div>

<p>
<code>P.ParseError</code> is from <a href="http://hackage.haskell.org/package/parsec"><code>Text.Parsec</code></a>, the parsing library I chose to use.</p>

<p>With a function <code>FilePath -&gt; IO PatternParseResult</code> for each parser, we can easily try each of them and select the first one that evaluates to something other than <code>IncorrectFormat</code>. This is exactly the implementation of the top level file parsing function.
<code></code></p>

<div class="dean_ch" style="white-space: wrap;">parseFile :: FilePath -&gt; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IO"><span class="kw4">IO</span></a> PatternParseResult<br />
parseFile fname = <span class="kw1">do</span><br />
&nbsp; attempts &lt;- <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:mapM"><span class="kw3">mapM</span></a> tryParser parsers<br />
&nbsp; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:return"><span class="kw3">return</span></a> $ <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:foldr"><span class="kw3">foldr</span></a> selectAttempt <span class="br0">&#40;</span>UnknownFormat fname<span class="br0">&#41;</span> attempts<br />
<br />
&nbsp; &nbsp; <span class="kw1">where</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span class="co1">-- | Try to apply the parser. Catch any IOException</span><br />
&nbsp; &nbsp; &nbsp; <span class="co1">-- and convert it to a FileError.</span><br />
&nbsp; &nbsp; &nbsp; tryParser :: <span class="br0">&#40;</span>FilePath -&gt; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IO"><span class="kw4">IO</span></a> PatternParseResult<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -&gt; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IO"><span class="kw4">IO</span></a> PatternParseResult<br />
&nbsp; &nbsp; &nbsp; tryParser parser = parser fname `<a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:catch"><span class="kw3">catch</span></a>` <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:return"><span class="kw3">return</span></a> . FileError<span class="br0">&#41;</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span class="co1">-- | Select the first parser that was run.</span><br />
&nbsp; &nbsp; &nbsp; selectAttempt IncorrectFormat next = next<br />
&nbsp; &nbsp; &nbsp; selectAttempt result _ = result<br />
&nbsp;</div>

<p>
<code>UnknownFormat</code> is the end value in the <code>foldr</code> call, which indicates that no parser could recognize the file.</p>

<p>The function <code>tryParser</code> is mapped over <code>parsers</code>, which is a list generated from each parser along with its name and file extension. Those are passed to a wrapper function that checks the extension, opens the file, runs the parser, and then prints any warnings generated by the parser.
<code></code></p>

<div class="dean_ch" style="white-space: wrap;">makeParser :: <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:String"><span class="kw4">String</span></a>, <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:String"><span class="kw4">String</span></a>, PatternParser T.Text <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IO"><span class="kw4">IO</span></a> LifePattern<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt; FilePath<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IO"><span class="kw4">IO</span></a> PatternParseResult<br />
makeParser <span class="br0">&#40;</span>extension, name, parser<span class="br0">&#41;</span> fname =<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>takeExtension fname<span class="br0">&#41;</span> == extension<br />
&nbsp; &nbsp; <span class="kw1">then</span> <span class="kw1">do</span><br />
&nbsp; &nbsp; &nbsp; contents &lt;- T.<a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:readFile"><span class="kw3">readFile</span></a> fname<br />
&nbsp; &nbsp; &nbsp; result &lt;- parsePatternFile parser fname contents<br />
&nbsp; &nbsp; &nbsp; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:either"><span class="kw3">either</span></a> err success result<br />
<br />
&nbsp; &nbsp; <span class="kw1">else</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:return"><span class="kw3">return</span></a> IncorrectFormat<br />
<br />
&nbsp; &nbsp; <span class="kw1">where</span><br />
&nbsp; &nbsp; &nbsp; err = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:return"><span class="kw3">return</span></a> . ParseError name<br />
<br />
&nbsp; &nbsp; &nbsp; success <span class="br0">&#40;</span>pattern, warnings<span class="br0">&#41;</span> = <span class="kw1">do</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; when <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:not"><span class="kw3">not</span></a> . <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:null"><span class="kw3">null</span></a> $ warnings<span class="br0">&#41;</span> $<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:putStrLn"><span class="kw3">putStrLn</span></a> . <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:unlines"><span class="kw3">unlines</span></a> . <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:map"><span class="kw3">map</span></a> <span class="br0">&#40;</span><span class="st0">&quot;Warning: &quot;</span> ++<span class="br0">&#41;</span> $ warnings<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:return"><span class="kw3">return</span></a> $ SuccessfulParse pattern<br />
&nbsp;</div>

<p>
<code>T.readFile</code> is from the <code>Text</code> library, which is generally more efficient than the <code>String</code> version. The function <code>parsePatternFile</code> is a thin wrapper around Parsec&#8217;s <code>runPT</code> which hides how the parsers report warnings.
<code></code></p>

<div class="dean_ch" style="white-space: wrap;"><span class="kw1">type</span> PatternParser s m = ParsecT s <span class="br0">&#91;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:String"><span class="kw4">String</span></a><span class="br0">&#93;</span> m<br />
<br />
patternWarning :: Stream s m <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Char"><span class="kw4">Char</span></a> =&gt; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:String"><span class="kw4">String</span></a> -&gt; PatternParser s m <span class="br0">&#40;</span><span class="br0">&#41;</span><br />
patternWarning msg = modifyState <span class="br0">&#40;</span>++ <span class="br0">&#91;</span>msg<span class="br0">&#93;</span><span class="br0">&#41;</span><br />
<br />
parsePatternFile :: Stream s m <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Char"><span class="kw4">Char</span></a> =&gt; PatternParser s m LifePattern<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt; FilePath -&gt; s<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt; m <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Either"><span class="kw4">Either</span></a> ParseError <span class="br0">&#40;</span>LifePattern, <span class="br0">&#91;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:String"><span class="kw4">String</span></a><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
parsePatternFile parser fname contents =<br />
&nbsp; &nbsp; runPT parser' <span class="br0">&#91;</span><span class="br0">&#93;</span> fname contents<br />
<br />
&nbsp; &nbsp; <span class="kw1">where</span><br />
&nbsp; &nbsp; &nbsp; parser' = <span class="br0">&#40;</span>,<span class="br0">&#41;</span> &lt;$&gt; parser &lt;*&gt; getState<br />
&nbsp;</div>

<p></p>

<p>That&#8217;s enough for this post. The next installment will look at the parsers for the RLE and plain text formats. Remember, all <a href="https://bitbucket.org/shadwstalkr/repa-life/src/cd69867c9f87?at=v0.2.0.0">the code for this post</a> is available on Bitbucket. Fork it, show me how awesome you can make this.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=koBZM5_Xd1w:M6B6WyTcySk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=koBZM5_Xd1w:M6B6WyTcySk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=koBZM5_Xd1w:M6B6WyTcySk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=koBZM5_Xd1w:M6B6WyTcySk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=koBZM5_Xd1w:M6B6WyTcySk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=koBZM5_Xd1w:M6B6WyTcySk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=koBZM5_Xd1w:M6B6WyTcySk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=koBZM5_Xd1w:M6B6WyTcySk:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/koBZM5_Xd1w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/haskell-life-repa-parsers1.htm/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Conway’s Life in Haskell with Repa and OpenGL</title>
		<link>http://www.tapdancinggoats.com/haskell-life-repa.htm</link>
		<comments>http://www.tapdancinggoats.com/haskell-life-repa.htm#comments</comments>
		<pubDate>Sun, 02 Dec 2012 06:48:55 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[glfw]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[life]]></category>
		<category><![CDATA[opengl]]></category>
		<category><![CDATA[repa]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=1139</guid>
		<description><![CDATA[To learn how to use repa in Haskell, I implemented Conway’s Life using repa for the simulation and OpenGL for the display.]]></description>
			<content:encoded><![CDATA[<div id="attachment_1156" class="wp-caption alignright" style="width: 360px"><a href="http://www.tapdancinggoats.com/haskell-life-repa.htm"><img src="http://www.tapdancinggoats.com/wp-content/uploads/2012/12/Acorn_final.png" alt="Conway&#039;s Life in Haskell" title="Conway&#039;s Life in Haskell" width="350" height="438" class="size-full wp-image-1156" /></a><p class="wp-caption-text">The final state after starting with the acorn pattern</p></div>

<p><a href="http://hackage.haskell.org/package/repa">Repa</a> is a new library in <a href="http://haskell.org/">Haskell</a> for handling arrays. It has flexible indexing like the <a href="http://hackage.haskell.org/package/array/">old array library</a>, but supports parallel computation, stream fusion, and has a rich API like the <a href="http://hackage.haskell.org/package/vector">vector library</a>.</p>

<p>To learn how to use repa, I implemented <a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life">Conway&#8217;s Life</a> using repa for the simulation and OpenGL for the display. The <a href="https://bitbucket.org/shadwstalkr/repa-life/src/021b2a45d413?at=v0.1.0.0">complete code is available on BitBucket</a> and builds on my <a href="http://www.tapdancinggoats.com/opengl-in-haskell-glfw-b-boilerplate.htm">GLFW-b boilterplate</a>, so I&#8217;ll only discuss the interesting parts here. <a href="http://donsbot.wordpress.com/">Don Stewart</a> wrote <a href="http://www.haskell.org/haskellwiki/Numeric_Haskell:_A_Repa_Tutorial">a good introductory tutorial to repa</a> that will fill in any gaps I leave in this post.</p>

<p><span id="more-1139"></span></p>

<h2>Evolution</h2>

<p>We&#8217;ll start with the Life evolution step, because that&#8217;s actually the simplest function in this implementation. I decided to represent the Life grid as a repa array of <code>Word8</code> elements. <code>Boolean</code> elements might seem like a more natural choice, and that&#8217;s what I used in <a href="http://www.tapdancinggoats.com/haskell-life.htm" title="Haskell Life with vectors and Gloss">my first version</a>, but you&#8217;ll see that using bytes makes the evolution step simpler.<sup id="fnref:bit-pack"><a href="#fn:bit-pack" rel="footnote">1</a></sup> The evolution step uses repa&#8217;s <a href="http://www.cse.unsw.edu.au/~benl/papers/stencil/stencil-icfp2011-sub.pdf">stencil convolution</a> support, which can turn small, static convolution kernels into fast code.</p>

<p><code></code></p>

<div class="dean_ch" style="white-space: wrap;"><span class="kw1">type</span> Grid = A.Array A.U A.DIM2 A.Word8<br />
<br />
updateGrid :: Grid -&gt; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IO"><span class="kw4">IO</span></a> Grid<br />
updateGrid = A.computeP<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;. A.smap step<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;. mapStencil2 <span class="br0">&#40;</span>A.BoundConst 0x20<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#91;</span>stencil2| <span class="nu0">1</span> &nbsp;<span class="nu0">1</span> &nbsp;<span class="nu0">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">1</span> <span class="nu0">16</span> &nbsp;<span class="nu0">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">1</span> &nbsp;<span class="nu0">1</span> &nbsp;<span class="nu0">1</span> |<span class="br0">&#93;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">where</span><br />
&nbsp; &nbsp; &nbsp; <span class="coMULTI">{-# INLINE step #-}</span><br />
&nbsp; &nbsp; &nbsp; step x<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | x == <span class="br0">&#40;</span><span class="nu0">16</span> .|. <span class="nu0">2</span><span class="br0">&#41;</span> = <span class="nu0">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <span class="br0">&#40;</span>x .&amp;. 0xF<span class="br0">&#41;</span> == <span class="nu0">3</span> = <span class="nu0">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:otherwise"><span class="kw3">otherwise</span></a> = <span class="nu0">0</span><br />
&nbsp;</div>

<p></p>

<p>Here is how the evolution step works. In the Life grid, a dead cell is 0 and a live cell is 1, so the convolution counts the adjacent live cells and adds 16 if the current cell was alive in the previous generation. Then we map over the results of the convolution and apply Conway&#8217;s rules in the step function: 3 live neighbors brings the cell to life, 2 live neighbors makes no change, any other number kills the cell.</p>

<p>The convolution and map generate a &#8220;delayed&#8221; array. A delayed array is just a function that maps from an index to a value. This is good if we&#8217;re only accessing a few elements, but if the elements are accessed several times they have to be recalculated. Instead, we can calculate the whole thing to generate a &#8220;manifest&#8221; array with either the <code>computeS</code> or <code>computeP</code> functions. The suffix describes the calculation strategy: <code>S</code> means serial and <code>P</code> means parallel. You might notice that <code>computeP</code> is monadic. Repa doesn&#8217;t support nested parallel computations, so to make sure each parallel calculation is complete before the next one starts, the parallel versions of repa&#8217;s calculation functions are monadic.</p>

<p>The stencil code is a little strange, so let&#8217;s take a closer look at it.
<code></code></p>

<div class="dean_ch" style="white-space: wrap;">mapStencil2 <span class="br0">&#40;</span>A.BoundConst 0x20<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#91;</span>stencil2| <span class="nu0">1</span> &nbsp;<span class="nu0">1</span> &nbsp;<span class="nu0">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">1</span> <span class="nu0">16</span> &nbsp;<span class="nu0">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">1</span> &nbsp;<span class="nu0">1</span> &nbsp;<span class="nu0">1</span> |<span class="br0">&#93;</span><br />
&nbsp;</div>

<p>
The last construction there between the brackets is actually <a href="http://www.haskell.org/haskellwiki/Template_Haskell">template Haskell</a> that is evaluated at compile time to generate Haskell code. This requires the language pragma <code>QuasiQuotes</code> (if you don&#8217;t understand that, look at the top of the source file), and we have to make sure that the names in the package <code>Data.Array.Repa.Stencil.Dim2</code> are visible. That means that package can&#8217;t be imported qualified. The repa index constructor also has to be visible; since we import <code>Data.Array.Repa</code> qualified we need this import line
<code></code></p>

<div class="dean_ch" style="white-space: wrap;"><span class="kw1">import</span> Data.Array.Repa <span class="br0">&#40;</span><span class="br0">&#40;</span>:.<span class="br0">&#41;</span> <span class="br0">&#40;</span>..<span class="br0">&#41;</span><span class="br0">&#41;</span></div>

<p>
It&#8217;s strange because it looks like an operator but it&#8217;s actually a data constructor.</p>

<p>The other argument to the <code>mapStencil2</code> function is how to treat boundary values. There are three options here.</p>

<dl>
<dt>BoundFixed a</dt>
<dd>This option will make the entire border area a constant value. The border area is half the size
of the convolution kernel.</dd>

<dt>BoundConst a</dt>
<dd>This option uses the constant value for all locations <em>outside</em> the array.</dd>

<dt>BoundClamp</dt>
<dd>This basically repeats the edge values as far as necessary.</dd>
</dl>

<p>I used <code>BoundConst</code> here to use a special value for locations outside the grid. This way, cells will always die when they get to the edge. It would be better to expand the grid one cell in each direction outside the view so that it appears infinite. That will be easier to do after I switch to shaders for the rendering, so I&#8217;ll address that in a later post.</p>

<h2>Grid Initialization</h2>

<p>Here is the function that creates a new grid when the program starts.
<code></code></p>

<div class="dean_ch" style="white-space: wrap;">freshGrid :: <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Int"><span class="kw4">Int</span></a> -&gt; Grid<br />
freshGrid gridSize =<br />
&nbsp; &nbsp; A.computeS . A.fromFunction <span class="br0">&#40;</span>A.Z :. gridSize :. gridSize<span class="br0">&#41;</span> $ initCell<br />
<br />
&nbsp; &nbsp; <span class="kw1">where</span><br />
&nbsp; &nbsp; &nbsp; cx = gridSize `<a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:div"><span class="kw3">div</span></a>` <span class="nu0">2</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span class="co1">-- | Initialize a grid cell. Guards are used</span><br />
&nbsp; &nbsp; &nbsp; <span class="co1">-- &nbsp; to make the initial pattern.</span><br />
&nbsp; &nbsp; &nbsp; initCell ix<br />
<br />
<span class="coMULTI">{- Blinker -}</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | ix == <span class="br0">&#40;</span>A.Z :. cx :. cx<span class="br0">&#41;</span> = <span class="nu0">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | ix == <span class="br0">&#40;</span>A.Z :. cx<span class="nu0">-1</span> :. cx<span class="br0">&#41;</span> = <span class="nu0">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | ix == <span class="br0">&#40;</span>A.Z :. cx<span class="nu0">+1</span> :. cx<span class="br0">&#41;</span> = <span class="nu0">1</span><br />
&nbsp;</div>

<p>
First it creates a delayed array with <code>A.fromFunction</code>, then calculates it into a manifest array with <code>A.computeS</code>. The function is a mapping from array index to value. Repa indices are created with the special constructors <code>Z</code> and <code>:.</code>. I&#8217;m using <code>Int</code>s for the index types, but repa supports indices of any type.</p>

<p>The initialization function is implemented using guards to poke some live cells into an initial pattern. This one is a blinker, and there is code for an acorn in the full source. A much better solution would be to accept a file containing the initial pattern. Supporting one or all of the formats on the <a href="http://conwaylife.com/wiki/Main_Page">Conway Life Wiki</a> would open a vast catalog to us. Another option would be allowing the user to draw a pattern in the screen before starting the simulation. I&#8217;ll cover both of these in later posts. [Update: There is now a series of posts about the <a href="http://www.tapdancinggoats.com/haskell-life-repa-parsers1.htm">life pattern file parsers</a>]</p>

<h2>Rendering</h2>

<p>The view is pretty straightforward. In each frame, I write the grid to a grayscale texture and draw it on a quad. Unboxed repa arrays use unboxed vectors underneath, so the grid is easily converted to a storable vector which can be dumped to texture memory. The only trick here is padding the array to a power of two width. Modern graphics cards are supposed to handle textures with off dimensions, but I have a cheap mobile Intel GPU that freaks out when I give it an off-size texture. Look at the source for all the details, but this is the important bit that uses traverse to copy the array into a bigger array.
<code></code></p>

<div class="dean_ch" style="white-space: wrap;">draw grid = <span class="kw1">do</span><br />
<span class="coMULTI">{- ... -}</span><br />
&nbsp; &nbsp; <span class="kw1">where</span><br />
&nbsp; &nbsp; &nbsp; gridShape@<span class="br0">&#40;</span>A.Z :. width :. height<span class="br0">&#41;</span> = A.extent grid<br />
&nbsp; &nbsp; &nbsp; maxS = nextPowerOf2 width<br />
&nbsp; &nbsp; &nbsp; maxT = nextPowerOf2 height<br />
<br />
&nbsp; &nbsp; &nbsp; pad ar = A.traverse ar<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:const"><span class="kw3">const</span></a> <span class="br0">&#40;</span>A.Z :. <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:fromIntegral"><span class="kw3">fromIntegral</span></a> maxS<span class="br0">&#41;</span> :. <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:fromIntegral"><span class="kw3">fromIntegral</span></a> maxT<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$ \lkup ix -&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">if</span> A.inShape gridShape ix<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">then</span> lkup ix<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">else</span> <span class="nu0">0</span><br />
&nbsp;</div>

<p></p>

<h2>Performance</h2>

<p>At first I thought this would have pretty terrible performance. Each frame is allocating several new arrays for the evolution and the conversion steps to the texture buffer. I thought I would need to rewrite this using mutable vectors to avoid allocations. However, when I ran it with the stats on (<code>+RTS -s</code>) the garbage collector hardly ever runs (only once in several thousand generations) and the program runs in constant space. Thanks to repa, the code is already parallelized and takes advantage of multiple cores (run it with <code>+RTS -NX</code> where X is the number of cores to use).</p>

<p>In the future I want to convert the rendering to use shaders. This will simplify the texturing step since the grayscale conversion can be done in the fragment shader. It will also fix the boundary issue, since I&#8217;ll be able to expand the grid to a power of two and only render a section.</p>

<p>Take a look at <a href="https://bitbucket.org/shadwstalkr/repa-life/src/021b2a45d413?at=v0.1.0.0">the full source</a>, fork it and improve it! What would you like to see next in my Haskell experiments? Let me know in the comments or on twitter.</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:bit-pack">
<p>The current implementation of repa doesn&#8217;t bit pack a bool array, so there is no real advantage to using <code>Boolean</code> elements anyway.&#160;<a href="#fnref:bit-pack" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=N0b1SYJSUWU:bEi83z1_-kw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=N0b1SYJSUWU:bEi83z1_-kw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=N0b1SYJSUWU:bEi83z1_-kw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=N0b1SYJSUWU:bEi83z1_-kw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=N0b1SYJSUWU:bEi83z1_-kw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=N0b1SYJSUWU:bEi83z1_-kw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=N0b1SYJSUWU:bEi83z1_-kw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=N0b1SYJSUWU:bEi83z1_-kw:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/N0b1SYJSUWU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/haskell-life-repa.htm/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>OpenGL in Haskell: GLFW-b Boilerplate</title>
		<link>http://www.tapdancinggoats.com/opengl-in-haskell-glfw-b-boilerplate.htm</link>
		<comments>http://www.tapdancinggoats.com/opengl-in-haskell-glfw-b-boilerplate.htm#comments</comments>
		<pubDate>Thu, 29 Nov 2012 05:33:03 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[glfw]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[opengl]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=1118</guid>
		<description><![CDATA[Haskell is turning out to be a great match for OpenGL. This is some boilerplate code for setting up GLFW-b and running a main loop.]]></description>
			<content:encoded><![CDATA[<p>Haskell is turning out to be a great match for OpenGL. Since we can
offload a lot of the rendering to shader code, we can use mostly pure
Haskell functions to update the game or simulation in response to user
input. Over a few blog posts, I&#8217;m going to outline how I&#8217;ve been using
OpenGL in Haskell.</p>

<p>First, to use OpenGL we need a way to open a window, get a context, and
respond to user input. There are several different cross-platform
libraries to do this, but for simple projects I prefer
<a href="http://www.glfw.org/">GLFW</a>. The Haskell package
<a href="http://hackage.haskell.org/package/GLFW-b">GLFW-b</a> has bindings for
GLFW and exposes a more Haskellish API than the regular GLFW package.
<span id="more-1118"></span></p>

<p>This is some boilerplate code for setting up GLFW-b and running a main
loop. It will open a window and draw a rotating square. There are
inline comments explaining what is going on, but here is a summary of
the main points.</p>

<ul>
<li>GLFW-b lets us run our own main loop instead of requiring us to use
callbacks like GLUT. However, there are still callbacks available
for some things. The only one we&#8217;ll use is the window resize
callback. We&#8217;ll use this to set the projection matrix and viewport
when the window changes size.</li>
<li>The rough procedure for using GLFW-b is

<ol>
<li>Call initialize</li>
<li>Call openWindow with our window options. Start with
defaultDisplayOptions and set what we care about. Remember to set
num*Bits if you want color.</li>
<li>Set the window size callback with setWindowSizeCallback</li>
<li>Run our loop, calling swapBuffers after every frame</li>
<li>Call closeWindow</li>
<li>Call terminate</li>
</ol></li>
<li>We can use <code>finally</code> to make sure that GLFW-b is terminated properly
no matter how our main loop exits.</li>
<li>Calling swapBuffers polls for input, so inside our main loop we can
use the GLFW-b input functions like <code>keyIsPressed</code>. We&#8217;ll also check
<code>windowIsOpen</code> to exit the main loop when the window closes.</li>
</ul>

<p><code></code></p>

<div class="dean_ch" style="white-space: wrap;"><span class="kw1">import</span> Control.Concurrent <span class="br0">&#40;</span>threadDelay<span class="br0">&#41;</span><br />
<span class="kw1">import</span> Control.Exception<br />
<span class="kw1">import</span> Control.<a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Monad"><span class="kw4">Monad</span></a><br />
<span class="kw1">import</span> <span class="kw1">qualified</span> Graphics.Rendering.OpenGL <span class="kw1">as</span> GL<br />
<span class="kw1">import</span> Graphics.Rendering.OpenGL <span class="br0">&#40;</span><span class="br0">&#40;</span>$=<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
<span class="kw1">import</span> <span class="kw1">qualified</span> Graphics.UI.GLFW <span class="kw1">as</span> GLFW<br />
<span class="kw1">import</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html"><span class="kw2">Prelude</span></a> <span class="kw1">hiding</span> <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:catch"><span class="kw3">catch</span></a><span class="br0">&#41;</span><br />
<br />
main = <span class="kw1">do</span><br />
&nbsp; <span class="co1">-- initialize has to come first. If it doesn't return True,</span><br />
&nbsp; <span class="co1">-- this crashes with a pattern match error.</span><br />
&nbsp; True &lt;- GLFW.initialize<br />
&nbsp; <br />
&nbsp; <span class="co1">-- Set the RGB bits to get a color window.</span><br />
&nbsp; <span class="co1">-- See the GLFW-b docs for all the options</span><br />
&nbsp; True &lt;- GLFW.openWindow GLFW.defaultDisplayOptions<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span> GLFW.displayOptions_numRedBits = <span class="nu0">8</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , GLFW.displayOptions_numGreenBits = <span class="nu0">8</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , GLFW.displayOptions_numBlueBits = <span class="nu0">8</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , GLFW.displayOptions_numDepthBits = <span class="nu0">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , GLFW.displayOptions_width = <span class="nu0">640</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , GLFW.displayOptions_height = <span class="nu0">480</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; GLFW.setWindowSizeCallback $ resize<br />
<br />
&nbsp; <span class="co1">-- Use `$=` for assigning to GL values, `get` to read them.</span><br />
&nbsp; <span class="co1">-- These functions basically hide IORefs.</span><br />
&nbsp; <br />
&nbsp; GL.depthFunc $= Just GL.Less<br />
<br />
&nbsp; <span class="co1">-- Use `finally` so that `quit` is called whether or</span><br />
&nbsp; <span class="co1">-- not `mainLoop` throws an exception</span><br />
&nbsp; finally mainLoop quit<br />
<br />
<span class="co1">-- | Resize the viewport and set the projection matrix</span><br />
resize w h = <span class="kw1">do</span><br />
&nbsp; <span class="co1">-- These are all analogous to the standard OpenGL functions</span><br />
&nbsp; GL.viewport $= <span class="br0">&#40;</span>GL.Position <span class="nu0">0</span> <span class="nu0">0</span>, GL.Size <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:fromIntegral"><span class="kw3">fromIntegral</span></a> w<span class="br0">&#41;</span> <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:fromIntegral"><span class="kw3">fromIntegral</span></a> h<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; GL.matrixMode $= GL.Projection<br />
&nbsp; GL.loadIdentity<br />
&nbsp; GL.perspective <span class="nu0">45</span> <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:fromIntegral"><span class="kw3">fromIntegral</span></a> w / <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:fromIntegral"><span class="kw3">fromIntegral</span></a> h<span class="br0">&#41;</span> <span class="nu0">1</span> <span class="nu0">100</span><br />
&nbsp; GL.matrixMode $= GL.Modelview <span class="nu0">0</span><br />
<br />
<span class="co1">-- | Close the window and terminate GLFW</span><br />
quit = GLFW.closeWindow &gt;&gt; GLFW.terminate<br />
<br />
<span class="co1">-- | This will print and clear the OpenGL errors</span><br />
printErrors = GL.get GL.errors &gt;&gt;= <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:mapM_"><span class="kw3">mapM_</span></a> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:print"><span class="kw3">print</span></a><br />
<br />
<span class="co1">-- | Draw the window and handle input</span><br />
mainLoop = <span class="kw1">do</span><br />
&nbsp; now &lt;- GLFW.getTime<br />
&nbsp; draw now<br />
<br />
&nbsp; <span class="co1">-- Input is polled each time swapBuffers is called</span><br />
&nbsp; esc &lt;- GLFW.keyIsPressed GLFW.KeyEsc<br />
&nbsp; isClosed &lt;- <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:fmap"><span class="kw3">fmap</span></a> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:not"><span class="kw3">not</span></a> GLFW.windowIsOpen<br />
&nbsp; unless <span class="br0">&#40;</span>esc || isClosed<span class="br0">&#41;</span> $ <span class="kw1">do</span><br />
&nbsp; &nbsp; <span class="co1">-- Sleep for the rest of the frame</span><br />
&nbsp; &nbsp; frameLeft &lt;- <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:fmap"><span class="kw3">fmap</span></a> <span class="br0">&#40;</span>spf + now -<span class="br0">&#41;</span> GLFW.getTime<br />
&nbsp; &nbsp; when <span class="br0">&#40;</span>frameLeft &gt; <span class="nu0">0</span><span class="br0">&#41;</span> $<br />
&nbsp; &nbsp; &nbsp; &nbsp; threadDelay <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:truncate"><span class="kw3">truncate</span></a> $ <span class="nu0">1000000</span> * frameLeft<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; mainLoop<br />
<br />
&nbsp; <span class="kw1">where</span><br />
&nbsp; &nbsp; <span class="co1">-- maximum frame rate</span><br />
&nbsp; &nbsp; fps = <span class="nu0">60</span><br />
&nbsp; &nbsp; spf = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:recip"><span class="kw3">recip</span></a> fps<br />
<br />
<span class="co1">-- | Draw a frame</span><br />
draw :: <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Double"><span class="kw4">Double</span></a> -&gt; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IO"><span class="kw4">IO</span></a> <span class="br0">&#40;</span><span class="br0">&#41;</span><br />
draw t = <span class="kw1">do</span><br />
&nbsp; <span class="co1">-- Again, the functions in GL almost all map to standard OpenGL functions</span><br />
&nbsp; GL.clear <span class="br0">&#91;</span>GL.ColorBuffer, GL.DepthBuffer<span class="br0">&#93;</span><br />
<br />
&nbsp; GL.loadIdentity<br />
&nbsp; GL.translate $ GL.Vector3 <span class="nu0">0</span> <span class="nu0">0</span> <span class="br0">&#40;</span><span class="nu0">-50</span> :: GL.GLfloat<span class="br0">&#41;</span><br />
&nbsp; GL.scale <span class="nu0">10</span> <span class="nu0">10</span> <span class="br0">&#40;</span><span class="nu0">1</span> :: GL.GLfloat<span class="br0">&#41;</span><br />
&nbsp; GL.rotate theta axis<br />
<br />
&nbsp; <span class="co1">-- renderPrimitive wraps the supplied action with glBegin and glEnd.</span><br />
&nbsp; <span class="co1">-- We'll stop using this when we switch to shaders and vertex buffers.</span><br />
&nbsp; GL.renderPrimitive GL.Quads $<br />
&nbsp; &nbsp; <span class="co1">-- Draw a unit square centered on the origin</span><br />
&nbsp; &nbsp; forM_ <span class="br0">&#91;</span><span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">0</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">0</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">1</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#93;</span> $ \<span class="br0">&#40;</span>x, y<span class="br0">&#41;</span> -&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">-- Note that we have to explicitly type Vertex* and Vector*, because</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">-- they are polymorphic in number field.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> vtx = GL.Vertex3 <span class="br0">&#40;</span>x - <span class="nu0">0.5</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>y - <span class="nu0">0.5</span><span class="br0">&#41;</span> <span class="nu0">0</span> :: GL.Vertex3 GL.GLfloat<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">in</span> GL.vertex vtx<br />
<br />
&nbsp; printErrors<br />
&nbsp; GL.flush<br />
&nbsp; GLFW.swapBuffers<br />
<br />
&nbsp; &nbsp; <span class="kw1">where</span><br />
&nbsp; &nbsp; &nbsp; <span class="co1">-- GL.rotate takes the angle in degrees, not radians</span><br />
&nbsp; &nbsp; &nbsp; theta = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:realToFrac"><span class="kw3">realToFrac</span></a> t * <span class="nu0">360</span><br />
&nbsp; &nbsp; &nbsp; axis = GL.Vector3 <span class="nu0">0</span> <span class="nu0">1</span> <span class="nu0">0</span> :: GL.Vector3 GL.GLfloat<br />
&nbsp;</div>

<p></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=tL0YrDA7bKM:dozAn7WpTMc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=tL0YrDA7bKM:dozAn7WpTMc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=tL0YrDA7bKM:dozAn7WpTMc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=tL0YrDA7bKM:dozAn7WpTMc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=tL0YrDA7bKM:dozAn7WpTMc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=tL0YrDA7bKM:dozAn7WpTMc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=tL0YrDA7bKM:dozAn7WpTMc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=tL0YrDA7bKM:dozAn7WpTMc:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/tL0YrDA7bKM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/opengl-in-haskell-glfw-b-boilerplate.htm/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How To Configure Onion Skinning in GAP</title>
		<link>http://www.tapdancinggoats.com/how-to-configure-onion-skin-gap.htm</link>
		<comments>http://www.tapdancinggoats.com/how-to-configure-onion-skin-gap.htm#comments</comments>
		<pubDate>Wed, 24 Oct 2012 14:30:28 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[OSS]]></category>
		<category><![CDATA[animation]]></category>
		<category><![CDATA[GAP]]></category>
		<category><![CDATA[gimp]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=1101</guid>
		<description><![CDATA[Learn how to configure onion skinning in GAP (Gimp Animation Package)]]></description>
			<content:encoded><![CDATA[<p>The Gimp Animation Package, or GAP, is a plugin that lets you do video or animation in Gimp.  Like most plugins in Gimp, it is both very powerful and very unfriendly.  If you have done animation in a program like Flash, you are used to having frames laid out along a visual timeline.  The timeline in Flash has a bracket to show the <a href="http://en.wikipedia.org/wiki/Onion_skinning">onionskin range</a>, which is the frames you will see overlaid on the current frame to help create a smooth animation.</p>

<p>None of this is readily apparent in GAP.  Each frame is a separate Gimp file, and GAP sees that they&#8217;re part of the same animation because the file names end with successive numbers.  There is an onion skinning item in the GAP menu (cleverly disguised as <strong>Video</strong>), but it doesn&#8217;t seem to do anything until you configure it correctly.</p>

<p>To configure onion skinning in GAP, go to <strong>Video</strong> &raquo; <strong>Onionskin</strong> &raquo; <strong>Configuration&#8230;</strong>.  The onionskin configuration in GAP is exquisitely flexible and confusing.  Here is how to configure onion skinning in GAP for a couple of common scenarios.  Note that I&#8217;m using Gimp 2.8.2.
<span id="more-1101"></span></p>

<h3>Overlay the previous frame</h3>

<div id="attachment_1102" class="wp-caption alignright" style="width: 310px"><a href="http://www.tapdancinggoats.com/wp-content/uploads/2012/10/onionskin1.png"><img src="http://www.tapdancinggoats.com/wp-content/uploads/2012/10/onionskin1-300x214.png" alt="GAP onionskin configuration for seeing one frame through the previous frame" title="GAP onionskin configuration for seeing one frame through the previous frame" width="300" height="214" class="size-medium wp-image-1102" /></a><p class="wp-caption-text">GAP onionskin configuration for seeing one frame through the previous frame</p></div>

<p>With onion skinning configured this way GAP will put the previous frame on top of the current frame, but with lowered opacity, and it will wrap around at the first frame.  This can be useful to draw keyframes as you&#8217;re building an animation cycle.</p>

<ul>
<li><strong>Reference Mode</strong> Tells GAP how to select frames for the onion skin.  This parameter doesn&#8217;t matter when we&#8217;re only using one frame.  With more than one frame, it works with the <strong>Frame Reference</strong> parameter to make the list of frames that become onionskin layers.</li>
<li><strong>Onionskin Layers</strong> How many frames to use in the onionskin stack. Here we want to use one.</li>
<li><strong>Ascending Opacity</strong> If this is checked, the frame that is farthest from the current frame will be most opaque.</li>
<li><strong>Frame Reference</strong> This number multiplied by the sequence in <strong>Reference Mode</strong> gives the offsets to the frames in the onionskin layers.  For example, using bidirectional double mode with a frame reference of -1, the first onionskin layer is the previous frame, the second onionskin layer would be the next frame, the third would be -2 (the second previous frame, etc.).</li>
<li><strong>Cyclic</strong> If this is checked the onionskin layers wrap around at the ends of the frame stack.</li>
<li><strong>Stackposition</strong> This is where to put the onionskin layers.  We&#8217;re telling GAP to put the onionskin layers at the very top.  Changing this might be useful if you&#8217;re animating a layer in the middle of your stack.</li>
<li><strong>Opacity</strong> The first number is the opacity of the first onionskin layer.  The second number is multiplied into the opacity for each successive onionskin layer.  So with our settings the second onionskin layer would have opacity <code>0.70 * 0.50 = 0.35</code>, the third would have opacity <code>0.70 * 0.50 * 0.50 = 0.175</code>, and so on.</li>
<li><strong>Layer Selection</strong> This can be used to only use certain layers in each frame for onion skinning.  The settings shown will use the entire frame.</li>
<li><strong>Auto create/delete</strong> Check these so that the onionskin layers don&#8217;t show up in thumbnails.  This is useful when using the GAP animation preview tools, but remember that you still have to delete the onion skin layers before exporting the animation or saving a frame.</li>
</ul>

<h3>Overlay the previous and following frames</h3>

<div id="attachment_1109" class="wp-caption alignright" style="width: 310px"><a href="http://www.tapdancinggoats.com/wp-content/uploads/2012/10/onionskin2.png"><img src="http://www.tapdancinggoats.com/wp-content/uploads/2012/10/onionskin2-300x214.png" alt="GAP onionskin configuration for in-between drawing" title="GAP onionskin configuration for in-between drawing" width="300" height="214" class="size-medium wp-image-1109" /></a><p class="wp-caption-text">GAP onionskin configuration for in-between drawing</p></div>

<p>This onion skinning configuration will let you see the current frame through the two surrounding frames. This is useful for drawing in-between frames to make a smooth animation.  You can see that the only change required from the previous settings are to use two onionskin layers.  This gets the previous frame and the next frame.  If you need more frames to draw your tween, just use more onionskin layers.</p>

<p>When I&#8217;m drawing tween frames, I often need to adjust the opacity on the onionskin layers.  You can directly change the opacity on these layers as you would with normal Gimp layers.  The next time you change frames, the new onionskin layers will be created with the opacity from the onionskin configuration.</p>

<p>I hope this helps explain how to configure onion skinning in GAP, and makes some of these options less confusing.  I&#8217;d love to see some of the animations you make with this, so share in the comments or <a href="http://twitter.com/amijlee">hit me on twitter</a>!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=xLgVmPAfPNo:gO82OX3Drt8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=xLgVmPAfPNo:gO82OX3Drt8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=xLgVmPAfPNo:gO82OX3Drt8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=xLgVmPAfPNo:gO82OX3Drt8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=xLgVmPAfPNo:gO82OX3Drt8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=xLgVmPAfPNo:gO82OX3Drt8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=xLgVmPAfPNo:gO82OX3Drt8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=xLgVmPAfPNo:gO82OX3Drt8:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/xLgVmPAfPNo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/how-to-configure-onion-skin-gap.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Five Great Reasons to Blog Lists</title>
		<link>http://www.tapdancinggoats.com/five-great-reasons-to-blog-lists.htm</link>
		<comments>http://www.tapdancinggoats.com/five-great-reasons-to-blog-lists.htm#comments</comments>
		<pubDate>Wed, 19 Sep 2012 02:04:52 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Humor]]></category>
		<category><![CDATA[Lists]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[writing]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=1063</guid>
		<description><![CDATA[So you&#8217;re trying to make money blogging? Want to be a pro blogger? Here are five great reasons why you should write all of your blog posts as lists. 1. Laziness Let&#8217;s assume that you&#8217;ve done your research and you know a lot about your topic. My high school English teacher wanted us to write [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1073" class="wp-caption alignright" style="width: 160px"><a href="http://www.tapdancinggoats.com/five-great-reasons-to-blog-lists.htm"><img class="size-full wp-image-1073   " title="Shopping List" src="http://www.tapdancinggoats.com/wp-content/uploads/2012/09/list_ex-smith.jpg" alt="" width="150" height="240" /></a><p class="wp-caption-text">Source: Flickr user Ex-Smith</p></div>

<p>So you&#8217;re trying to make money blogging? Want to be a pro blogger?  Here are five great reasons why you should write all of your blog posts as lists.</p>

<p><span id="more-1063"></span></p>

<h2>1. Laziness</h2>

<p>Let&#8217;s assume that you&#8217;ve done your research and you know a lot about your topic.  My high school English teacher wanted us to write research papers by writing each fact we learned an a 3&#215;5 card.  Then, we could experiment with arranging the facts in different ways.  The hardest part, of course, was writing the transitions and synthesizing all those facts into an interesting, cohesive narrative.</p>

<p>Let&#8217;s face it, organizing information into a coherent 500 word essay is hard work, and most of us couldn&#8217;t even do it in high school.  Now you&#8217;re competing with every literate person in the developed world, and <a href="http://www.paulgraham.com/essay.html">the five paragraph form you learned never really worked in the first place</a>.  So why bother with synthesis and transitions?  Just dump all the facts you&#8217;ve learned into a numbered list and let your readers put it together!</p>

<h2>2. Nobody Reads Anyway</h2>

<p>The average American <a href="http://en.wikipedia.org/wiki/Literacy_in_the_United_States">reads at an 8th grade level</a>, so all your fancy prose is lost on the proles anyway.  Readers are so distracted and overloaded with information these days, no one wants to commit to even the most beautifully written wall of text.  I&#8217;ve checked twitter three times already while I was writing this.</p>

<p>Most people will scan through the bold headings in your article, pick out a few words from the body, and decide whether or not to share it.  Using the list format gives your article a natural set of headings that should stand on their own.  For bonus link-bait, follow the lead of major news organizations: write misleading headlines that grab attention but don&#8217;t accurately describe the content.</p>

<h2>3. Numbers Conveniently Label Content for Sharing</h2>

<p>Paragraphs aren&#8217;t clear on websites, especially when the text is flowed around images or pull quotes.  Counting paragraphs manually is a pain, and you look like an elitist prick pointing out a paragraph by number.  <a href="http://www.scripting.com">Dave Winer</a> uses custom blog software that creates a hyperlink for each paragraph, but, since no one has stolen the idea, I don&#8217;t think anyone understands or uses them.</p>

<p>By writing list items, you&#8217;re giving your readers clear labels to point out different sections of text.  When they share your blog post, your readers will be able to point out exactly what they liked by saying, &#8220;OMG #4 is LOLZ!!1!&#8221;  Classy.</p>

<h2>4. Mix N&#8217; Match</h2>

<p>Since you&#8217;re not wasting time analyzing and synthesizing your ideas, each list item can probably stand on its own without much context.  This is your opportunity to work smarter (not harder!) by reusing items from old lists to create new ones.  So you wrote the barn burner, &#8220;7 Killer Trout Flies,&#8221; and you crushed it with, &#8220;5 Secret Fly Fishing Techniques.&#8221;  Now just pick out the ten best items, and bam! You&#8217;ve got, &#8220;10 Tips for Trout Fly Fishing!&#8221;</p>

<p>Reusing content is a classic trick of pro bloggers, but you have to be careful about overdoing it.  Search engines have developed algorithms to punish content that is copied to too many pages, so pros have come up with techniques to create syntactically distinct articles while retaining the semantic meaning.  There is even a whole market of tools they use to &#8220;spin&#8221; articles, which mainly consists of replacing common adjectives with synonyms.</p>

<h2>5. Brainstorm to Blog in One Easy Step!</h2>

<p>To make money writing a blog you have to post a lot, and each post has to be long enough and have the right keywords to rank well.  Coming up with all those ideas and writing all that content is hard work, even <a href="http://billrice.com/simple-blog-writing-framework/">with a template</a>.</p>

<p>Using lists can cut down some of that work.  If you have an idea for a topic you want to write about, start by making a list of everything that comes to mind about the topic.  Pick out the most compelling, punchiest items in your list and expand on them.  Add an introduction, some links and images, and you&#8217;re done!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=GuiLzpDSPTM:fnL7AOISXl4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=GuiLzpDSPTM:fnL7AOISXl4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=GuiLzpDSPTM:fnL7AOISXl4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=GuiLzpDSPTM:fnL7AOISXl4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=GuiLzpDSPTM:fnL7AOISXl4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=GuiLzpDSPTM:fnL7AOISXl4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=GuiLzpDSPTM:fnL7AOISXl4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=GuiLzpDSPTM:fnL7AOISXl4:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/GuiLzpDSPTM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/five-great-reasons-to-blog-lists.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Psychobilly Sampler</title>
		<link>http://www.tapdancinggoats.com/psychobilly-sampler.htm</link>
		<comments>http://www.tapdancinggoats.com/psychobilly-sampler.htm#comments</comments>
		<pubDate>Fri, 20 Jul 2012 15:00:21 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Music]]></category>
		<category><![CDATA[music sampler]]></category>
		<category><![CDATA[psychobilly]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=1052</guid>
		<description><![CDATA[I&#8217;ve been really getting into psychobilly over the last few months. Psychobilly is kind of punked up rockabilly or Western swing. There&#8217;s a huge variety in the sounds across the genre, from straight rockabilly to 50&#8242;s horror homage, but the bands all seem to be having a ton of fun. They don&#8217;t have a chance [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been really getting into <a href="http://en.wikipedia.org/wiki/Psychobilly">psychobilly</a> over the last few months.  Psychobilly is kind of punked up rockabilly or Western swing.  There&#8217;s a huge variety in the sounds across the genre, from straight rockabilly to 50&#8242;s horror homage, but the bands all seem to be having a ton of fun.  They don&#8217;t have a chance to get big and let fame and money sap the band&#8217;s spirit, since it&#8217;s such a niche genre.</p>

<p>To help you get started, here is a sampler of some representative psychobilly music.  I included <a href="http://www.reverendhortonheat.com/">Reverend Horton Heat</a>, <a href="http://www.madsin.de/">Mad Sin</a>, <a href="http://www.tigerarmy.com/">Tiger Army</a>, <a href="http://en.wikipedia.org/wiki/Nekromantix">Nekromantix</a>, <a href="http://en.wikipedia.org/wiki/Mano_Negra">Mano Negra</a>, <a href="http://www.facebook.com/pages/Mad-Marge-and-the-Stonecutters/194903736718">Mad Marge And The Stonecutters</a>, <a href="http://en.wikipedia.org/wiki/Horrorpops">Horrorpops</a>, <a href="http://www.goddamngallows.com/">The Goddamn Gallows</a>, and <a href="http://www.facebook.com/pages/Hillbilly-Hellcats/210370150485">Hillbilly Hellcats</a>.  I wrote comments on each track, hover your mouse on them to see.</p>

<p><span id="more-1052"></span></p>

<p>If you like what you hear, be sure to buy the albums. (this is an affiliate link)</p>

<div class="aligncenter"><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab" id="Player_cba6ceac-4da4-4650-9613-903c25972c2c"  WIDTH="336px" HEIGHT="280px"> <param NAME="movie" VALUE="http://ws.amazon.com/widgets/q?rt=tf_w_mpw&#038;ServiceVersion=20070822&#038;MarketPlace=US&#038;ID=V20070822%2FUS%2Ftapdagoats-20%2F8014%2Fcba6ceac-4da4-4650-9613-903c25972c2c&#038;Operation=GetDisplayTemplate"></param><param NAME="quality" VALUE="high"></param><param NAME="bgcolor" VALUE="#FFFFFF"></param><param NAME="allowscriptaccess" VALUE="always"><embed src="http://ws.amazon.com/widgets/q?rt=tf_w_mpw&#038;ServiceVersion=20070822&#038;MarketPlace=US&#038;ID=V20070822%2FUS%2Ftapdagoats-20%2F8014%2Fcba6ceac-4da4-4650-9613-903c25972c2c&#038;Operation=GetDisplayTemplate" id="Player_cba6ceac-4da4-4650-9613-903c25972c2c" quality="high" bgcolor="#ffffff" name="Player_cba6ceac-4da4-4650-9613-903c25972c2c" allowscriptaccess="always"  type="application/x-shockwave-flash" align="middle" height="280px" width="336px"></embed></param></object> <noscript><a HREF="http://ws.amazon.com/widgets/q?rt=tf_w_mpw&#038;ServiceVersion=20070822&#038;MarketPlace=US&#038;ID=V20070822%2FUS%2Ftapdagoats-20%2F8014%2Fcba6ceac-4da4-4650-9613-903c25972c2c&#038;Operation=NoScript">Amazon.com Widgets</a></noscript></div>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=ECYSGKeI4Ak:wHOddS39hCQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=ECYSGKeI4Ak:wHOddS39hCQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=ECYSGKeI4Ak:wHOddS39hCQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=ECYSGKeI4Ak:wHOddS39hCQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=ECYSGKeI4Ak:wHOddS39hCQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=ECYSGKeI4Ak:wHOddS39hCQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=ECYSGKeI4Ak:wHOddS39hCQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=ECYSGKeI4Ak:wHOddS39hCQ:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/ECYSGKeI4Ak" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/psychobilly-sampler.htm/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Specializing Theme Hooks in Custom Drupal 7 Modules</title>
		<link>http://www.tapdancinggoats.com/specializing-theme-hooks-in-custom-drupal-7-modules.htm</link>
		<comments>http://www.tapdancinggoats.com/specializing-theme-hooks-in-custom-drupal-7-modules.htm#comments</comments>
		<pubDate>Wed, 11 Jul 2012 06:03:19 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Drupal]]></category>
		<category><![CDATA[drupal module]]></category>
		<category><![CDATA[drupal theme]]></category>
		<category><![CDATA[drupal theme hook]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=1028</guid>
		<description><![CDATA[An important feature of Drupal 7 is the clean separation between the structure of elements created by modules and the rendering of those elements by themes.  One cool thing is that a module can provide suggestions for the theme hook which should render an element.  This gives theme writers an opportunity to override the theme for very specific elements in a module, and provides for more generic fallback themes otherwise.]]></description>
			<content:encoded><![CDATA[<p><img alt="" src="/assets/druplicon.small_.png" title="Drupal" class="alignright" width="175" height="200" />An important feature of Drupal 7 is the clean separation between the structure of elements created by modules and the rendering of those elements by themes.  One cool thing is that a module can provide suggestions for the theme hook which should render an element.  This gives theme writers an opportunity to override the theme for very specific elements in a module, and provides for more generic fallback themes otherwise.</p>

<p>The theme hook suggestions are lists of increasingly specific keys separated by a double underscore, for example <tt>node__mymodule__block5</tt>.  The first entry, <tt>node</tt> here, is a top level hook defined by a <tt><a href="http://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_theme/7">hook_theme</a></tt> function.  When the <tt><a href="http://api.drupal.org/api/drupal/includes%21theme.inc/function/theme/7">theme</a></tt> function is called, the theme system will try the most specific hook first, in this example <tt>node__mymodule__block5</tt>.  If that doesn&#8217;t exist, it will try the next hook, <tt>node__mymodule</tt>, and so on until it gets to the top level hook.  Themes that implement these specific hooks with template files will replace the underscores with hyphens, so <tt>node__mymodule__block5</tt> would be rendered by <tt>node--mymodule--block5.tpl.php</tt>.</p>

<p>Module developers can set a theme hook suggestion for an element by using the <tt>#theme</tt> key of a <a href="http://drupal.org/node/930760">render array</a>.  The keys of the render array will have to include any parameters that the top level hook requires.  These parameters are defined when the hook is declared.  Hooks in Drupal core have their parameters in the <a href="http://api.drupal.org/">Drupal API</a>, and hooks from custom Drupal modules should be documented in the module.  Here is a nice <a href="http://api.drupal.org/api/drupal/modules%21system%21theme.api.php/group/themeable/7">list of default theme hooks in Drupal core</a></p>

<p>Here is an example that creates a list using a theme suggestion derived from the Drupal core hook <tt><a href="http://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_item_list/7">item_list</a></tt>, getting the elements from some function <tt>get_items</tt>.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
<span class="kw2">function</span> mymodule_block_view<span class="br0">&#40;</span><span class="re0">$delta</span> = <span class="st0">&quot;&quot;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re0">$block</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$block</span><span class="br0">&#91;</span><span class="st0">&quot;subject&quot;</span><span class="br0">&#93;</span> = t<span class="br0">&#40;</span><span class="st0">&quot;My Awesome List&quot;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$block</span><span class="br0">&#91;</span><span class="st0">&quot;content&quot;</span><span class="br0">&#93;</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// item_list is the Drupal core theme hook for unordered or ordered lists</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;#theme&quot;</span> =&gt; <span class="st0">&quot;item_list__mymodule__awesome_list&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// #type and #items are parameters for the item_list theme</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;#type&quot;</span> =&gt; <span class="st0">&quot;ul&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;#items&quot;</span> =&gt; get_items<span class="br0">&#40;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; <span class="br0">&#41;</span>;<br />
<br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$block</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=swD90nDRmwE:xCPXJ8xIYjg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=swD90nDRmwE:xCPXJ8xIYjg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=swD90nDRmwE:xCPXJ8xIYjg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=swD90nDRmwE:xCPXJ8xIYjg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=swD90nDRmwE:xCPXJ8xIYjg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=swD90nDRmwE:xCPXJ8xIYjg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=swD90nDRmwE:xCPXJ8xIYjg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=swD90nDRmwE:xCPXJ8xIYjg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/swD90nDRmwE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/specializing-theme-hooks-in-custom-drupal-7-modules.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Three Styles for LaTeX Vector Notation</title>
		<link>http://www.tapdancinggoats.com/latex-vector-notation.htm</link>
		<comments>http://www.tapdancinggoats.com/latex-vector-notation.htm#comments</comments>
		<pubDate>Tue, 26 Jun 2012 05:24:26 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[LaTeX]]></category>
		<category><![CDATA[Math]]></category>
		<category><![CDATA[arrow]]></category>
		<category><![CDATA[bold]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[example]]></category>
		<category><![CDATA[hat]]></category>
		<category><![CDATA[LaTeX vector notation]]></category>
		<category><![CDATA[vector]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=816</guid>
		<description><![CDATA[LaTeX is a very flexible program for typesetting math, but sometimes figuring out how to get the effect you want can be tricky. Most of the stock math commands are written for typesetting math or computer science papers for academic journals, so you might need to dig deeper into LaTeX commands to get the vector [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/creative_stock/3400669616/"><img src="http://www.tapdancinggoats.com/wp-content/uploads/2012/06/arrows_flickr_Creativity103.jpg" alt="LaTeX Vectors by Creativity103" title="LaTeX Vector Notation by Creativity103" width="240" height="180" class="alignright first size-full wp-image-845" /></a>
LaTeX is a very flexible program for typesetting math, but sometimes figuring out how to get the effect you want can be tricky.  Most of the stock math commands are written for typesetting math or computer science papers for academic journals, so you might need to dig deeper into LaTeX commands to get the vector notation styles that are common in physics textbooks and articles.</p>

<p>This post shows how to typeset a LaTeX vector with an arrow, a hat, or bold.
<span id="more-816"></span></p>

<h2>LaTeX Vector With an Arrow</h2>

<p>The arrow vector notation is the standard in LaTeX, just use the <tt>\vec</tt> command in math mode.</p>

<p>This:</p>

<div class="dean_ch" style="white-space: wrap;"><span class="re5">$<span class="re2">\dot</span>{<span class="re3"><span class="re2">\vec</span>{p}} = m<span class="re2">\vec</span>{v</span>}$</span></div>

<p>Generates this:<br />
<img src="http://www.tapdancinggoats.com/wp-content/uploads/2012/06/vec1.png" alt="LaTeX Vector With Arrow" title="LaTeX Vector With Arrow" width="88" height="41" class="alignnone size-full wp-image-821" /></p>

<h2>LaTeX Vectors With Hats</h2>

<p>Using the <tt>\hat</tt> command in LaTeX generates a caret commonly used for unit vectors.</p>

<p>This:</p>

<div class="dean_ch" style="white-space: wrap;"><span class="re5">$<span class="re2">\hat</span>{<span class="re3">k&#8217;} = 0.5<span class="re2">\hat</span>{k} + 0.2<span class="re2">\hat</span>{<span class="re2">\jmath</span></span>}$</span></div>

<p>Generates this:<br />
<img src="http://www.tapdancinggoats.com/wp-content/uploads/2012/06/hat1.png" alt="LaTeX Vector with a Hat" title="LaTeX Vector with a Hat" width="152" height="35" class="alignnone size-full wp-image-827" /></p>

<p>Note that I used <tt>\jmath</tt> in the last statement.  This gets rid of the dot over the <tt>j</tt> which screws up the placement of the caret.  A similar command, <tt>\imath</tt> is also available for <tt>i</tt>.</p>

<h2>Bold LaTeX Vector</h2>

<p>This command will make <tt>\vec</tt> typeset LaTeX vectors using bold instead of an arrow:</p>

<div class="dean_ch" style="white-space: wrap;"><span class="re2">\renewcommand</span>{<span class="re3"><span class="re2">\vec</span>}[<span class="re4">1</span>]{<span class="re2">\mathbf</span>{#1}</span>}</div>

<p>Put that in the header of the LaTeX file, then <tt>$\vec{v} = 5\hat{k}$</tt> generates:<br />
<img src="http://www.tapdancinggoats.com/wp-content/uploads/2012/06/bold1.png" alt="LaTeX Bold Vector" title="LaTeX Bold Vector" width="76" height="31" class="alignnone size-full wp-image-830" /></p>

<p>If you like bold unit vectors, these commands will also modify the <tt>\hat</tt> command:</p>

<div class="dean_ch" style="white-space: wrap;"><span class="re2">\let</span><span class="re2">\oldhat</span><span class="re2">\hat</span><br />
<span class="re2">\renewcommand</span>{<span class="re3"><span class="re2">\hat</span>}[<span class="re4">1</span>]{<span class="re2">\oldhat</span>{<span class="re2">\mathbf</span>{#1}}</span>}</div>

<p>Now <tt>$\vec{v} = 5\hat{k}$</tt> generates:<br />
<img src="http://www.tapdancinggoats.com/wp-content/uploads/2012/06/bold2.png" alt="LaTeX Vectors with Bold and Hat" title="LaTeX Vectors with Bold and Hat" width="77" height="32" class="alignnone size-full wp-image-831" /></p>

<p>My other post about <a href="http://www.tapdancinggoats.com/bold-vectors-in-latex.htm" title="Bold LaTeX Vectors">bold LaTeX vectors</a> has some great tips in the comments about using this with Greek letters.</p>

<p>Bold is my favorite style for vectors in LaTeX articles, but the decorated styles can look good in a well-printed book.  Leave your favorite styles and tips in the comments!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=uG33_XUN1NE:ZpaDGnO8qz8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=uG33_XUN1NE:ZpaDGnO8qz8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=uG33_XUN1NE:ZpaDGnO8qz8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=uG33_XUN1NE:ZpaDGnO8qz8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=uG33_XUN1NE:ZpaDGnO8qz8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=uG33_XUN1NE:ZpaDGnO8qz8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=uG33_XUN1NE:ZpaDGnO8qz8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=uG33_XUN1NE:ZpaDGnO8qz8:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/uG33_XUN1NE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/latex-vector-notation.htm/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Inside Drupal are All the Stars in the Sky</title>
		<link>http://www.tapdancinggoats.com/inside-drupal-are-all-the-stars-in-the-sky.htm</link>
		<comments>http://www.tapdancinggoats.com/inside-drupal-are-all-the-stars-in-the-sky.htm#comments</comments>
		<pubDate>Mon, 11 Jun 2012 05:18:53 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Drupal]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=785</guid>
		<description><![CDATA[I have drilled deep into Drupal and come out the other side, dripping with offal and frustration. It is an incredibly powerful framework, with an easy, standard way to modify literally anything in the system at any point during the page flow. Of course, finding the easy way is the hard part, because there are [...]]]></description>
			<content:encoded><![CDATA[<p>I have drilled deep into Drupal and come out the other side, dripping with offal and frustration. It is an incredibly powerful framework, with an easy, standard way to modify literally anything in the system at any point during the page flow. Of course, <em>finding</em> the easy way is the hard part, because there are also ten wrong ways to do anything you want to do, and the API reference is written as more of a gentle reminder to the API authors that relegates the uninitiated to swapping war stories in the comments on each page. I still love it, though, especially now that I know the secrets, which I will be sharing here soon.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=DM1DXkEfUYE:GHTBXy5nt_M:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=DM1DXkEfUYE:GHTBXy5nt_M:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=DM1DXkEfUYE:GHTBXy5nt_M:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=DM1DXkEfUYE:GHTBXy5nt_M:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=DM1DXkEfUYE:GHTBXy5nt_M:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=DM1DXkEfUYE:GHTBXy5nt_M:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=DM1DXkEfUYE:GHTBXy5nt_M:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=DM1DXkEfUYE:GHTBXy5nt_M:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/DM1DXkEfUYE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/inside-drupal-are-all-the-stars-in-the-sky.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hear How You Sound to Others</title>
		<link>http://www.tapdancinggoats.com/hear-how-you-sound-to-others.htm</link>
		<comments>http://www.tapdancinggoats.com/hear-how-you-sound-to-others.htm#comments</comments>
		<pubDate>Sat, 26 May 2012 14:26:25 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Links]]></category>
		<category><![CDATA[sound]]></category>
		<category><![CDATA[voice]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=780</guid>
		<description><![CDATA[Are you surprised at how you sound when you listen to a recording of your voice? I always thought that we sound different to ourselves because your voice vibrates through your skull to your own eardrums, which gives you a unique experience of your voice. It&#8217;s kind of nice to think that every time you [...]]]></description>
			<content:encoded><![CDATA[<iframe width="480" height="360" src="http://www.youtube.com/embed/eWLWOSgYlG8" frameborder="0" allowfullscreen></iframe>

<p>Are you surprised at how you sound when you listen to a recording of your voice?  I always thought that we sound different to ourselves because your voice vibrates through your skull to your own eardrums, which gives you a unique experience of your voice.  It&#8217;s kind of nice to think that every time you speak you&#8217;re giving yourself a private concert, but for effective communication you need to know how others hear you.</p>

<p>Vocal Coach Chris Beatty&#8217;s video shows one way to hear how you sound to others.  He explains that part of the effect is due to sound travelling around your face to your ears.  Blocking this sound lets you hear how your voice changes as it travels through the room.  I gave it a try, and I was surprised at how well it works.</p>

<p>I have a deep voice, and people often have trouble understanding me.  I&#8217;ve always wondered if I sound louder to myself than others, and if the distinct frequencies of my voice get muddled as they bounce around a room.  When I used this technique and blocked my voice with some magazines, it sounded like my volume dropped to about 30%.  I couldn&#8217;t believe it!  I used to do theatre,<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> so I know I can speak loudly enough to be clearly heard across an auditorium.  Because of this, I try to keep my volume down so that people don&#8217;t think I&#8217;m shouting, but I think I went too far.  Now, using this technique to hear how I sound to others for feedback I&#8217;ll be able to adjust how I speak to be more clearly understood.</p>

<p>via <a href="http://lifehacker.com/5910119/learn-how-other-people-hear-your-voice-with-two-folders">LifeHacker</a></p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:1">
<p>Yes, I was a stage ac-tor, I trod the boards&#160;<a href="#fnref:1" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=sDkxN7lVTlc:sgJFdyWupvQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=sDkxN7lVTlc:sgJFdyWupvQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=sDkxN7lVTlc:sgJFdyWupvQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=sDkxN7lVTlc:sgJFdyWupvQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=sDkxN7lVTlc:sgJFdyWupvQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=sDkxN7lVTlc:sgJFdyWupvQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=sDkxN7lVTlc:sgJFdyWupvQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=sDkxN7lVTlc:sgJFdyWupvQ:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/sDkxN7lVTlc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/hear-how-you-sound-to-others.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
