<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-12109108</id><updated>2011-07-29T04:50:57.200-04:00</updated><category term='theory'/><category term='math'/><category term='javascript'/><category term='clojure'/><category term='patterns'/><category term='socks'/><category term='lace'/><category term='programming'/><category term='sweaters'/><category term='lisp'/><category term='blankets'/><category term='ideas'/><category term='computers'/><category term='swtches'/><category term='firefox'/><category term='knitting'/><category term='hacks'/><category term='tinkering'/><category term='scarves'/><category term='textures'/><category term='cables'/><category term='design'/><category term='hats'/><category term='failure'/><category term='spirals'/><category term='gloves'/><category term='opera'/><title type='text'>wet pixels</title><subtitle type='html'>random notes about projects and works in progress</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>37</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-12109108.post-9094252859052615896</id><published>2010-03-05T20:47:00.004-05:00</published><updated>2010-03-07T13:39:46.624-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Spiraling Twist Hat</title><content type='html'>&lt;a href="http://www.flickr.com/photos/29571367@N07/4414569350/"
   title="Spiral Twist Hat by turvity, on
          Flickr"&gt;
  &lt;img src="http://farm3.static.flickr.com/2696/4414569350_d63484c8a7.jpg"
       width="500"
       height="467"
       style="float:right;"
       alt="Spiral Twist Hat" /&gt;
&lt;/a&gt;
&lt;p&gt; This hat is based around a simple pattern of twists, creating a
  design that spirals around the crown.  The goal was to make a hat
  simple enough to knit without a pattern (on a bus ride) while still
  being more interesting than simply knitting stockingette forever and
  ever.
&lt;/p&gt;
&lt;h3&gt; Casting on &lt;/h3&gt;
&lt;p&gt; Cast on a multiple of 6 stitches.  I used 120 stitches on 5.5mm
  needles to give a fairly loose fit.  Join without twisting and mark
  the beginning of the round.
&lt;/p&gt;

&lt;h3&gt; Brim &lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt; Knit 10 rounds of k1, p1 rib.  (k1, p1, repeat to the end of
  the round.)
  &lt;li&gt; Knit 2 rounds of stockingette (knit stitch).
  &lt;li&gt; Knit 9 rounds of k1, p1 rib.
&lt;/ul&gt;

&lt;h3&gt; Crown &lt;/h3&gt;
&lt;p&gt; The crown is made up of twists, followed by ribbing.  On each row
  of twists, move any markers one stitch to the right.  This means
  that, rather than purling the last stitch of the round before a
  round of twists, you instead twist it with the first statch of the
  next round.
&lt;/p&gt;
&lt;ol start="10"&gt;
  &lt;li&gt; Move marker one stitch right.  RT (knit into the second stitch
    on the left needle and, without removing the stitch from the
    needle, knit into the first stitch, removing both stitches from
    the left needle.)  Repeat, twisting every two stitches together
    until the end of the round.
  &lt;li&gt; k1, p1, repeat to the end of the round.
  &lt;li&gt; k1, p1, repeat to the end of the round.
&lt;/ol&gt;
&lt;p&gt; Repeat these three rows four times.
&lt;/p&gt;
&lt;ol start="22"&gt;
  &lt;li&gt; Move marker one stitch right.  RT until the end of the round.
  &lt;li&gt; k1, p1 to the end of the round.
&lt;/ol&gt;
&lt;p&gt; Repeat these two rows four times.
&lt;/p&gt;
&lt;ol start="30"&gt;
  &lt;li&gt; Move marker one stitch right.  RT until the end of the round.
  &lt;li&gt; Remove the marker, slip the last stitch on the right needle
  onto the left needle and place the marker on the right needle.  RT
  until the end of the round.
&lt;/ol&gt;
&lt;h3&gt; Decreasing &lt;/h3&gt;
&lt;p&gt; If you are using circular needles, when it becomes uncomfortable
  to knit the smaller rounds here, switch to double-pointed needles.
&lt;/p&gt;
&lt;ol start="32"&gt;
  &lt;li&gt; k1, p1, k1, p1, k2tog, repeat to the end of the round.
  &lt;li&gt; k1, p1, k1, p1, k1, repeat to the end of the round.
  &lt;li&gt; k1, p1, k1, p1, k1, repeat to the end of the round.
  &lt;li&gt; k1, p1, p2tog, k1, repeat to the end of the round.
  &lt;li&gt; k1, p2, k1, repeat to the end of the round.
  &lt;li&gt; k1, p2, k1, repeat to the end of the round.
  &lt;li&gt; Move marker one stitch right.  k2tog, p2, repeat to the end of
  the round.
  &lt;li&gt; k1, p2, repeat to the end of the round.
  &lt;li&gt; k1, p2, repeat to the end of the round.
  &lt;li&gt; k1, p2tog, repeat to the end of the round.
  &lt;li&gt; k1, p1, repeat to the end of the round.
  &lt;li&gt; k1, p1, repeat to the end of the round.
  &lt;li&gt; k2tog, repeat to the end of the round.
  &lt;li&gt; k1 to the end of the round.
  &lt;li&gt; k1 to the end of the round.
&lt;/ol&gt;
&lt;p&gt; At this point, the hat has 1/6 of the original number of
  stitches.  On a 120-stitch hat, this left me with 20 stitches.
  Repeat the last three rounds until you have ten stitches or fewer,
  then cut your yarn, draw the tail through the remaining loops and
  pull tight. 
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-9094252859052615896?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/9094252859052615896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=9094252859052615896' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/9094252859052615896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/9094252859052615896'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2010/03/spiraling-twist-hat.html' title='Spiraling Twist Hat'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2696/4414569350_d63484c8a7_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-61468190361987450</id><published>2009-10-31T21:45:00.003-04:00</published><updated>2009-10-31T21:53:56.608-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spirals'/><category scheme='http://www.blogger.com/atom/ns#' term='blankets'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='lace'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Golden Spiral Blanket - One square metre</title><content type='html'>&lt;a href="http://www.flickr.com/photos/29571367@N07/4062044873/" title="Golden Spiral Blanket by turvity, on Flickr"&gt;&lt;img src="http://farm3.static.flickr.com/2574/4062044873_ce8c3842f7.jpg" width="500" height="455" alt="Golden Spiral Blanket" /&gt;&lt;/a&gt;

&lt;p&gt;This is the blanket I'm working on, with the eventual goal of having it be a bed-sized spiral.

&lt;p&gt;Like so:

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.photobucket.com/albums/v205/kearsley/charts/LogarithmicSpiral2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 634px; height: 1023px;" src="http://img.photobucket.com/albums/v205/kearsley/charts/LogarithmicSpiral2.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-61468190361987450?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/61468190361987450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=61468190361987450' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/61468190361987450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/61468190361987450'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/10/golden-spiral-blanket-one-square-metre.html' title='Golden Spiral Blanket - One square metre'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2574/4062044873_ce8c3842f7_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-6008159627556355758</id><published>2009-10-31T12:54:00.002-04:00</published><updated>2009-10-31T13:08:01.089-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cables'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='socks'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Twirling twist socks - One foot</title><content type='html'>&lt;a href="http://www.flickr.com/photos/29571367@N07/4061424918/" title="Twirling Twist Socks - Toe and foot by turvity, on Flickr"&gt;&lt;img src="http://farm3.static.flickr.com/2661/4061424918_9dcd06331f.jpg" width="350" alt="Twirling Twist Socks - Toe and foot" style="float:right;" /&gt;&lt;/a&gt;

&lt;a href="http://www.flickr.com/photos/29571367@N07/4061423566/" title="Twirling Twist Socks - Toe and foot by turvity, on Flickr"&gt;&lt;img src="http://farm3.static.flickr.com/2718/4061423566_db19926eaa.jpg" width="350" alt="Twirling Twist Socks - Toe and foot" style="float:right;" /&gt;&lt;/a&gt;

&lt;p&gt;This is how far I've got in knitting the socks that woke me up.  I'm just about ready to start knitting the heel flap.  After that, the cable that features prominently on the foot here will split into two branches, each of which will twirl in opposite directions.

&lt;p&gt;The cables will continue twisting in the same way as the cable on the foot, but will gradually make their way to the back of the sock, cross each other, then come back to the front of the sock again.

&lt;p&gt;And again, the nice thing about this design is that, when it comes time to write down the pattern (which I seem to do after one sock, then follow it for the second) it's actually relatively easy to explain.  Or, rather, it'll be easy to write down the exact stitches to make to end up with the same result.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-6008159627556355758?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/6008159627556355758/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=6008159627556355758' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/6008159627556355758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/6008159627556355758'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/10/twirling-twist-socks-one-foot.html' title='Twirling twist socks - One foot'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2661/4061424918_9dcd06331f_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-4815878800489744467</id><published>2009-10-29T21:10:00.002-04:00</published><updated>2009-10-29T21:39:58.478-04:00</updated><title type='text'>Woken by socks</title><content type='html'>&lt;p&gt;Dear knitblog,

&lt;p&gt;I know I've been bad at updating you.  I didn't knit from March through October.  But I've started again.  Working on a blanket now.  All placid and black hole.  And what I would like to cite as a sign of obsessive attachment:

&lt;p&gt;I was woken up tonight by a pair of socks.

&lt;p&gt;Not just any socks, but a sock pattern pretty enough that I can use my Knitpicks pretty-pretty-pet-it-pretty yarn on.  (An xmas gift)

&lt;p&gt;Socks where cables spiral around each other in a manner that is wholly an illusion, and is easy to knit.  A pattern that I think I'll be able to actually chart and put up, unlike some of the more, shall we say, esoteric&lt;sup&gt;1&lt;/sup&gt; patterns I did in February and March.

&lt;p&gt;The idea is this: A line of c2x2 twist up the foot, splitting into two cables that twist around the ankle, in opposite directions, propelled by KFBs and p2togs.

&lt;p&gt;Anyway, I'm casting on a toe, and I'll see where it takes me!

&lt;hr/&gt;
&lt;ol&gt;
&lt;li&gt; By which I mean 'needlessly complicated'.
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-4815878800489744467?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/4815878800489744467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=4815878800489744467' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/4815878800489744467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/4815878800489744467'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/10/woken-by-socks.html' title='Woken by socks'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-5179881684388045934</id><published>2009-04-04T17:54:00.004-04:00</published><updated>2009-04-04T18:45:59.556-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scarves'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='lace'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Sierpinski/Koch Scarf - Halfway there</title><content type='html'>&lt;table&gt;
  &lt;tr&gt;
    &lt;td valign="top"&gt;
      &lt;p&gt;Now that I'm halfway done this project and no longer
        routinely swearing and ripping it out, I think it's time to
        show off my progress.

      &lt;p&gt;The project was partially conceived out of a desire to play
        with triangle-based fractals and partially out of a desire to
        make myself more comfortable with lace.

      &lt;p&gt;The bottom panel is a Sierpinski sieve after three iterations
        of the algorithm.  Each panel goes back one iteration, until
        nothing remains but a triangle.

      &lt;p&gt;I'm currently knitting said triangle.  After I'm done that,
        I'll go forward two iterations into the 2-dimensional Koch
        curve (or Koch snowflake).  At the size I'm knitting, I only
        have the resolution to knit two Koch curves.

      &lt;p&gt;However, the Koch curve pattern (which I've sketched, but not
        yet plotted out with all its decreases) has the fortuitous
        property of being half again as large as the Sierpinski
        triangle.  Hence, two Koch curves will be as long as three
        Sierpinski triangles.

      &lt;p&gt;I had a few false starts with the Sierpinski pattern, though.
        First, I misguessed how to angle the decreases, resulting in a
        random web of yarn.  Second, I saw that once I'd knitted more
        than half the triangle, the corners of the fabric drooped
        dramatically.  To fix that, I spread out and flattened the
        scarf, then placed a straight edge from the middle over the
        drooping corners and noted the row that it intersected.
        Having done that, I cast on with twice the number of stitches
        that that row had outside the pattern (twice 14 --$gt; 28).  From
        there, I increased every row without a corresponding decrease,
        until the scarf was 45 stitches across, the width of the
        pattern.
        
      &lt;p&gt;I intend to, on the second Koch curve, decrease every pattern
        row for the last third of the pattern, giving it the opposite
        curve to the bottom of the scarf, rather than the simple curve
        that would result from casting off on a flat edge.
    &lt;/td&gt;
    &lt;td valign="top"&gt;
      &lt;a href="http://www.flickr.com/photos/29571367@N07/3412023951/" title="Sierpinski / Koch Scarf - Panel 3 by turvity, on Flickr"&gt;
        &lt;img src="http://farm4.static.flickr.com/3573/3412023951_1de1e5df6d.jpg" width="300" alt="Sierpinski / Koch Scarf - Panel 3" /&gt;
      &lt;/a&gt;
      &lt;a href="http://www.flickr.com/photos/29571367@N07/3412828062/" title="Sierpinski / Koch Scarf - Panel 2 by turvity, on Flickr"&gt;
        &lt;img src="http://farm4.static.flickr.com/3612/3412828062_1b3c462170.jpg" width="300" alt="Sierpinski / Koch Scarf - Panel 2" /&gt;
      &lt;/a&gt;
      &lt;a href="http://www.flickr.com/photos/29571367@N07/3412826736/" title="Sierpinski / Koch Scarf - Panel 1 by turvity, on Flickr"&gt;
        &lt;img src="http://farm4.static.flickr.com/3614/3412826736_28dc035e19.jpg" width="300" alt="Sierpinski / Koch Scarf - Panel 1" /&gt;
      &lt;/a&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-5179881684388045934?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/5179881684388045934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=5179881684388045934' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/5179881684388045934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/5179881684388045934'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/04/sierpinskikoch-scarf-halfway-there.html' title='Sierpinski/Koch Scarf - Halfway there'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm4.static.flickr.com/3573/3412023951_1de1e5df6d_t.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-6312202140140404654</id><published>2009-03-30T16:45:00.004-04:00</published><updated>2009-03-30T17:17:02.624-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tinkering'/><category scheme='http://www.blogger.com/atom/ns#' term='socks'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Mutations</title><content type='html'>&lt;p&gt;A few days ago, I was approached by &lt;a href="http://colorlessblue.blogspot.com/"&gt;colorlessblue&lt;/a&gt;.  She had a &lt;a href="http://www.knitty.com/ISSUEwinter06/PATTmonkey.html"&gt;pretty sock pattern made up of triangles&lt;/a&gt;, but it required her to use exactly 64 stitches around.

&lt;p&gt;Her difficulty was that she couldn't find a gauge in which that worked.  Me first reaction was to say, "well, that's not a big deal, the pattern is trivial to make fit on a multiple of 12 or 14 stitches."  Then I tried to explain what stitches to remove, and it really quickly became messy.  

&lt;p&gt;So I stopped for 15 minutes or so and drew a few patterns.  As I started, she clarified that she didn't want to purl.

&lt;p&gt;This is what resulted:  

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.photobucket.com/albums/v205/kearsley/charts/Chevrons14.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px;" src="http://img.photobucket.com/albums/v205/kearsley/charts/Chevrons14.png" border="0" alt="" /&gt;&lt;/a&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.photobucket.com/albums/v205/kearsley/charts/Chevrons12.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px;" src="http://img.photobucket.com/albums/v205/kearsley/charts/Chevrons12.png" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;However, the absence of purl stitches meant that the resulting pattern would be triangles of vertical knit stitches with a zigzag border of slanted stitches.  So, my next thought was, "Why not make the slanted stitches into the motif.  That resulted in this pattern:

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.photobucket.com/albums/v205/kearsley/charts/Triangles14.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px;;" src="http://img.photobucket.com/albums/v205/kearsley/charts/Triangles14.png" border="0" alt="" /&gt;&lt;/a&gt;

It's not perfect by any means.  The k2tog and SSK being next to each other results in a ladder.  Were I continuing that tangent, I'd turn all paired decreases into double decreases.  Also, as it turns out, I didn't like how the paired yarn overs at the apex of the triangle looked.

At the same time as I was thinking that, I also wondered what would happen if the triangles were offset by half a repeat, giving the whole pattern a longer period before it repeats.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.photobucket.com/albums/v205/kearsley/charts/Diamonds25.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px;" src="http://img.photobucket.com/albums/v205/kearsley/charts/Diamonds25.png" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;This pattern (which is almost the same as a Barbara Walker one) has the property that the knit stitches actually form themselves into vein-like curves: the diamonds end up looking like oval leaves.

&lt;p&gt;I tried knitting it half in  knit and half in purl, to see if that would give the leaves more shape, but that ended up being a step too far: The lace lost enough of its definition that the pattern looked awkward and no longer anything like leaves.

&lt;p&gt;I think I'm likely to use this one at some point, possibly as a motif one some leaf-patterned socks that I keep not getting around to.  Before I do, I'm likely to put it through one more mutation, reducing it to about half the size and extending the widest part of the leaf by two rows, so that it more accurately matches the shape of a beech leaf.

&lt;p&gt;Most of my charts seem to follow a similar pattern of starting point and progressive mutation, followed by a test knit, correction of discovered problems, a further test knit and possibly correcting steps that went too far.

&lt;p&gt;It's like saying "just one more row", but "just one more change" instead.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-6312202140140404654?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/6312202140140404654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=6312202140140404654' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/6312202140140404654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/6312202140140404654'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/03/mutations.html' title='Mutations'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-5063136388399009138</id><published>2009-03-20T10:59:00.005-04:00</published><updated>2009-03-20T12:03:55.813-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sweaters'/><category scheme='http://www.blogger.com/atom/ns#' term='cables'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Braid-pattern pullover -- Prelude</title><content type='html'>&lt;p&gt;I'd be the first to admit that I think of myself as a sock-and-hat knitter.  I like my projects the way I... Never mind, I'm not going to finish that chestnut.  Suffice it to say that I like my projects small enough that I can always keep the end in sight.

&lt;p&gt;That said, I picked up two bales of wool this week; bulky natural wool in a pleasant brown.  Along with that, I expanded what is apparently becoming an Addi collection.  Essentially, I've committed to knitting a sweater.

&lt;p&gt;As is my wont, I started by browsing the internet to determine what &lt;em&gt;kind&lt;/em&gt; of sweater I wanted, then searching &lt;a href="http://www.ravelry.com/patterns/search?page=5&amp;query=pullover&amp;sort=best&amp;view=thumblist"&gt;Ravelry&lt;/a&gt; for patterns.  As usually happens, I got frustrated.  Fortunately, Elizabeth Zimmerman has a pattern, described in proportions, for a warm baggy pullover.  Less-fortunately, it's &lt;a href="http://www.knitty.com/ISSUEspring03/FEATsteeks.html"&gt;steeked&lt;/a&gt;.  After more research and not a little bit of swearing, I decided to blissfully close my eyes and pay no mind to those instructions.  After all, I have many many many stitches between me and slicing two holes into my knitting.

&lt;p&gt;Plenty of time to chicken out and re-think the pattern as two trapezoids sewn together with the arms attached by picking up off the selvedge.  Plenty of time to consider that sewing two trapezoids together will be far less solid than biting the bullet and knitting the whole thing as a tapered cylinder.

&lt;p&gt;Plenty of time to knit swatches.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.photobucket.com/albums/v205/kearsley/charts/CablePanel.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px;" src="http://img.photobucket.com/albums/v205/kearsley/charts/CablePanel.png" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;This is what I'm using as a swatch.  This pattern, repeated over and over, is intended to make up two front panels of the sweater.  The intent is to swatch it to see if it looks right and also to test texture and gauge of the wool and needles.  As I'm more than mildly worried that 5mm needles (my preferred size for worsted) will simply be too tiny for bulky.

&lt;p&gt;After only a little bit of discussion and plotting, I realised that the back of the sweater really deserves a different pattern from the front.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.photobucket.com/albums/v205/kearsley/charts/CablePanel2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px" src="http://img.photobucket.com/albums/v205/kearsley/charts/CablePanel2.png" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Rather than two panels of four-strand braids, the back has a single panel, centred, that makes a twelve-strand braid or knot.  Fortunately, this pattern will look pleasing so long as the front panel does, so I only need to knit the one swatch as a test pattern.

&lt;p&gt;In keeping with my three-project rule, I'm not to start a pair of socks or a hat or anything else until I've finished with this swatch.  Further, once I've committed to the sweater, that's one of the three available slots for patterns taken up.  So, likely, I'll knit the swatch, knit some socks (I have a pattern that I want to try), possibly knit some more socks (I actually have two patterns waiting for me), maybe finish a hat, and then get to the sweater, just in time for it to be too warm out for sweaters.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-5063136388399009138?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/5063136388399009138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=5063136388399009138' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/5063136388399009138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/5063136388399009138'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/03/braid-pattern-pullover-prelude.html' title='Braid-pattern pullover -- Prelude'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-1142939666128934805</id><published>2009-02-18T21:56:00.003-05:00</published><updated>2009-02-18T22:48:44.863-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='hacks'/><category scheme='http://www.blogger.com/atom/ns#' term='opera'/><title type='text'>Ravelry Hack #1 - Counting downloads</title><content type='html'>&lt;p&gt;So, I like &lt;a href="http://www.ravelry.com/designers/kearsley-schieder-wethy"&gt;Ravelry's designer pages&lt;/a&gt;.  They're great for indulging my vanity.  I tend to check my downloads every once in a while, just out of curiosity, to see if anyone's downloading my patterns.

&lt;p&gt;But one thing it's lacking, and that I'm generally curious about, is how many times they've been downloaded in &lt;em&gt;total&lt;/em&gt;.  The page doesn't indulge that curiosity.  I initially considered putting in a feature request, but then got sidetracked by geekery.

&lt;p&gt;See, the Ravelry downloads page is remarkably readable HTML.  Which led me to a quick and easy conclusion: I can fix this in &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/748"&gt;Greasemonkey&lt;/a&gt;.

&lt;p&gt;Even having forgotten most of what I learned about the Javascript HTML DOM last time I wrote a Greasemonkey script, it took just over two hours.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.photobucket.com/albums/v205/kearsley/Picture2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 640px; height: 125px;" src="http://img.photobucket.com/albums/v205/kearsley/Picture2.png" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Becomes:

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img.photobucket.com/albums/v205/kearsley/Picture1-1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 639px; height: 133px;" src="http://img.photobucket.com/albums/v205/kearsley/Picture1-1.png" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;With added daily counts on the right-hand column and a "Total Downloads" field at the bottom of the graph.

&lt;h3&gt;Installation&lt;/h3&gt;

&lt;p&gt;If you are using Firefox without Greasemonkey, a compiled Firefox addon &lt;a href="http://sites.google.com/site/turvity/Home/ravelrystatistics.xpi.zip?attredirects=0"&gt;is available here&lt;/a&gt;.  Download it, unzip it and drag it into your Firefox window.  It should ask to install, like a normal add-on.

&lt;p&gt;If you have Greasemonkey installed or are using Opera, download &lt;a href="http://sites.google.com/site/turvity/Home/ravelry_statistics.user.js.zip?attredirects=0"&gt;the Greasemonkey script file&lt;/a&gt; and install the user.js file by: 

&lt;p&gt;&lt;strong&gt;Firefox&lt;/strong&gt;: by dragging the file into your Firefox window.  Greasemonkey should open, displaying the affected URL and ask you if you wish to install.

&lt;p&gt;&lt;strong&gt;Opera&lt;/strong&gt;: The path where User Javascript files are loaded from is indicated in Preferences/Advanced/Content/Javascript Options.  If no path is indicated, choose one.  Place the user.js file into that directory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-1142939666128934805?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/1142939666128934805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=1142939666128934805' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/1142939666128934805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/1142939666128934805'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/ravelry-hack-1-counting-downloads.html' title='Ravelry Hack #1 - Counting downloads'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-1130261571665774452</id><published>2009-02-16T17:36:00.008-05:00</published><updated>2009-02-16T21:12:02.530-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><category scheme='http://www.blogger.com/atom/ns#' term='patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Knitting is an acceptable Lisp</title><content type='html'>&lt;p&gt;So, I'm a knitter.  And I
  pretend to be a designer some days, when I'm not knitting
  endless swathes of &lt;span class="stitch"&gt;k2, p2&lt;/span&gt; rib.  But
  first and foremost, I'm an unabashed geek.

&lt;p&gt;As such, I took a look
  at &lt;a href="http://www.knitml.com"&gt;KnitML&lt;/a&gt;.  And it's neat.
  Well, in theory, it's neat.  In practice, I haven't got the java
  dependencies set up on my computer yet to play with it.  I do
  intend to do that, and am downloading them, but while I wait for
  them, I want to ponder through an idea that's been percolating
  in my brain.

&lt;p&gt;Namely, I think of knitting patterns in two ways.  One is the
  chart.  This is how I write patterns, really.  And given the
  choice between a chart and a list of stitches, I'll pick the
  chart every time.

&lt;p&gt;It's a question of information density.  The chart presents
  all the information that I need, in the least amount of space
  while still being human-readable.

&lt;p&gt;So, let's look at a chart.

  &lt;a onblur="try {parent.deselectBloggerImageGracefully();}
             catch(e) {}"
     href="http://3.bp.blogspot.com/_iq3iNCSmnh8/SY8K_dMMn7I/AAAAAAAAAGg/x1dWFdhFZBg/s1600-h/Embedded+Moss+Stitch+Rib.png"&gt;
    &lt;img style="display:block;
                margin:0px auto 10px; text-align:center;cursor:pointer;
                cursor:hand;width: 200px"
         src="http://3.bp.blogspot.com/_iq3iNCSmnh8/SY8K_dMMn7I/AAAAAAAAAGg/x1dWFdhFZBg/s400/Embedded+Moss+Stitch+Rib.png"
         border="0" alt=""id="BLOGGER_PHOTO_ID_5300467371722186674"
         /&gt;&lt;/a&gt;
  
&lt;p&gt;It's a fairly simple pattern, &lt;span class="pattern"&gt;embedded
    moss stitch rib&lt;/span&gt;.  And can be easily transformed into a
  written pattern:

  &lt;ol&gt;
    &lt;li&gt;p2, k2, p1, k1, repeat to end of round
    &lt;li&gt;p2, k2, p1, k1, repeat to end of round
    &lt;li&gt;p2, k1, p1, k2, repeat to end of round
    &lt;li&gt;p2, k1, p1, k2, repeat to end of round
  &lt;/ol&gt;

&lt;p&gt;This is where my brain starts making clicky noises.  See, my
  immediate reaction to that is that it's a simple program.  One
  that generates a handsome little ribbing.

&lt;p&gt;However, my second line of thought runs straight for a
  programming principle: Don't Repeat Yourself.  My process for
  generating a pattern is to draw charts
  in &lt;a href="http://www.inkscape.org/"&gt;Inkscape&lt;/a&gt;, test those
  charts by knitting them, then translate the chart into written
  instructions.  In future, I may also want to make my charts
  available in KnitML.

&lt;p&gt;What this immediately says to me as a programmer is that I
  should have a single piece of data from which I can generate:

  &lt;ul&gt;
    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics"&gt;PNG graphics&lt;/a&gt;&lt;br/&gt; This is the format I use to show
      charts.  It's a useful format in that it does a good job
      of reducing low-colour line drawings (like knitting
      charts) to a fairly small file size with no loss of detail
      or crispness.&lt;br/&gt;  This is an even worse format to use as
      a data source, though.  Rather than just interpreting the
      XML that SVG gives, I'd have to start into OCR
      territory.
    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Svg"&gt;SVG graphics&lt;/a&gt;&lt;br/&gt; This is the format that I actually use
      to make charts.  Unfortunately, it would be a considerable
      effort to use it as a starting point: Anything more
      complicated than a knit or purl stitch are relatively
      complex "groups", rather than simple objects.&lt;br/&gt;
      However, they work admirably as a way to draw charts, and
      from my perusal of the spec, should be able to be drawn
      programmatically fairly easily.
    &lt;li&gt;HTML lists&lt;br/&gt; This actually isn't a bad starting
      point.  Not good enough that I'd want to use it as a data
      source, but not bad enough, either, to discard it out of
      hand.&lt;br/&gt;  Specifically, if I look at the HTML describing
      the pattern:
      &lt;blockquote&gt;
        &amp;lt;ol&amp;gt;&lt;br/&gt;
        &amp;nbsp;&amp;nbsp;&amp;lt;li&amp;gt; p2, k2, p1, k1, repeat to end of round &lt;br/&gt;
        &amp;nbsp;&amp;nbsp;&amp;lt;li&amp;gt; p2, k2, p1, k1, repeat to end of round &lt;br/&gt;
        &amp;nbsp;&amp;nbsp;&amp;lt;li&amp;gt; p2, k1, p1, k2, repeat to end of round &lt;br/&gt;
        &amp;nbsp;&amp;nbsp;&amp;lt;li&amp;gt; p2, k1, p1, k2, repeat to end of round &lt;br/&gt;
        &amp;lt;/ol&amp;gt;
      &lt;/blockquote&gt;
      Other than the &amp;lt;ol&amp;gt; and &amp;lt;li&amp;gt; tags, this
      actually isn't a bad representation of the data at all.
    &lt;li&gt;Plaintext&lt;br/&gt; What if I were to use the plaintext
      representation of the aforementioned list:
      &lt;blockquote&gt;
        p2, k2, p1, k1, repeat to end of round &lt;br/&gt;
        p2, k2, p1, k1, repeat to end of round &lt;br/&gt;
        p2, k1, p1, k2, repeat to end of round &lt;br/&gt;
        p2, k1, p1, k2, repeat to end of round &lt;br/&gt;
      &lt;/blockquote&gt;
      That's actually, as I alluded before, a programmatic
      representation of knitting.  And, were it not for that
      pesky "repeat to end of round", would be nearly
      perfect.&lt;br/&gt;  In fact, this is relatively close to what
      KnitML uses as a human-readable format, according to my
      reading of the spec.
    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/S-expression"&gt;S-Expressions&lt;/a&gt;&lt;br/&gt;
      These little gems are the core of Lisp, and are easily
      transformable to and from XML if the need arises.&lt;br/&gt;
      The core elements to them are lists and atoms.  A list is
      multiple atoms surrounded by parentheses and separated by
      spaces.  An atom is some text
      representing &lt;em&gt;something&lt;/em&gt;.&lt;br/&gt;
      Thus, the pattern described above becomes:
      &lt;blockquote&gt;
        (repeat 2&lt;br/&gt;
        &amp;nbsp;&amp;nbsp;(repeat-to-end (p2 k2 p1 k1)))&lt;br/&gt;
        (repeat 2&lt;br/&gt;
        &amp;nbsp;&amp;nbsp;(repeat-to-end (p2 k1 p1 k2)))&lt;br/&gt;
      &lt;/blockquote&gt;
      And any Lisp programmer reading this just started twitching.  As
      that's not properly-formed Lisp.  On the other hand, it does
      represent a very interesting way to mix data and instructions.&lt;br/&gt;
      Patterns become lists of stitches and transformative operations performed on those stitches.  It's knitting as a pseudo-mathematical notation.
  &lt;/ul&gt;

&lt;p&gt;So, taking s-expressions as a base, what does it all mean?

&lt;p&gt;Well, in that list of representations, the further along I went,
  the more the representation changed from being a &lt;em&gt;depiction&lt;/em&gt;
  of the data to a &lt;em&gt;representation&lt;/em&gt;.  By the time we reach the
  plaintext version of the pattern, it is recognisable as a
  rudimentary program.

&lt;p&gt;The s-expression version isn't even a rudimentary one; if it were
  fed into an interpreter that recognised the words and symbols used,
  it &lt;em&gt;is&lt;/em&gt; a program to generate a knitting pattern.

&lt;p&gt;Now that offers some interesting prospects, because the output of
  the interpreter by no means has to be fixed.  For instance, I could
  have one interpreter that reads the pattern as a way to generate a
  plain text file, another interpreter that generates an SVG graphic
  and a third that reads the pattern as a way to generate the
  equivalent KnitML file.

&lt;p&gt;Why does all this matter?  Well, I've become interested, in the
  past weeks, in the idea of an editor where I type in a row of
  stitches and it appears on the screen as a graphical pattern.
  Thinking about how to represent stitches is a first step on the road
  to knitting pattern zen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-1130261571665774452?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/1130261571665774452/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=1130261571665774452' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/1130261571665774452'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/1130261571665774452'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/knitting-is-acceptable-lisp.html' title='Knitting is an acceptable Lisp'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_iq3iNCSmnh8/SY8K_dMMn7I/AAAAAAAAAGg/x1dWFdhFZBg/s72-c/Embedded+Moss+Stitch+Rib.png' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-8083893286213833180</id><published>2009-02-14T11:49:00.003-05:00</published><updated>2009-02-14T12:00:22.727-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='tinkering'/><category scheme='http://www.blogger.com/atom/ns#' term='swtches'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><title type='text'>Swatch, knit thyself</title><content type='html'>&lt;p&gt;Someday, I'm going to learn to knit tiny swatches.  The first one I did for this hat was enormous, the size of a tea towel, but highlighted more than a few mistakes that I was making.

&lt;p&gt;Luckily, the cable pattern is composed of repeated motifs.  So, seeing these motifs work once was enough to know how they work throughout.

&lt;p&gt;Unfortunately, my first sketch for the lace pattern was done somewhat foolishly.  I believed that I could guess, from the pattern, what it would look like, conveniently forgetting that lace isn't just a pattern of holes: it also relies on a structure of slanted and upright stitches.

&lt;p&gt;What I'm trying to say is that my first sketch was uglier than ugly.  I've revised it now, and on paper, it looks nice.  In practice, I don't know.  So I'm doing the sensible thing this time and knitting it again.

&lt;p&gt;There needs to be a pattern to the decreases anyhow, and I've no idea what that'll be.  Thus, he sensible thing is 30 rows of swatch, a lifeline and then some puzzling out what decreases go where.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-8083893286213833180?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/8083893286213833180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=8083893286213833180' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/8083893286213833180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/8083893286213833180'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/swatch-knit-thyself.html' title='Swatch, knit thyself'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-7853151918204354800</id><published>2009-02-13T14:26:00.004-05:00</published><updated>2009-02-13T15:44:58.665-05:00</updated><title type='text'>Why I like circular knitting</title><content type='html'>&lt;p&gt;So, I'm swatching a project.  A project that's 2/3 cabling and 1/3 lace.  A project where there's at least one stitch pattern that's heavily used and may not even be possible.

&lt;p&gt;And as is my wont, perhaps foolishly, I'm swatching it flat.  20 rows, 51 stitches.  Which is fine for the lace pattern: It was meant to be flat and I can live with that.  The cable pattern is much worse.

&lt;p&gt;It actually looks reasonable enough charted in the round.  I have a very rough sketch, written before I realised a few things.  Flat, though, that's a different story.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_iq3iNCSmnh8/SZXJyNHxFtI/AAAAAAAAAHQ/f4ALj6w7udk/s1600-h/Weeping+Willow+Swatch.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 284px; height: 400px;" src="http://1.bp.blogspot.com/_iq3iNCSmnh8/SZXJyNHxFtI/AAAAAAAAAHQ/f4ALj6w7udk/s400/Weeping+Willow+Swatch.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5302366000651507410" /&gt;&lt;/a&gt;

&lt;p&gt;I'm deliberately only knitting a fraction of the pattern as a swatch, and that still took me an hour and a half to draw.  It's going to be &lt;em&gt;fun&lt;/em&gt; when I draw the entire pattern, seeing as that chart is 1/125th of the pattern.

&lt;p&gt;At least the pattern will be flat.

&lt;hr/&gt;

&lt;p&gt;Well, after realising that I was going to be working the chart forever and ever, I re-charted the lace pattern to run 30 rows, the minimum possible to see the pattern working.  

&lt;p&gt;The cable pattern is only 20, but if I'm feeling ambitions, I'll extend it, just to see the whole sweep of the pattern.  Unfortunately, this actually makes the swatch larger.  Fortunately, only by 100 stitches.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-7853151918204354800?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/7853151918204354800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=7853151918204354800' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/7853151918204354800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/7853151918204354800'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/why-i-like-circular-knitting.html' title='Why I like circular knitting'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_iq3iNCSmnh8/SZXJyNHxFtI/AAAAAAAAAHQ/f4ALj6w7udk/s72-c/Weeping+Willow+Swatch.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-9184962989497938943</id><published>2009-02-12T16:01:00.007-05:00</published><updated>2009-02-12T17:30:03.014-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='textures'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='socks'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Shadow Check Socks - Pattern</title><content type='html'>&lt;a href="http://www.flickr.com/photos/29571367@N07/3274225049/" title="Shadow Check Socks - Completed by turvity, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3525/3274225049_8d5ddbaa52.jpg" width="500" height="386" alt="Shadow Check Socks - Completed" class="right"/&gt;&lt;/a&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ravelry.com/dl/kearsley-schieder-wethy-designs/17047?filename=Shadow_Check_Socks.pdf"&gt;&lt;img 
class="left" src="http://2.bp.blogspot.com/_iq3iNCSmnh8/SYdBZ2tJj_I/AAAAAAAAAFY/zq60iaC3dHM/s400/download_free_button_rav.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5298275399062097906" /&gt;&lt;/a&gt;

&lt;p&gt;Well, they took two weeks to get together, but I'm happy to say that these socks are finally a pair.  Happily, they are indeed as thick, dense and warm as I'd hoped when &lt;a href="http://wetpixels.blogspot.com/2009/02/simple-textured-socks.html"&gt;I first started planning for them&lt;/a&gt;.

&lt;h3&gt;Requirements&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt; 300m sport weight yarn
  &lt;li&gt; 3.5mm double-pointed needles
  &lt;li&gt; 3.5mm straight needles 
  &lt;li&gt; A crochet hook
&lt;/ul&gt;

&lt;h3&gt;Measurements&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt; The circumference of the ball of the foot.
  &lt;li&gt; The length of the foot.
  &lt;li&gt; The circumference of the ankle.
  &lt;li&gt; The circumference of the middle calf.
  &lt;li&gt; Your gauge in circular &lt;span class="pattern"&gt;heel stitch&lt;/span&gt;.
  &lt;li&gt; Your gauge in &lt;span class="pattern"&gt;seed rib&lt;/span&gt;.
&lt;/ul&gt;

&lt;p&gt;For the gauges, fear not.  You'll be knitting a number (quite a
number, in fact) of rounds of those stitches before you need to know
gauge, so it's simple to measure directly on the sock
itself.

&lt;h3&gt;Instructions&lt;/h3&gt;

&lt;h4&gt;Casting On&lt;/h4&gt;

&lt;p&gt;Perform a provisional cast on of eight stitches, knitting four
rows, as for the &lt;a
href="http://wetpixels.blogspot.com/2009/01/simple-toe-up-socks.html"
&gt;Simple Toe-Up Socks&lt;/a&gt;

&lt;h4&gt;Heel Stitch Toe&lt;/h4&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iq3iNCSmnh8/SZSZu7QiN5I/AAAAAAAAAG4/mFWKIBze1ZM/s1600-h/Toe+Needle+Numbering.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 317px;" src="http://4.bp.blogspot.com/_iq3iNCSmnh8/SZSZu7QiN5I/AAAAAAAAAG4/mFWKIBze1ZM/s400/Toe+Needle+Numbering.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5302031692781991826" /&gt;&lt;/a&gt;

&lt;p&gt;Stitches between {braces} are repeated the number of times indicated.  Stitch counts are in  brackets and indicate the number of stitches on both the top and the bottom.

&lt;p&gt;Knit this pattern until you have enough stitches around to go snugly around the ball of the  foot.  End on an even-numbered round.

&lt;ol&gt;
  &lt;li&gt; Knit the entire round. 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k1, kfb, k4, kfb, k1 (10)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k4, kfb, k1 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(3 times), k2&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k2, {k1, s1 wyib}(3 times), k2 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k8, kfb, k1 (11)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k8 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(4 times), k1&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, {k1, s1 wyib}(4 times), k2 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k1, kfb, k7, kfb, k1 (13)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k7, kfb, k1 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k3, {s1 wyib, k1}(4 times), k2&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k2, {k1, s1 wyib}(4 times), k3 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k11, kfb, k1 (14)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k11 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k3, {s1 wyib, k1}(5 times), k1&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, {k1, s1 wyib}(5 times), k3 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k1, kfb, k10, kfb, k1 (16)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k10, kfb, k1 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(6 times), k2&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k2, {k1, s1 wyib}(6 times), k2 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k14, kfb, k1 (17)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k14 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(7 times), k1&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, {k1, s1 wyib}(7 times), k2 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k1, kfb, k13, kfb, k1 (19)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k13, kfb, k1 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k3, {s1 wyib, k1}(7 times), k2&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k2, {k1, s1 wyib}(7 times), k3 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k17, kfb, k1 (20)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k17 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k3, {s1 wyib, k1}(8 times), k1&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, {k1, s1 wyib}(8 times), k3 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k1, kfb, k16, kfb, k1 (22)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k16, kfb, k1 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(9 times), k2&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k2, {k1, s1 wyib}(9 times), k2 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k20, kfb, k1 (23)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k20 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(10 times), k1&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, {k1, s1 wyib}(10 times), k2 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k1, kfb, k19, kfb, k1 (25)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k19, kfb, k1 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(10 times), k2&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k2, {k1, s1 wyib}(10 times), k2 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k23, kfb, k1 (26)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k23 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k11, kfb, k1 (14)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k11 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k3, {s1 wyib, k1}(5 times), k1&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, {k1, s1 wyib}(5 times), k3 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k1, kfb, k10, kfb, k1 (16)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k10, kfb, k1 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(6 times), k2&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k2, {k1, s1 wyib}(6 times), k2 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k14, kfb, k1 (17)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k14 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(7 times), k1&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, {k1, s1 wyib}(7 times), k2 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k1, kfb, k13, kfb, k1 (19)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k13, kfb, k1 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k3, {s1 wyib, k1}(7 times), k2&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k2, {k1, s1 wyib}(7 times), k3 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k17, kfb, k1 (20)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k17 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: k3, {s1 wyib, k1}(8 times), k1&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, {k1, s1 wyib}(8 times), k3 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k1, kfb, k16, kfb, k1 (22)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k16, kfb, k1 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(9 times), k2&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k2, {k1, s1 wyib}(9 times), k2 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k20, kfb, k1 (23)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k20 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(10 times), k1&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, {k1, s1 wyib}(10 times), k2 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k1, kfb, k19, kfb, k1 (25)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k19, kfb, k1 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k2, {s1 wyib, k1}(10 times), k2&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k2, {k1, s1 wyib}(10 times), k2 
  &lt;li&gt;&lt;strong&gt;Top&lt;/strong&gt;: k23, kfb, k1 (26)&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: k1, kfb, k23
&lt;/ol&gt;

&lt;h4&gt;Knitting the body of the sock&lt;/h4&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iq3iNCSmnh8/SZSS5OAMlkI/AAAAAAAAAGw/LhGHm-5Ikuc/s1600-h/Body+Needle+Numbering.png"&gt;&lt;img class="right" src="http://3.bp.blogspot.com/_iq3iNCSmnh8/SZSS5OAMlkI/AAAAAAAAAGw/LhGHm-5Ikuc/s400/Body+Needle+Numbering.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5302024173031036482" /&gt;&lt;/a&gt;

&lt;p&gt;First, you'll need to divide the stitches again, this time onto
three needles.

&lt;p&gt;Count the stitches on needles 3 and 4 and divide it by three,
rounding down.  This is the number of stitches that should be moved
from the sole to the sides and top of the sock.  For the rest of the
pattern, these will be referred to as “side stitches”.

&lt;p&gt;For example, I have 25 stitches on needles 3 and 4 combined:

&lt;blockquote&gt;
&lt;p&gt; 25 / 3 = 8 1/3
&lt;p&gt; 8 1/3 ≈ 8
&lt;/blockquote&gt;

&lt;p&gt;So I want to move eight stitches, or four from each side.   First, transfer all the  stitches from needle 4 to needle 3.  Needle  3 will knit the sole of the sock, needles 1  and 2 will knit the top.  Next, place a  marker at the end of needle 1 and transfer  half of the side stitches from needle 3 to needle 1.  Place a marker at the end of needle 2 and  transfer the other half of the stitches from needle 3 to needle 2.  If you are moving an odd  number of stitches, move the extra stitch to the needle that has fewer toe increases (needle  1 for a right sock, needle 2 for a left.)

&lt;p&gt;Count the stitches on needle 3 again.  If there is an odd number of stitches, perfect.  If, on  the other hand, it's even, transfer one more stitch.  If you transferred an odd number  before, place this extra stitch on the opposite needle from the odd stitch.  Otherwise, place  it on the needle with fewer toe increases, as above.

&lt;p&gt;The pattern for the body of the sock is 6 rounds long.  Stitches in {braces} are repeated,  either to the end of needle 3 (for bottom stitches) or until the end of needle 2 (for top). The  side stitches are knit in pattern for the top.

&lt;ol&gt;
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: {Knit 1}&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: {Purl 1}  
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: {k1, p1}&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: p1, {k1, p1} 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: {p1}&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: p1, {yop, s1 wyib, purl 1} Here, the yarn should wrap over the slipped stitch, making one stitch crossed  over the other. 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: {k1}&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: p1, {drop the yo from the previous row, si wyib, p1} Dropping the yarn over looks like it should leave a very loose stitch around the  slipped stitch.  However, purling the next stitch adjusts its tension, bringing it  tighter once more. 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: {p1, k1}&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: p1, {s1 wyib, p1} 
  &lt;li&gt; &lt;strong&gt;Top&lt;/strong&gt;: {p1}&lt;br/&gt;
  &lt;strong&gt;Bottom&lt;/strong&gt;: p1, {s1 wyib, p1}
&lt;/ol&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iq3iNCSmnh8/SZSZxGezFfI/AAAAAAAAAHI/ZOohVIRYRmY/s1600-h/Shadow+Check+Socks+-+Body.png"&gt;&lt;img 
class="centre" style="cursor:pointer; cursor:hand;width: 400px; height: 264px;" src="http://2.bp.blogspot.com/_iq3iNCSmnh8/SZSZxGezFfI/AAAAAAAAAHI/ZOohVIRYRmY/s400/Shadow+Check+Socks+-+Body.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5302031730154345970" /&gt;&lt;/a&gt;

&lt;h4&gt;Knitting a gusseted heel&lt;/h4&gt;

&lt;p&gt;This is a slight adaptation of the heel described in the &lt;a
href="http://wetpixels.blogspot.com/2009/01/simple-toe-up-socks.html"
&gt;Simple Toe-Up Socks&lt;/a&gt; pattern.

&lt;p&gt;Continue knitting the 6 rounds of pattern for the body until it measures 70% of the length  of the foot.  For me, each pattern repeat is less than a centimetre long, so you can expect  this to be rather a lot of knitting.  My foot is 22cm long, so I calculate that as follows:

&lt;blockquote&gt;
&lt;p&gt;22 cm ∗ 0.7 = 15.39 cm
&lt;/blockquote&gt;

&lt;p&gt;Finish on round 6 of the body pattern, having just knit the bottom of the sock.

&lt;p&gt;For the next while, needles 1 and 2 will not be used, so do what you will with the stitches on  them, be it transferring them to a holder, placing them on a spare needle or scrap of yarn or  simply leaving them on the two double-pointed needles.

&lt;p&gt;The heel is knit flat and the yarn is currently placed so that the next row is the wrong side,  so, to complete the shadow check pattern, knit the row, which will finish the sole with a row  of purl stitches.  Then, with straight needles of the same size as your double-pointed  needles, knit the following 2-row pattern:

&lt;h5&gt;Heel Stitch&lt;/h5&gt;

&lt;ol&gt;
  &lt;li&gt; (right side) k1, {s1, k1}
  &lt;li&gt; Purl the row
&lt;/ol&gt;

&lt;p&gt;This is &lt;span class="pattern"&gt;heel stitch&lt;/span&gt; again.  However, since there are no increases or decreases at play, it's 16 times simpler than it was at the toe.

&lt;p&gt;Knit this until the heel is 95% of the length of  the foot (i.e. 4-6 rows below the foot length).

&lt;h4&gt;Turning the heel&lt;/h4&gt;

&lt;p&gt;Next, knit row 1 of the &lt;span class="pattern"&gt;heel stitch&lt;/span&gt; pattern,  stopping 2 stitches before the end of the row.  Turn the sock and knit row 2, stopping 2  stitches before the end of the row.

&lt;p&gt;Knit row 1 again, stopping 4 stitches before  the end of the row, then row 2, stopping 4  stitches before the end of the row.

&lt;p&gt;Continue like this, losing two more stitches  each row, until you have either 9 or 7 stitches  left live and have just completed a purl row  (row 2).

&lt;p&gt;Next, knit row 1 again, knitting the last live stitch together with
the first saved stitch and knitting the second saved stitch.  Turn
your work and knit row 2, purling the last live stitch together with
the first saved stitch and purling the second saved stitch.

&lt;p&gt;Repeat those two steps until all the stitches are live again.
Congratulations.  You're halfway done the heel.

&lt;h4&gt;Picking up from the heel flap&lt;/h4&gt;

&lt;p&gt;You should have just completed a purl row so, to get your
yarn in position to knit in the round, knit across the heel one more
time, this time using two double-pointed needles, one holding each
half of the heel.

&lt;p&gt;Begin &lt;a href="http://wetpixels.blogspot.com/2009/01/picking-up-knit-selvedge.html" &gt;picking up stitches&lt;/a&gt; along the side of the heel flap with the
second double-pointed needle used to knit the heel.  If you look at
the selvedge, you should have a raised row of slipped stitches below a
slightly-curled row of knit stitches.  You'll want to pick up one
stitch per row along the heel, so insert a needle in the hole beneath
the two strands of the knit stitch, insert your double-pointed needle
into the hole underneath it and knit one stitch.

&lt;p&gt;Repeat this for every row of the heel, as well as picking up two
stitches from the first stitch on the top of the sock in order to
ensure that there's not a hole between the heel and the top of the
sock.  Note the number of stitches you picked up, place a marker at
the end of the needle and knit the side stitches onto it.  This keeps
you from working the decreases across a gap between needles.

&lt;p&gt;Knit across the top of the sock, transferring stitches onto two
double-pointed needles if needs be.  With the second double-pointed
needle, pick up the same number of stitches along the heel flap as you
did on the other side, leaving a marker before the picked-up
stitches.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_iq3iNCSmnh8/SZSZwA_m3EI/AAAAAAAAAHA/4JrVderYKQg/s1600-h/Heel+Needle+Numbering.png"&gt;&lt;img class="right" style="cursor:pointer; cursor:hand;width: 361px; height: 400px;" src="http://1.bp.blogspot.com/_iq3iNCSmnh8/SZSZwA_m3EI/AAAAAAAAAHA/4JrVderYKQg/s400/Heel+Needle+Numbering.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5302031711501474882" /&gt;&lt;/a&gt;

&lt;p&gt;Finally, transfer the picked-up stitches and the side
stitches to the other needle on the back of the sock.  Time for the
final change in needle numbering.  As before, the needles are numbered
in clockwise order.  The two across the top of the foot are needles 2
and 3.  The two making up the heel are 1 and 4.

&lt;p&gt;That's it.  The heel has been turned, the stitches have been picked
up.  All that's left is to decrease the heel gusset until the sock is
the same size as it was at the ball of the foot.

&lt;h4&gt;Gusseting&lt;/h4&gt;

&lt;p&gt;Compared to everything you've been through so far, this bit is
easy.  Knit each round using the &lt;span class="pattern"&gt;seed rib&lt;/span&gt;
pattern.  To determine where in the pattern to start count the number
of stitches on needle 1.  If it's even, start the pattern on round 1,
if it's odd, start on round 4.

&lt;p&gt;Two stitches before the marker on needle 1, stop.  If you are on a
knit round, &lt;span class="stitch"&gt;K2TOG&lt;/span&gt;.  If you are on a purl
round, &lt;span class="stitch"&gt;P2TOG&lt;/span&gt;.  If you are on a seed round,
do not decrease.

&lt;p&gt;Continue knitting &lt;span class="pattern"&gt;seed rib&lt;/span&gt; until you
get to the marker on needle 4.  If you are on a knit round, &lt;span
class="stitch"&gt;SSK&lt;/span&gt;.  If you are on a purl round, &lt;span
class="stitch"&gt;S1, P1, PSSO&lt;/span&gt;.  If you are on a seed round, do
not decrease.

&lt;p&gt;Continue knitting
this pattern until you have the same number of stitches as you did for
the ball of the foot.

&lt;h5&gt;Seed Rib&lt;/h5&gt;

&lt;ol&gt;
  &lt;li&gt; Knit the round
  &lt;li&gt; k1, p1, repeat
  &lt;li&gt; Purl the round
  &lt;li&gt; Knit the round
  &lt;li&gt; p1, k1, repeat
  &lt;li&gt; Purl the round
&lt;/ol&gt;


&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iq3iNCSmnh8/SZSC_OJsodI/AAAAAAAAAGo/VTxhOWx0gHs/s1600-h/Seed+Rib.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 289px;" src="http://3.bp.blogspot.com/_iq3iNCSmnh8/SZSC_OJsodI/AAAAAAAAAGo/VTxhOWx0gHs/s400/Seed+Rib.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5302006683964056018" /&gt;&lt;/a&gt;

&lt;p&gt;The half above the black line is the normal pattern repeat.  The part below is the general pattern for the gusset decreases.

&lt;h4&gt;Ankle&lt;/h4&gt;

&lt;p&gt;If the ankle is to be smaller than the ball of the foot, continue
knitting &lt;span class="pattern"&gt;seed rib&lt;/span&gt; for three rounds.  Once
you have done that, work decreases as follows:

&lt;p&gt;If you are on a seed round, do not decrease.

&lt;p&gt;If you are on a knit round, knit the first stitch of needle 1,
&lt;span class="stitch"&gt;SSK&lt;/span&gt;, knit to the last three stitches on
needle 4, &lt;span class="stitch"&gt;K2TOG, K1&lt;/span&gt;.

&lt;p&gt;If you are on a purl round, purl one stitch, &lt;span
class="stitch"&gt;S1, P1, PSSO&lt;/span&gt;, purl to the last three stitches on
needle 4, &lt;span class="stitch"&gt;P2TOG, P1&lt;/span&gt;.

&lt;p&gt;Decrease in this way until you have the right number of stitches
for the ankle.

&lt;h4&gt;Calf&lt;/h4&gt;

&lt;p&gt;Knit four repeats of the &lt;span class="pattern"&gt;seed rib&lt;/span&gt;
pattern.  Count your stitches.  If they are not divisible by 6,
increase via &lt;span class="stitch"&gt;KFB&lt;/span&gt;s in the knit rounds as you knit rounds 1-5 of a fifth repeat.  Otherwise, knit those rounds without increase.

&lt;p&gt;That done, it's time to begin ribbing.  The pattern for the rib is
another Barbara Walker one: &lt;span class="pattern"&gt;embedded moss stitch
ribbing&lt;/span&gt;, with a single amendment.  It'll be worked over 6
stitches, rather than 7, to ensure that its repeat length matches that
of the &lt;span class="pattern"&gt;seed rib&lt;/span&gt;.

&lt;h5&gt;Embedded Moss Stitch Ribbing&lt;/h5&gt;

&lt;p&gt;Repeat these 6 stitches around the entire circumference of the sock.

&lt;ol&gt;
  &lt;li&gt; p2, k2, p1, k1 
  &lt;li&gt; p2, k2, p1, k1 
  &lt;li&gt; p2, k1, p1, k2 
  &lt;li&gt; p2, k1, p2, k2
&lt;/ol&gt;


&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iq3iNCSmnh8/SY8K_dMMn7I/AAAAAAAAAGg/x1dWFdhFZBg/s1600-h/Embedded+Moss+Stitch+Rib.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px" src="http://3.bp.blogspot.com/_iq3iNCSmnh8/SY8K_dMMn7I/AAAAAAAAAGg/x1dWFdhFZBg/s400/Embedded+Moss+Stitch+Rib.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5300467371722186674" /&gt;&lt;/a&gt;

&lt;p&gt;This gives a rib that is a 2-stitch purl gutter between columns of
knit stitches, with a twocolumn moss stitch pattern between them.

&lt;p&gt;Knit this ribbing until the sock is as long as you want it, knit
two rounds in &lt;span class="stitch"&gt;P2, K4&lt;/span&gt; ribbing, then cast off very loosely with the
following pattern: &lt;span class="stitch"&gt;P2, K4&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-9184962989497938943?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/9184962989497938943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=9184962989497938943' title='21 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/9184962989497938943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/9184962989497938943'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/shadow-check-socks-pattern.html' title='Shadow Check Socks - Pattern'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm4.static.flickr.com/3525/3274225049_8d5ddbaa52_t.jpg' height='72' width='72'/><thr:total>21</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-8840538485440179233</id><published>2009-02-08T16:21:00.003-05:00</published><updated>2009-02-08T16:39:48.549-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='socks'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Shadow Check Socks - One down!</title><content type='html'>&lt;a href="http://www.flickr.com/photos/29571367@N07/3263755001/" title="Shadow Check Socks - One Down! by turvity, on Flickr"&gt;&lt;img src="http://farm1.static.flickr.com/237/3263755001_5994be3010.jpg" width="500" height="354" alt="Shadow Check Socks - One Down!" class="right"/&gt;&lt;/a&gt;

&lt;p&gt;Well, I got lucky.  My first knit of the ankle and calf turned out to be exactly what I wanted and my lifeline ended up being wholly unnecessary.  So, with only a dozen metres or so of yarn left on my first ball, I turn to the second and begin knitting the second sock.

&lt;p&gt;This becomes helpful proofreading, as for the second sock, I follow the pattern that I wrote while knitting the first.  If it matches, I post the pattern as-is.  If not, I edit the erroneous parts of the pattern.

&lt;p&gt;While I was terribly happy to open Ravelry and mark the pattern as 50% done, I recognise that the second sock is likely to take almost as long as the first, as the slowness wasn't due to revising, but rather because the sock was simply a hell of a lot of knitting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-8840538485440179233?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/8840538485440179233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=8840538485440179233' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/8840538485440179233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/8840538485440179233'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/shadow-check-socks-one-down.html' title='Shadow Check Socks - One down!'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm1.static.flickr.com/237/3263755001_5994be3010_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-7604359943427460527</id><published>2009-02-07T15:36:00.008-05:00</published><updated>2009-02-12T15:16:17.973-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='textures'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Stitch Patterns - Charts</title><content type='html'>&lt;p&gt;In a little more thinking aloud, I charted the stitch patterns that I'm currently thinking about.  The sensible next step would be to swatch them, but I'm going to be daft and simply lifeline my socks in another few pattern repeats and use them as the swatch.

&lt;p&gt;Because I'm thinking about these patterns for socks, they're all given as circular directions, rather than flat.

&lt;h3&gt;Seed Rib&lt;/h3&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iq3iNCSmnh8/SZSC_OJsodI/AAAAAAAAAGo/VTxhOWx0gHs/s1600-h/Seed+Rib.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 289px;" src="http://3.bp.blogspot.com/_iq3iNCSmnh8/SZSC_OJsodI/AAAAAAAAAGo/VTxhOWx0gHs/s400/Seed+Rib.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5302006683964056018" /&gt;&lt;/a&gt;

&lt;p&gt;The half above the black line is the normal pattern repeat.  The part below is the general pattern for the gusset decreases.

&lt;p&gt;Stitches with a green background are repeated.

&lt;h3&gt;Mistake Stitch Rib&lt;/h3&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_iq3iNCSmnh8/SY8Fu1mYSgI/AAAAAAAAAGQ/dQj9YSRESxg/s1600-h/Mistake+Stitch+Rib.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px;" src="http://1.bp.blogspot.com/_iq3iNCSmnh8/SY8Fu1mYSgI/AAAAAAAAAGQ/dQj9YSRESxg/s400/Mistake+Stitch+Rib.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5300461588658539010" /&gt;&lt;/a&gt;

&lt;p&gt;This pattern uses a multiple of 4 stitches plus 3.  The stritches in green are repeated.

&lt;h3&gt;Embedded Moss Stitch Rib&lt;/h3&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iq3iNCSmnh8/SY8K_dMMn7I/AAAAAAAAAGg/x1dWFdhFZBg/s1600-h/Embedded+Moss+Stitch+Rib.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px" src="http://3.bp.blogspot.com/_iq3iNCSmnh8/SY8K_dMMn7I/AAAAAAAAAGg/x1dWFdhFZBg/s400/Embedded+Moss+Stitch+Rib.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5300467371722186674" /&gt;&lt;/a&gt;

&lt;p&gt;The six stitches of this pattern are repeated throughout.

&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;ETA (08/02/2009)&lt;/strong&gt;: Updated with better chart images.
&lt;p&gt;&lt;strong&gt;ETA (12/02/2009)&lt;/strong&gt;: Changed the &lt;span class="pattern"&gt;Seed Rib&lt;/span&gt; pattern, because the pattern of decreases in the seed rows was near-impossible to explain.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-7604359943427460527?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/7604359943427460527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=7604359943427460527' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/7604359943427460527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/7604359943427460527'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/stitch-patterns-charts.html' title='Stitch Patterns - Charts'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_iq3iNCSmnh8/SZSC_OJsodI/AAAAAAAAAGo/VTxhOWx0gHs/s72-c/Seed+Rib.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-6369373931948977415</id><published>2009-02-07T13:07:00.004-05:00</published><updated>2009-02-08T13:47:55.124-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='textures'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Stitch patterns</title><content type='html'>&lt;p&gt;So, these socks take three, possibly four stitch patterns: &lt;span class="pattern_name"&gt;heel stitch&lt;/span&gt;, &lt;span class="pattern_name"&gt;shadow check&lt;/span&gt;,  a stitch whose name I can't find, but will call &lt;span class="pattern_name"&gt;seed rib&lt;/span&gt; and a pattern for the ribbing along the calf.

&lt;p&gt;&lt;span class="pattern_name"&gt;Shadow check&lt;/span&gt; and &lt;span class="pattern_name"&gt;heel stitch&lt;/span&gt; are described in my &lt;a href='http://wetpixels.blogspot.com/2009/02/simple-textured-socks.html'&gt;original post about the shadow check socks&lt;/a&gt;.  The unnamed stitch, which I shall, in future, call &lt;span class="pattern_name"&gt;seed rib&lt;/span&gt;, is two rows garter, one row seed, two rows garter and one row seed (in the opposite pattern to the previous seed row).

&lt;p&gt;My first humbling lesson was that &lt;span class="pattern_name"&gt;heel stitch&lt;/span&gt; &lt;a href='http://wetpixels.blogspot.com/2009/02/simple-textured-socks-rip-number-3.html'&gt;is incredibly difficult in the round&lt;/a&gt;.  I've played with that some more, and in my working pattern, have managed to simplify the pattern for the toe dramatically.

&lt;p&gt;My second was that &lt;span class="pattern_name"&gt;shadow check&lt;/span&gt; draws the fabric far too tight to have any stockingette in the same row with it.  That realisation led directly to my changing the &lt;span class="pattern_name"&gt;seed rib&lt;/span&gt; from a part of the top to an all-over pattern, continuing it along the heel gusset.  The decision to include it over the gusset created its own problems, though.

&lt;p&gt;When decreasing for the gusset, to keep the pattern shrinking at an appropriate rate, there need to be decreases every round.  The problem with that is that every third row is seed, and the decreases need to happen in pattern.  Approaching the decreases, there are two possible patterns: &lt;span class="stitch"&gt;k1&lt;/span&gt;, &lt;span class="stitch"&gt;p1&lt;/span&gt;, &lt;span class="stitch"&gt;k1&lt;/span&gt;, (marker) &lt;span class="stitch"&gt;p1&lt;/span&gt;, &lt;span class="stitch"&gt;k1&lt;/span&gt; or &lt;span class="stitch"&gt;p1&lt;/span&gt;, &lt;span class="stitch"&gt;k1&lt;/span&gt;, &lt;span class="stitch"&gt;p1&lt;/span&gt;,  (marker) &lt;span class="stitch"&gt;k1&lt;/span&gt;, &lt;span class="stitch"&gt;p1&lt;/span&gt;.  As you can see, either one of those patterns means that a 2-stitch decrease will double up a stitch.  Taking the first as an example, if you k2tog, you end up with &lt;span class="stitch"&gt;k1&lt;/span&gt;, &lt;span class="stitch"&gt;k2tog&lt;/span&gt;, (marker) &lt;span class="stitch"&gt;p1&lt;/span&gt;, &lt;span class="stitch"&gt;k1&lt;/span&gt; and if you p2tog, you have the opposite problem: &lt;span class="stitch"&gt;k1&lt;/span&gt;, &lt;span class="stitch"&gt;p2tog&lt;/span&gt;, (marker) &lt;span class="stitch"&gt;p1&lt;/span&gt;, &lt;span class="stitch"&gt;k1&lt;/span&gt;.

&lt;p&gt;After several rounds of deliberation, I came up with the following pattern for decreasing the gusset in seed rows: 
&lt;ol&gt;
&lt;li&gt;Knit in pattern to two stitches before marker.
&lt;li&gt;If the last stitch  was knit, k2tog.  If it was purled, p2tog.
&lt;li&gt;Knit in pattern to the second marker.
&lt;li&gt;If the last stitch was knit, s1, p1, psso.  If it was purled, ssk.
&lt;li&gt;Knit in pattern to the end of the round.
&lt;/ol&gt;

&lt;p&gt;This ensures that the paired stitches match up nicely.  Its biggest advantage, though, is that it stops what I was doing before, namely looking at the previous seed row and guessing based on that.

&lt;p&gt;I still haven't decided what to do for the ribbing around the calf, though.  Conceivably, I could knit the lot in &lt;span class="pattern_name"&gt;seed rib&lt;/span&gt;, but I think I'd feel that I was ducking out.  I expect and anticipate that I'll end up increasing to a multiple of five stitches and relying on that lovely standby, &lt;span class="pattern_name"&gt;slip-stitch rib&lt;/span&gt;.

&lt;p&gt;On the other hand Barbara Walker has two patterns that intrigue me.  One is &lt;span class="pattern_name"&gt;mistake-stitch ribbing&lt;/span&gt;, which looks interesting from the photos, but would have to be rather altered to work as a circular pattern.  What it is is &lt;span class="stitch"&gt;k2&lt;/span&gt;, &lt;span class="stitch"&gt;p2&lt;/span&gt; rib, worked on one stitch less than the needed multiple of 4 stitches, so that there is a column of knit surrounded by jagged knit and purl stitches.

&lt;p&gt;The other is &lt;span class="pattern_name"&gt;embedded moss stitch ribbing&lt;/span&gt;.  That stitch pattern actually fits, interestingly, with &lt;span class="pattern_name"&gt;seed rib&lt;/span&gt;.  What it is is a pair of knit stitches enclosing two moss stitches.  Converting that would be easy and looks like it'll fit with the overall texture.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-6369373931948977415?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/6369373931948977415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=6369373931948977415' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/6369373931948977415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/6369373931948977415'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/stitch-patterns.html' title='Stitch patterns'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-4207623289160813718</id><published>2009-02-06T11:35:00.009-05:00</published><updated>2009-02-06T13:30:13.618-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='textures'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='socks'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Shadow Check Socks -- Time to start the heel flap</title><content type='html'>&lt;p&gt;So I spent two days playing with blogger, poking at layouts and widgets, all the while glancing over at the toe of the sock with no small amount of frustration.  The sock was giving me a slight case of knitter's block, not helped by my ballpark calculation that I needed 600 stitches for each centimetre of sock.

&lt;p&gt;Calling them &lt;a href="http://wetpixels.blogspot.com/2009/02/simple-textured-socks.html"&gt;Simple Textured Socks&lt;/a&gt; had passed from misnomer to outright lie.  The pattern may be 5 stitches and six rows, but it requires enough attentiveness that I was unable to knit it while reading (my habit for stockingette and cables).

&lt;p&gt;I finally put on a TV show, buckled down and started knitting, and was quite pleased to find that the interesting nature of the textures was carrying me along.  As I knitted, I was intensely curious to see how the two patterns would grow.

&lt;p&gt;I'm not sure whether to call this sock pattern beautiful or ugly.  "Idiosyncratic" certainly describes it.  The soles are dense but soft, about three times as thick as knit stitch.  Even when flattened, the fact that the sock is so very dense and thick means that it's rounded rather than sitting flat.

&lt;p&gt;The uppers are about half the thickness of the soles, but have an amazing amount of stretch to them.  Horizontally, they can stretch to double their width and vertically to half again their size.

&lt;p&gt;As well, and thankfully, the upper part of the sock gathers tightly in the vertical direction.  Since the soles take 6 rows to get the same amount of length as two rows of knit stitch, they are incredibly tight in the vertical sense.  Horizontally, they have the same density as heel stitch, something that I noted with my test swatch, and am using to my advantage.

&lt;p&gt;For these socks, I've been adopting my usual &lt;i&gt;modus operandi&lt;/i&gt;, namely knitting enough of the pattern that I have a clear picture of how it should look, then typing out an actual pattern and following it, amending mistakes and missteps as I go.

&lt;p&gt;To date, there have been three changes to my pattern as written:

&lt;ul&gt;
&lt;li&gt;I initially said that some stitches along the sides of the socks should be knit in stockingette, rather than working them in pattern.  I was wrong about that; it resulted in two columns of stitches that were trying to grow vertically at a rate three times that of the rest of the sock, resulting in unfortunate bulges.
&lt;li&gt;Because I was following my &lt;a href="http://wetpixels.blogspot.com/2009/01/simple-toe-up-socks.html"&gt;Simple Toe-Up Socks&lt;/a&gt; pattern, I indicated several rounds of decreases between the ball of the foot and the instep.  As it turns out, knitting a dense and stretch material neatly removes the need for that shaping, while making the socks' fit quite close.
&lt;li&gt;I had planned to knit the gussets and the calf in simple knit stitch, but it's becoming evident to me that changing the stitch that dramatically would look bad.&lt;br/&gt;
At the moment, I'm vacillating between four choices:
&lt;ol&gt;
&lt;li&gt;Knit the gusset and the calf in garter stitch.&lt;br/&gt;
Simple, straightforward, but I worry that it'll be too plain.
&lt;li&gt;Knit the gusset in stockingette but knit all stitches that are not decreased as a part of the gusset in garter.  This will eventually mean that the back garter stitches and the front garter stitches meet, making the calf a continuous band of garter stitch.&lt;br/&gt;
This adds some decoration to the previous pattern, but I'm afraid that what happened before with combining stockingette and a tighter stitch will recur, leaving the gusset to bulge outward.
&lt;li&gt;Knit the gusset and calf in the same pattern as the upper part of the sock, decreasing in pattern.&lt;br/&gt;
The only reason to not do this is that it continues the pattern of this sock requiring careful attentiveness.  In all honesty, I should bite the bullet, suck it up and knit the pattern.
&lt;li&gt;Knit the upper and back of the sock in pattern, but the gusset in stockingette.&lt;br/&gt;
I'm nearly certain that this idea will fail due to bulgy, unsightly gussets.
&lt;/ol&gt;
What I'm actually going to do is run a lifeline through the stitches once I've picked up off the edges of the heel flap, as, fortunately, all four of my possibilities start with one round of knit stitch.
&lt;/ul&gt; 

&lt;table class="gallery"&gt;
&lt;tr class="gallery_title"&gt;
&lt;td class="gallery_title"&gt;
&lt;h4&gt;Upper pattern&lt;/h4&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="gallery"&gt;
&lt;td valign="top" class="gallery_text"&gt;
&lt;p&gt;This is the as-yet-unnamed stitch that I adopted in order to keep the fabric throughout the sock in similar tension.  It comes out as two rows of garter, making a single garter ridge, followed by one row of seed.

&lt;p&gt;If you look carefully, you can see that the stitch pattern in the seed rows alternates, making this a 6-row pattern.

&lt;p&gt;I decided on this for the upper part of the socks in order to have a stitch that was elastic in both directions but gathered vertically.  And by "decided", I mean that I guessed at a texture and happened to get one that's quite functional.
&lt;/td&gt;
&lt;td class="gallery_pictures"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.flickr.com/photos/29571367@N07/3258512058/"&gt;&lt;img style="margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 250px;" src="http://farm4.static.flickr.com/3346/3258512058_8e9c3e573b.jpg" border="0" alt="Shadow Check Socks - Body (Worn) by turvity, on Flickr" /&gt;&lt;/a&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.flickr.com/photos/29571367@N07/3258513124/"&gt;&lt;img style="margin:0px auto 10px; cursor:pointer; cursor:hand;width: 250px;" src="http://farm4.static.flickr.com/3083/3258513124_33e35e99a3_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;

&lt;tr class="gallery_title"&gt;
&lt;td class="gallery_title"&gt;
&lt;h4&gt;Shadow Check - Right Side&lt;/h4&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="gallery"&gt;
&lt;td valign="top" class="gallery_text"&gt;
&lt;p&gt;This shows the outer part of the soles.  The right side of the &lt;i&gt;shadow check&lt;/i&gt; pattern is a row of purl stitch, a stretched slip stitch sitting atop a purled background, followed by another row of slip stitch.

&lt;p&gt;This pattern has next to no give in either direction, because the stitches that are slipped across five rows pull it very tight.

&lt;p&gt;Below the &lt;i&gt;shadow check&lt;/i&gt; pattern is the toe of the sock, showing how the raised (slipped) columns of &lt;i&gt;heel stitch&lt;/i&gt; match up exactly with the slip stitches in the &lt;i&gt;shadow check&lt;/i&gt; pattern.
&lt;/td&gt;
&lt;td class="gallery_pictures"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.flickr.com/photos/29571367@N07/3257810731/"&gt;&lt;img style="margin:0px auto 10px; cursor:pointer; cursor:hand;width: 250px;" src="http://farm4.static.flickr.com/3409/3257810731_8b5c190f58_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;

&lt;tr class="gallery_title"&gt;
&lt;td class="gallery_title"&gt;
&lt;h4&gt;Shadow Check - Wrong Side&lt;/h4&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="gallery"&gt;
&lt;td valign="top" class="gallery_text"&gt;
&lt;p&gt;This is the wrong side of the &lt;i&gt;shadow check&lt;/i&gt; pattern and why I picked it in the first place.

&lt;p&gt;The first picture is deliberately taken with the lighting highlighting the incredible depth of the texture.  The pattern makes the sole of the sock incredibly dense and soft.
&lt;/td&gt;
&lt;td class="gallery_pictures"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.flickr.com/photos/29571367@N07/3257684731/"&gt;&lt;img style="margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 250px;" src="http://farm4.static.flickr.com/3407/3257684731_4cc56721b9_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.flickr.com/photos/29571367@N07/3257686117/"&gt;&lt;img style="margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 250px;" src="http://farm4.static.flickr.com/3530/3257686117_68693073e8_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-4207623289160813718?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/4207623289160813718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=4207623289160813718' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/4207623289160813718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/4207623289160813718'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/shadow-check-socks-time-to-start-heel.html' title='Shadow Check Socks -- Time to start the heel flap'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm4.static.flickr.com/3346/3258512058_8e9c3e573b_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-8706562026843705297</id><published>2009-02-04T15:26:00.005-05:00</published><updated>2009-02-11T12:03:33.317-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='tinkering'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Dogwood Cabled Hat -- Pattern Amendments</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ravelry.com/dl/kearsley-schieder-wethy-designs/16909?filename=Dogwood_Cabled_Hat.pdf"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 108px; height: 60px;" src="http://2.bp.blogspot.com/_iq3iNCSmnh8/SYdBZ2tJj_I/AAAAAAAAAFY/zq60iaC3dHM/s400/download_free_button_rav.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5298275399062097906" /&gt;&lt;/a&gt;

&lt;p&gt;I've made a little change to the instructions: In decreasing the ribbing, I said to p1, s1, psso.  That's not really possible.  I meant to say s1, p1, psso.

&lt;p&gt;Also, I noticed that the pattern was written with my old method of typing stitches into a spreadsheet.  Since then, I've set up &lt;a href="http://www.inkscape.org/"&gt;Inkscape&lt;/a&gt; with a template SVG document that does a far far better job at giving me good-looking knitting patterns.

&lt;p&gt;So, while updating the PDF for the dogwood cabled hat, I added in a proper graphical pattern, which looks far far prettier than the previous ASCII-art one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-8706562026843705297?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/8706562026843705297/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=8706562026843705297' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/8706562026843705297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/8706562026843705297'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/dogwood-cabled-hat-pattern-amendments.html' title='Dogwood Cabled Hat -- Pattern Amendments'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iq3iNCSmnh8/SYdBZ2tJj_I/AAAAAAAAAFY/zq60iaC3dHM/s72-c/download_free_button_rav.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-4055835954407438674</id><published>2009-02-02T21:31:00.003-05:00</published><updated>2009-02-07T16:32:33.802-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='textures'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='tinkering'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Simple Textured Socks -- Rip number 3</title><content type='html'>&lt;p&gt;Well, I've ripped these things three times.  One because I realised that I wanted to do the toe in heel stitch.  Two because circular heel stitch while increasing is harder than I thought.

&lt;p&gt;So, in the interests of not ripping a fourth time, I'm going to write out one full repeat of the heel stitch-while-increasing pattern.

&lt;p&gt;It uses the needle numbering I've used elsewhere, where the two needles on top are 1 and 4, and the ones on the bottom are 2 and 3.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3266/3248940702_bf61f4a0eb_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 388px;" src="http://farm4.static.flickr.com/3266/3248940702_bf61f4a0eb_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;h3&gt;Heel Stitch Toe&lt;/h3&gt;

&lt;p&gt;First, knit four rows from a provisional cast on of 8 stitches and divide the 16 stitches between four needles.  You'll be on needle 4, so knit that needle to get to needle 1.

&lt;ol&gt;
  &lt;li&gt;Knit the entire round.
  &lt;li&gt;&lt;b&gt;Needle 1:&lt;/b&gt; k2, kfb, k1 (5)
  &lt;br/&gt;&lt;b&gt;Needle 2:&lt;/b&gt; k1, kfb, k2 (5)
  &lt;br/&gt;&lt;b&gt;Needle 3:&lt;/b&gt; k2, kfb, k1 (5)
  &lt;br/&gt;&lt;b&gt;Needle 4:&lt;/b&gt; k1, kfb, k2 (5)
  &lt;li&gt;&lt;b&gt;Needle 1:&lt;/b&gt; k1, s1 wyib, k3
  &lt;br/&gt;&lt;b&gt;Needle 2:&lt;/b&gt; k3, s1 wyib,, k1
  &lt;br/&gt;&lt;b&gt;Needle 3:&lt;/b&gt; s1 wyib, k1, s1 wyib, k2
  &lt;br/&gt;&lt;b&gt;Needle 4:&lt;/b&gt; k2, s1 wyib, k1, s1 wyib
  &lt;li&gt;&lt;b&gt;Needle 1:&lt;/b&gt; k3, kfb, k1 (6)
  &lt;br/&gt;&lt;b&gt;Needle 2:&lt;/b&gt; k1, kfb, k3 (6)
  &lt;br/&gt;&lt;b&gt;Needle 3:&lt;/b&gt; k5
  &lt;br/&gt;&lt;b&gt;Needle 4:&lt;/b&gt; k5
  &lt;li&gt;&lt;b&gt;Needle 1:&lt;/b&gt; k1, s1 wyib, k1, s1 wyib, k2
  &lt;br/&gt;&lt;b&gt;Needle 2:&lt;/b&gt; k2, s1 wyib, k1, s1 wyib, k1
  &lt;br/&gt;&lt;b&gt;Needle 3:&lt;/b&gt; s1 wyib, k1, s1 wyib, k2
  &lt;br/&gt;&lt;b&gt;Needle 4:&lt;/b&gt; k2, s1 wyib, k1, s1 wyib
  &lt;li&gt;&lt;b&gt;Needle 1:&lt;/b&gt; k4, kfb, k1 (7)
  &lt;br/&gt;&lt;b&gt;Needle 2:&lt;/b&gt; k1, kfb, k4 (7)
  &lt;br/&gt;&lt;b&gt;Needle 3:&lt;/b&gt; k3, kfb, k1 (6)
  &lt;br/&gt;&lt;b&gt;Needle 4:&lt;/b&gt; k1, kfb, k3 (6)
  &lt;li&gt;&lt;b&gt;Needle 1:&lt;/b&gt; k1, s1 wyib, k1, s1 wyib, k3
  &lt;br/&gt;&lt;b&gt;Needle 2:&lt;/b&gt; k3, s1 wyib, k1, s1 wyib, k1
  &lt;br/&gt;&lt;b&gt;Needle 3:&lt;/b&gt; s1 wyib, k1, s1 wyib, k3
  &lt;br/&gt;&lt;b&gt;Needle 4:&lt;/b&gt; k3, s1 wyib, k1, s1 wyib
  &lt;li&gt;&lt;b&gt;Needle 1:&lt;/b&gt; k5, kfb, k1 (8)
  &lt;br/&gt;&lt;b&gt;Needle 2:&lt;/b&gt; k1, kfb, k5 (8)
  &lt;br/&gt;&lt;b&gt;Needle 3:&lt;/b&gt; k6
  &lt;br/&gt;&lt;b&gt;Needle 4:&lt;/b&gt; k6
  &lt;li&gt;&lt;b&gt;Needle 1:&lt;/b&gt; k1, s1 wyib, k1, s1 wyib, k1, s1 wyib, k2
  &lt;br/&gt;&lt;b&gt;Needle 2:&lt;/b&gt; k2, s1 wyib, k1, s1 wyib, k1, s1 wyib, k1
  &lt;br/&gt;&lt;b&gt;Needle 3:&lt;/b&gt; s1 wyib, k1, s1 wyib, k3
  &lt;br/&gt;&lt;b&gt;Needle 4:&lt;/b&gt; k3, s1 wyib, k1, s1 wyib
&lt;/ol&gt;

&lt;p&gt;The rules are:

&lt;ul&gt;
  &lt;li&gt;Knit on increase rows.
  &lt;li&gt;Needle 1 starts on a knit stitch.
  &lt;li&gt;The last two stitches on the needle are never slipped, otherwise you get holes.
  &lt;li&gt;Needle 2 is needle 1 knit backwards (ends on a knit stitch).
  &lt;li&gt;Needle 3 starts on a slip stitch.
  &lt;li&gt;Needle 4 is needle 3 knit backwards (ends on a slip stitch).
&lt;/ul&gt;

&lt;p&gt;I think, when I write this pattern out in full, that I'll write it from 4 stitches on each needle through to 60 stitches around, simply because it's not a pattern that follows easily.

&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;ETA (7/2/2009)&lt;/strong&gt;: I've considered and toyed with this pattern more since noting it down, and the correct answer is that I'm numbering the needles wrong.  Realistically, 1 and 2 should be the top of the foot, 3 and 4 the bottom.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iq3iNCSmnh8/SY37YSPvGtI/AAAAAAAAAF4/n3_PYDBYsYA/s1600-h/Toe+Needle+Numbering.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 317px;" src="http://4.bp.blogspot.com/_iq3iNCSmnh8/SY37YSPvGtI/AAAAAAAAAF4/n3_PYDBYsYA/s400/Toe+Needle+Numbering.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5300168731118213842" /&gt;&lt;/a&gt;

&lt;p&gt;I worked that out when trying to chart the pattern and not wanting to either write a chart with directions like "start at the middle, read right to left for needle 1, read left to right for needle 2 and 3, then right http://www.blogger.com/img/blank.gifto left for needle 4, stopping at the middle" or to write a separate pattern for each needle.

&lt;p&gt;By changing how I thought of the needles, I was able to write a single chart for the top and the bottom, presented as two charts, as the bottom is the &lt;a href="http://en.wikipedia.org/wiki/Enantiomer"&gt;enantiomer&lt;/a&gt; of the top.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iq3iNCSmnh8/SY39PpL214I/AAAAAAAAAGA/ZBsQfIAfudY/s1600-h/Heel+Stitch+Toe+-+Top.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 299px; height: 400px;" src="http://4.bp.blogspot.com/_iq3iNCSmnh8/SY39PpL214I/AAAAAAAAAGA/ZBsQfIAfudY/s400/Heel+Stitch+Toe+-+Top.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5300170781680392066" /&gt;&lt;/a&gt;

&lt;p&gt;Deliberately, this chart goes on past what I reasonably expect as sizes, just to avoid having to try to give the extrapolation of the pattern as a process, as the algorithm for generating the toe relies somewhat on anticipating the next line.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-4055835954407438674?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/4055835954407438674/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=4055835954407438674' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/4055835954407438674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/4055835954407438674'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/simple-textured-socks-rip-number-3.html' title='Simple Textured Socks -- Rip number 3'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_iq3iNCSmnh8/SY37YSPvGtI/AAAAAAAAAF4/n3_PYDBYsYA/s72-c/Toe+Needle+Numbering.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-9208183932834750636</id><published>2009-02-02T15:32:00.008-05:00</published><updated>2009-02-06T13:28:03.127-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='textures'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='socks'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Simple Textured Socks</title><content type='html'>&lt;p&gt;This is meant as an alteration to my &lt;a href="http://wetpixels.blogspot.com/2009/01/simple-toe-up-socks.html"&gt;simple toe-up socks&lt;/a&gt;, but will en up with its own pattern when I'm done.

&lt;p&gt;Since knitting them, I've been thinking about how to improve the pattern, and have realised that I'd like the soles thicker and softer.  Barbara Walker has a stitch pattern called &lt;i&gt;shadow check&lt;/i&gt; on page 103 of &lt;u&gt;A Treasury of Knitting Patterns&lt;/u&gt;.  

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3257/3247864587_141f879420_m_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 240px; height: 202px;" src="http://farm4.static.flickr.com/3257/3247864587_141f879420_m_d.jpg" border="0" alt="Shadow Check -- Right Side" /&gt;&lt;/a&gt;

&lt;p&gt;It's a lovely slip-stitch pattern, with a beautiful wrong side.  The slipped stitches make it exceptionally dense, but the way it works makes it quite soft.  Better still is that it can be worked over the same number of stitches as &lt;i&gt;heel stitch&lt;/i&gt;.  

&lt;p&gt;However, there's a catch.  As with all of her patterns, &lt;i&gt;shadow check&lt;/i&gt; is given as a flat pattern with a right and a wrong side.  Further, it doesn't easily translate to knitting in the round, at least, not easily enough that I can do it in my head, so I'm jotting down the stitch pattern, converted to circular knitting, so that I can refer to it when needed.

&lt;h3&gt;Shadow check (circular)&lt;/h3&gt;

&lt;p&gt;Odd number of stitches.  Stitches in {braces} are repeated.

&lt;ol&gt;
&lt;li&gt;{Purl 1}
&lt;li&gt;Purl 1, {knit 1, purl 1}
&lt;li&gt;Purl 1, {yarn over, slip 1 with yarn in back, purl 1}
&lt;li&gt;Purl 1, {drop the yarn over from the previous round, slip 1 with yarn in back, purl 1}
&lt;li&gt;Purl 1, {slip 1 with yarn in back, purl 1}
&lt;li&gt;Purl 1, {slip 1 with yarn in back, purl 1}
&lt;/ol&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3086/3247865711_437d4a403e_m_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 240px; height: 232px;" src="http://farm4.static.flickr.com/3086/3247865711_437d4a403e_m_d.jpg" border="0" alt="Shadow Check -- Wrong Side" /&gt;&lt;/a&gt;

&lt;p&gt;That pattern will make up the sole of the sock, with the right side facing out and the dense, corrugated wrong side facing in as padding.  Because this will make the sole denser than simple knit stitch, I plan on having a small amount of ribbing on the top of the sock, to give the whole thing some give.

&lt;p&gt;The heel of the sock will be made from standard &lt;i&gt;heel stitch&lt;/i&gt;, which lines up exactly with &lt;i&gt;shadow check&lt;/i&gt; and begins with a row of purl, which will serve nicely to complete the previous pattern.

&lt;h3&gt;Heel Stitch&lt;/h3&gt;

&lt;p&gt;Odd number of stitches.  As this is worked flat, it has a right and a wrong side.

&lt;ol&gt;
&lt;li&gt;(Wrong Side) {Purl 1}
&lt;li&gt;Knit 1, {slip 1 with yarn in back, knit 1}
&lt;/ol&gt;

&lt;p&gt;Again, this is denser than simple knit stitch, but because the heel is knit flat and then gusseted, the only significant difference will be that there will be more decreases along the gusset.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3078/3247866487_e15111ee0e_m_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 240px; height: 148px;" src="http://farm4.static.flickr.com/3078/3247866487_e15111ee0e_m_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Because slip-stitch patterns look really interesting when worked in multiple colours, rather than doing what I did before and knitting the toe, heel and cuff in self-striping yarn and the foot and ankle in plain, instead I'm going to use self-striping yarn for the whole thing.

&lt;p&gt;Like everything, it's an experiment, but the only downside I see to this project is going to be that I can't work the sole while reading a book.  Anyhow, time to cast this project on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-9208183932834750636?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/9208183932834750636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=9208183932834750636' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/9208183932834750636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/9208183932834750636'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/simple-textured-socks.html' title='Simple Textured Socks'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-2962424674789431118</id><published>2009-02-01T23:47:00.009-05:00</published><updated>2009-02-02T14:15:20.600-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cables'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Two-Piece Knotwork Hat</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3116/3247334079_0af262458f_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 486px; height: 500px;" src="http://farm4.static.flickr.com/3116/3247334079_0af262458f_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Well, after six attempts at the brim and two test-knits plus one failed attempt at the body, this hat came together.  

&lt;p&gt;It began as a simple concept: I wanted to make a hat that had a single braid pattern running around the brim.  From that, form ollowed design.  I knew that I'd have to graft the brim into a loop and pick up stitches.

&lt;p&gt;That said, when starting, I noted grafting as something that I'd have to learn and had no clue what pattern I'd attach to the body of the hat.  In the end, I failed at grafting but learned a lot and ended up knitting four patterns for the body before finding one that wasn't overwhelming.

&lt;p&gt;The hat itself has the shift in density that I wanted, though.  Around the ears, the fabric is thick, dense and warm.  Atop the head, it flates out just slightly and sits loosely on my hair, hopefully preventing it from getting tangled and staticked by the hat.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ravelry.com/dl/kearsley-schieder-wethy-designs/16493?filename=Two-Piece_Knotwork_Hat.pdf"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 108px; height: 60px;" src="http://2.bp.blogspot.com/_iq3iNCSmnh8/SYdBZ2tJj_I/AAAAAAAAAFY/zq60iaC3dHM/s400/download_free_button_rav.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5298275399062097906" /&gt;&lt;/a&gt;

&lt;h3&gt;Requirements&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;150-175 metres of worsted weight yarn, preferably in two colours.
  &lt;li&gt;4mm straight needles. 
  &lt;li&gt;6mm circular needles and/or double-pointed needles.
  &lt;li&gt;Circular or double-pointed needles in a size smaller than 4mm.
  &lt;li&gt;A tapestry or sewing needle with an eye large enough to accommodate worsted weight yarn.
&lt;/ul&gt;

&lt;h3&gt;Instructions&lt;/h3&gt;

&lt;h4&gt;Brim&lt;/h4&gt;

&lt;h5&gt;Casting on&lt;/h5&gt;

&lt;p&gt;Cast on onto 4mm straight needles using a &lt;a href="http://wetpixels.blogspot.com/2009/01/simple-toe-up-socks.html"&gt;crocheted provisional cast-on&lt;/a&gt; of 22 stitches.  Crochet a chain, placing the yarn behind a needle after every crochet stitch and pulling it through the loop on the hook such that it wraps around the needle.  Chain a few more stitches and then pull the yarn through the loop.  This gives a provisional cast-on that can be easily undone later on.&lt;/p&gt;

&lt;p&gt;Knit the following pattern (brim chart):
&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;(wrong side) p2, k2, p6, k2, p6, k4
  &lt;li&gt;(right side) p4, k4, c2l, c2r, k4, p2, k2
&lt;li&gt;p2, k2, p4, k1, p4, k1, p4, k4
&lt;li&gt;p4, c2x2l, p1, c2x2r, p1, c2x2r, p2, k2
&lt;li&gt;p2, k2, p4, k1, p4, k1, p4, k4
&lt;li&gt;p4, k4, c2r, c2l, k4, p2, k2
&lt;li&gt;p2, k2, p6, k2, p6, k4
&lt;li&gt;p4, k2, c2x2r, p2, c2x2l, k2, p2, k2
&lt;li&gt;p2, k2, p6, k2, p6, k4
&lt;li&gt;p4, k4, c2l, c2r, k4, p2, k2
&lt;li&gt;p2, k2, p4, k1, p4, k1, p4, k4
&lt;li&gt;p4, c2x2l, p1, c2x2l, p1, c2x2r, p2, k2
&lt;li&gt;p2, k2, p4, k1, p4, k1, p4, k4
&lt;li&gt;p4, k4, c2r, c2l, k4, p2, k2
&lt;li&gt;p2, k2, p6, k2, p6, k4
&lt;li&gt;p4, k2, c2x2r, p2, c2x2l, k2, p2, k2
&lt;/ol&gt;

&lt;p&gt;Note here that the only difference between rows 1-8 and rows 9-16 is that on lines 4 and 12, the centre cable slants the opposite way.
&lt;/p&gt;
&lt;p&gt;Knit this pattern until, at the end of a set of 16 rows, the flat band that you are knitting is large enough to fit around the ears.  Knit row 1 again.  Cut the yarn, leaving a 1 metre long tail.
&lt;/p&gt;

&lt;h5&gt;Grafting&lt;/h5&gt;
&lt;p&gt;Untie the knot at the end of your crochet chain and tug on the tail of yarn to undo it.  As it releases stitches, pick them up on your free needle.  The stitches may be slightly twisted here, so make sure before grafting that they are in the order specified by row 1 of the pattern.
&lt;/p&gt;
&lt;p&gt;Holding up the two needles, they should be facing the same way without twisting the brim.  Turn them so that the brim forms a loop with the wrong side facing out.
&lt;/p&gt;
&lt;p&gt;You'll need to &lt;a href="http://wetpixels.blogspot.com/2009/01/two-piece-knotwork-hat-grafting-and.html" &gt;graft the stitches&lt;/a&gt; as they lie, using knit grafting (kg) for the knit stitches and purl grafting (pg) for the purls.  Or, in other words, kg 4 times, pg 6 times, kg twice, pg 6 times, kg twice, pg twice.
&lt;/p&gt;

&lt;h4&gt;Body&lt;/h4&gt;

&lt;h5&gt;Picking up&lt;/h5&gt;

&lt;p&gt;Hold the looped brim so that the k2, p2 rib is at the top and the p4 stockingette is at the bottom.  &lt;a href="http://wetpixels.blogspot.com/2009/01/picking-up-knit-selvedge.html" &gt;Pick up one stitch per row&lt;/a&gt; around the brim.  Because the body is knit on larger needles, there is no need to adjust for gauge.&lt;/p&gt;

&lt;h5&gt;Knitting the body&lt;/h5&gt;
&lt;p&gt;Count the picked up stitches.  If you didn't miss any rows, you should have a multiple of 16 stitches, plus one.  Find the nearest multiple of 16.  If it is greater than your number of stitches, you'll be increasing.  If it is less than the current number of stitches, you'll need to decrease.
&lt;/p&gt;
&lt;p&gt;Mark the beginning of the round.
&lt;/p&gt;
&lt;p&gt;Using the 6 mm needles, knit one round in p2, k2 rib.  If you need to increase, knit, evenly around the round, kfb, p2.  If you need to decrease, knit k2tog, k1, p2 evenly spaced around the body of the hat.
&lt;/p&gt;
&lt;p&gt;Knit the following pattern:
&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;p2, k2, p2, k2, p2, k2, p2, k2
&lt;li&gt;p2, k2, p2, k2, p2, k2, p2, k2
&lt;li&gt;p2, c2l, c2r, p2,  c2l, c2r
&lt;li&gt;p3, c2x2l, p4, c2x2r, p1
&lt;li&gt;p3, k4, p4, k4, p1
&lt;li&gt;p3, c2x2l, p4, c2x2r, p1
&lt;li&gt;p3, k4, p4, k4, p1
&lt;li&gt;p2, c2r, c2l, p2, c2r, c2l
&lt;li&gt;p2, k2, p2, k2, p2, k2, p2, k2
&lt;br/&gt;Do not knit the last two stitches of this round.  Instead, move your round marker back two stitches.  This is the new beginning of the round.
&lt;li&gt;c2l, c2r, p2, c2l, c2r, p2
&lt;li&gt;p1, c2x2r, p4, c2x2l, p3
&lt;li&gt;p1, k4, p4, k4, p3
&lt;li&gt;p1, c2x2r, p4, c2x2l, p3
&lt;li&gt;p1, k4, p4, k4, p3
&lt;br/&gt;These two rounds make a 4-stitch-wide twist in the columns of 4 knit stitches.
&lt;li&gt;c2r, c2l, p2, c2r, c2l, p2
&lt;br/&gt;Knit the first two stitches of the next round and move your round marker forward two stitches.  This is the new beginning of the round.
&lt;li&gt;p2, k2, p2, k2, p2, k2, p2, k2
&lt;li&gt;p2, c2l, c2r, p2, c2l, c2r
&lt;li&gt;p3, c2x2l, p4, c2x2r, p1
&lt;li&gt;p3, k4, p4, k4, p1
&lt;li&gt;p3, c2x2l, p4, c2x2r, p1
&lt;/ol&gt;

&lt;h5&gt;Reducing&lt;/h5&gt;
&lt;p&gt;If you are knitting on circular needles, as you knit the following rounds, when the stitches become too tight, switch to double-pointed needles.
&lt;/p&gt;

&lt;ol start="21"&gt;
&lt;li&gt;p3, k2tog, k2, p4, k2, ssk, p1 (14 stitches per repeat)
&lt;li&gt;p2, s1, p1, psso, c2l, p2, c2r, p2tog (12 stitches/repeat)
&lt;li&gt;p2, s1, p1, psso, k2, p2, k2, p2tog (10 stitches/repeat)
&lt;li&gt;p3, c2l, c2r, p1
&lt;li&gt;s1, p1, psso, p2, c2x2r, p2tog (8 stitches/repeat)
&lt;li&gt;p3, k4, p1
&lt;li&gt;p3, c2x2r, p1
&lt;li&gt;p3, ssk, k2tog, p1 (6 stitches/repeat)
&lt;li&gt;s1, p1, psso, p1, k2tog, p1 (4 stitches/repeat)
&lt;li&gt;s1, p1, psso, p2tog (2 stitches/repeat)
&lt;/ol&gt;

&lt;h3&gt;Finishing&lt;/h3&gt;
&lt;p&gt;Cut the yarn and draw the tail through the stitches on your double-pointed needles.  Pull it tight, knot it and weave it in.
&lt;/p&gt;
&lt;p&gt;The bottom of the brim is 4 rows of purl stitches and likely rolls in on itself.  Taking a tapestry needle and yarn of the same colour as the brim, sew the selvedge to the uppermost row of purl stitches.  
&lt;/p&gt;

&lt;h3&gt;Chart&lt;/h3&gt;
&lt;h4&gt;Brim&lt;/h4&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iq3iNCSmnh8/SYc2uC5RuyI/AAAAAAAAAFA/JJu1JS7B2Ic/s1600-h/Knotwork+Hat+Brim.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 309px;" src="http://3.bp.blogspot.com/_iq3iNCSmnh8/SYc2uC5RuyI/AAAAAAAAAFA/JJu1JS7B2Ic/s320/Knotwork+Hat+Brim.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5298263651303668514" /&gt;&lt;/a&gt;

&lt;h4&gt;Body&lt;/h4&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iq3iNCSmnh8/SYc4GuhOy5I/AAAAAAAAAFQ/2gcnFl_9igM/s1600-h/Two+Piece+Knotwork+Hat+Panels+Small-Small.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 217px; height: 400px;" src="http://2.bp.blogspot.com/_iq3iNCSmnh8/SYc4GuhOy5I/AAAAAAAAAFQ/2gcnFl_9igM/s400/Two+Piece+Knotwork+Hat+Panels+Small-Small.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5298265174842461074" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-2962424674789431118?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/2962424674789431118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=2962424674789431118' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/2962424674789431118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/2962424674789431118'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/02/two-piece-knotwork-hat.html' title='Two-Piece Knotwork Hat'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iq3iNCSmnh8/SYdBZ2tJj_I/AAAAAAAAAFY/zq60iaC3dHM/s72-c/download_free_button_rav.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-5720908638540955274</id><published>2009-01-31T14:45:00.005-05:00</published><updated>2009-02-02T14:16:59.086-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='cables'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Spiral-stitch hat</title><content type='html'>&lt;p&gt;Here's a nice simple hat pattern that popped into my head as I was re-knitting the knotwork hat.

&lt;p&gt;Cast on enough stitches (a multiple of 4) on a circular needle to go loosely around the head.  Join in the round and mark your starting point.

&lt;ol&gt;
&lt;li&gt;Knit one round of k2, p2 rib.
&lt;li&gt;Cable two left (place two stitches on a cable needle, purl one stitch, knit two stitches off of the cable needle), purl one, repeat.&lt;br/&gt;
At the end of the round, move your starting point forward one stitch.
&lt;/ol&gt;

&lt;p&gt;When the hat fits from ears to the top of the head, begin decreasing on the purl stitches.  As before, after every cable row, move your round marker forward one stitch.

&lt;p&gt;Essentially,ssk the last knit stitch of every fourth rib together with the following purl stitch.  Cable the next round, then ssk on the cable before the decreased one, cable again.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iq3iNCSmnh8/SYTHN-OhP3I/AAAAAAAAAE4/mJY5hlF6cAQ/s1600-h/Spiral-Stitch+Hat.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 295px; height: 320px;" src="http://3.bp.blogspot.com/_iq3iNCSmnh8/SYTHN-OhP3I/AAAAAAAAAE4/mJY5hlF6cAQ/s320/Spiral-Stitch+Hat.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5297578104550670194" /&gt;&lt;/a&gt;

&lt;p&gt;The chart shows four cables; the parts in purple are repeats of the pattern.  Rounds 1 and 2 should be repeated until the hat is tall enough, as described above.

&lt;p&gt;These decreases should spiral around to the middle, where they meet. 

&lt;p&gt;After you're done decreasing, pass the yarn through the remaining stitches and pull tight.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-5720908638540955274?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/5720908638540955274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=5720908638540955274' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/5720908638540955274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/5720908638540955274'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/spiral-stitch-hat.html' title='Spiral-stitch hat'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_iq3iNCSmnh8/SYTHN-OhP3I/AAAAAAAAAE4/mJY5hlF6cAQ/s72-c/Spiral-Stitch+Hat.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-523563068742404698</id><published>2009-01-31T13:24:00.002-05:00</published><updated>2009-02-02T14:12:17.026-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><category scheme='http://www.blogger.com/atom/ns#' term='failure'/><title type='text'>Two-Piece Knotwork Hat -- Ripping</title><content type='html'>&lt;p&gt;By round 20 of the hat body, I'd made four mistakes.  The biggest was that I'd cabled one of the twists left then right, but I'd also lost a stitch, realised that I wanted to alter the pattern at round 5, and didn't like how the knitted join between brim and body looked.

&lt;p&gt;Solution: Rip 20, start over.  I am, however, liking the feel of the second attempt more than the first, but this brings the false-start tally on this project to:

&lt;ul&gt;
&lt;li&gt;5 attempts at knitting a nice cable pattern for the brim.
&lt;li&gt;2 test knits for the body pattern.
&lt;li&gt;1 nearly-complete body ripped out.
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-523563068742404698?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/523563068742404698/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=523563068742404698' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/523563068742404698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/523563068742404698'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/two-piece-knotwork-hat-ripping.html' title='Two-Piece Knotwork Hat -- Ripping'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-8521386396593001117</id><published>2009-01-29T14:46:00.000-05:00</published><updated>2009-01-29T15:43:32.203-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Picking up a knit selvedge</title><content type='html'>&lt;p&gt;This is a step that I first tried two months ago.  I was pleasantly surprised that it was far less difficult than I was anticipating.&lt;/p&gt;

&lt;h3&gt;Preparation&lt;/h3&gt;

You'll need the following:

&lt;ul&gt;
  &lt;li&gt;Needles smaller than the ones you intend to use, of the same type (straight, circular or double-pointed.)&lt;/li&gt;
  &lt;li&gt;Knowledge of your vertical gauge (rows/cm) in the material from which you're picking up and your horizontal gauge (stitches/cm) with the yarn and needles that you'll be using to knit new material.&lt;br/&gt;
  &lt;em&gt;It is utterly vital that your gauge be over the same measurement.&lt;/em&gt;  Further, this will be a lot easier if the number of stitches is a whole number.  3.5 rows / cm is &lt;em&gt;much&lt;/em&gt; harder to work with than 7 rows / 2 cm.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Picking Up&lt;/h3&gt;

&lt;p&gt;For the sake of discussion, I'll presume that your stitches on the fabric from which you're picking up run left to right.  That is to say that the material has been rotated ninety degrees clockwise.  If it's turned the other way, reverse all lefts and right in the directions.&lt;/p&gt;

&lt;p&gt;Looking at the fabric, the knit stitches should make "V"s, all pointing left.  Directly above those should be your selvedge stitches.  Between those, above the point of the "V", there is a hole in the fabric.&lt;/p&gt;

&lt;p&gt;Insert one needle into this hole, then the other one beneath it.  There should be &lt;em&gt;two&lt;/em&gt; strands of yarn above the needles, as you're inserting the needles between two knit stitches.  Knit one stitch.&lt;/p&gt;

&lt;p&gt;Your new stitches should pull slightly to the right, making the hole through which you knit larger and more visible.  Fortunately, as you pick up the other selvedge stitches, this becomes less visible.&lt;/p&gt;

&lt;p&gt;Repeat this process with the next stitch, inserting the needle at the hole left of the knit "V" and knitting another stitch.  This will give you one picked-up stitch per row.&lt;/p&gt;

&lt;h3&gt;Equalizing Sizes&lt;/h3&gt;

&lt;p&gt;There's a problem here, as you might guess from the gauge measurements.  Namely, vertical gauge is different from horizontal gauge.  There's two ways to solve that problem, one easy, the other giving more control over the fabric.&lt;/p&gt;

&lt;p&gt;To cover the easy way first, simply knit the new material on needles where your horizontal gauge is the same as the vertical gauge on the fabric from which you're picking up.  That is to say, if your vertical gauge is 5 rows / 2 cm, increase the needle size to ones where you have a horizontal gauge of 5 stitches / 2 cm.&lt;/p&gt;

&lt;p&gt;Simple enough.  The drawback is that, by necessity, the new fabric will be looser than the fabric from which you were picking up.  If that doesn't bother you, carry on.  If it does, read on.&lt;/p&gt;

&lt;p&gt;To figure out how the fabric has to change requires a little math.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;( stitches / cm ) / ( rows / cm ) == stitches / row&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, for example, if I have a horizontal gauge of 9 stitches / 2 cm and a vertical gauge of 7 rows / 2 cm, it works out as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;( 9 stitches / 2 cm ) / ( 7 rows / 2 cm ) == 9 / 7 stitches / row&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The above is why I emphasized that the measurements need to be over the same distance.  So long as your measurements are the same distance, the distances cancel out.  It's also why the number of stitches need to be whole numbers: to avoid having fractions like 4.5 / 3.5.  This is important because later on, these numbers are used for counting stitches, and 4.5 stitches is not a valid count.&lt;/p&gt;

&lt;p&gt;If, on the other hand, I'm going from 24 rows / 5 cm to 8 stitches / 5 cm (small needles to larger ones), I get the calculation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;( 8 stitches / 5 cm ) / ( 24 rows / 5 cm ) == 8 / 24 stitches / row&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hopefully, it's evident that this part is simply creating a fraction with horizontal gauge over vertical gauge.  There's nothing more to it if your measurement is the same.&lt;/p&gt;

&lt;p&gt;If you want, reduce the fraction, so that both halves are as small as possible.  This is only necessary for mathematical correctness (or ease of counting) though, so if you don't remember how or don't want to bother, leave it as it is.&lt;/p&gt;

&lt;h4&gt;Increasing&lt;/h4&gt;

&lt;p&gt;If the numerator (top part of the fraction) is greater than the denominator (bottom part of the fraction), that indicates that you need to increase the number of stitches to meet gauge.&lt;/p&gt;

&lt;p&gt;Subtract the denominator from the numerator.  The result is how many stitches you have to gain.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I start with 9 / 7 stitches / row:&lt;/p&gt;
&lt;p&gt;numerator - denominator == 9 - 7 == 2&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So in that example, I need to gain 2 stitches over every 7.  In other words, in every 7 stitches knit, I need two increases.&lt;/p&gt;

&lt;h4&gt;Decreasing&lt;/h4&gt;

&lt;p&gt;If the numerator (top part of the fraction) is less than the denominator (bottom part of the fraction), you'll need to decrease the number of stitches to meet gauge.&lt;/p&gt;

&lt;p&gt;Subtract the numerator from the denominator.  The result is how many stitches you need to lose.  The result times 2 (because a decrease takes 2 stitches and makes them into 1 is how many stitches are required to make that many simple decreases.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I start with 8 / 24 stitches / row:&lt;/p&gt;
&lt;p&gt;denominator - numerator == 24 - 8 == 16&lt;/p&gt;
&lt;p&gt;16 * 2 == 32&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The result tells me that I need to lose 16 stitches, meaning that I need 32 stitches to decrease, or that I need to start rethinking needle sizes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I start with the more reasonable 7 / 9 stitches / row:&lt;/p&gt;
&lt;p&gt;denominator - numerator == 9 - 7 == 2&lt;/p&gt;
&lt;p&gt;2 * 2 == 4&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This time, I need to lose two stitches every 9.  That is to say, I need to decrease over 4 stitches, making them into 2.  Because 4 is less than 9, this change in gauge is plausible.&lt;/p&gt;

&lt;h3&gt;Actually changing the number of stitches&lt;/h3&gt;

&lt;p&gt;The easiest way is to either knit or purl a row (depending on the rest of the pattern).  Work all the increases or decreases on this row, which should sit close to the original fabric.&lt;/p&gt;

&lt;p&gt;If you're working increases, do so with an eye to the bottom of the pattern, that way a stitch knit front and back can become two knit stitches on the next row.&lt;/p&gt;

&lt;p&gt;In either case, it looks neater if the increases and decreases are spread out across the pattern, rather than being clustered together.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-8521386396593001117?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/8521386396593001117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=8521386396593001117' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/8521386396593001117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/8521386396593001117'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/picking-up-knit-selvedge.html' title='Picking up a knit selvedge'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-1963629640505821413</id><published>2009-01-29T13:51:00.007-05:00</published><updated>2009-01-29T15:44:29.672-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><category scheme='http://www.blogger.com/atom/ns#' term='failure'/><title type='text'>Two-Piece Knotwork Hat -- Grafting and Failure</title><content type='html'>&lt;p&gt; So, the brim to this hat is done; 60 cm of dense cabling.  That led me to a technique that I knew I was going to have to use.  Namely, grafting.&lt;/p&gt;

&lt;p&gt;Knowing that, I turned to Google, which gave me the helpful &lt;a href="http://nonaknits.typepad.com/nonaknits/2005/06/gulp_grafting.html"&gt;entry on nonaKnits blog&lt;/a&gt;  However, there was a catch: that and every tutorial I could find that made sense to me wanted to talk about stockingette.  My fabric is p4, k6, p2, k6, p2, k2.&lt;/p&gt;

&lt;p&gt;So I thought a bit.  Then I forged ahead, full of hubris.  And, to be blunt, I fucked up.  After the fact, it occured to me that, on a project that, to date, has had six test swatches knit to get the cable patterns right, I could have spared the ten minutes to knit two pieces of stockingette-plus-ribbing to screw around with.  Especially since I know better than to carry out experiments in a production environment.&lt;/p&gt;

&lt;p&gt;That said, I learned a &lt;em&gt;lot&lt;/em&gt; from my mistakes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Always, always, always swatch. &lt;/li&gt;
  &lt;li&gt;Kitchener stitch has four actions for each stitch.&lt;/li&gt;
  &lt;li&gt;If the yarn goes to the middle, that's a knit.  If it goes to the outside, that's a purl.&lt;/li&gt;
  &lt;li&gt;It's easiest to start on a knit stitch.&lt;/li&gt;
  &lt;li&gt;Grafted stitches are nearly impossible to pull out.&lt;/li&gt;
  &lt;li&gt;Always swatch, you fool.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, that said, I now see the geometry of the two basic stitches and I'm writing it down so that next time, I don't dig myself a hole.&lt;/p&gt;

&lt;p&gt;To start, have all stitches live and on two needles with the tips facing left as you hold them in front of you.  Have a tail of yarn at least 3 times the length of the edges that you're about to graft together.&lt;/p&gt;

&lt;p&gt;If the right side starts with a purl stitch, turn the work inside out, so that you're starting on a wrong side knit stitch.&lt;/p&gt;

&lt;h3&gt;Knit Stitch&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Pass the yarn knitwise through the first stitch on the needle nearest you.  Since it is going toward the middle, it's a knit stitch.&lt;br/&gt;
  Drop the stitch off the needle.&lt;/li&gt;
  &lt;li&gt;Pass the yarn purlwise through the next stitch on the needle nearest you.&lt;br/&gt;
  Leave this stitch on the needle.&lt;/li&gt;
  &lt;li&gt;Pass the yarn purlwise through the first stitch on the farther needle.  Since it is again going toward the middle, it's a knit stitch.
  Drop the stitch off the needle.&lt;/li&gt;
  &lt;li&gt;Finally, pass the yarn knitwise through the next stitch on the farther needle.&lt;br/&gt;
  Leave this stitch on the needle.&lt;/li&gt;
&lt;/ol&gt;

Repeat those four steps for every knit stitch, even if the next is a purl.  I count them in my head as 'in, out, in, out'

&lt;h3&gt;Purl Stitch&lt;/h3&gt;

Unsurprisingly, the purl is simply the inverse of the knit.

&lt;ol&gt;
  &lt;li&gt;Pass the yarn purlwise through the first stitch on the needle nearest you.  Since it is going away from the middle, it's a purl stitch.&lt;br/&gt;
  Drop the stitch off the needle.&lt;/li&gt;
  &lt;li&gt;Pass the yarn knitwise through the next stitch on the needle nearest you.&lt;br/&gt;
  Leave this stitch on the needle.&lt;/li&gt;
  &lt;li&gt;Pass the yarn knitwise through the first stitch on the farther needle.  Since it is again going toward the outside, it's a knit stitch.
  Drop the stitch off the needle.&lt;/li&gt;
  &lt;li&gt;Finally, pass the yarn purlwise through the next stitch on the farther needle.&lt;br/&gt;
  Leave this stitch on the needle.&lt;/li&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3506/3237166604_9886c6057d_m_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 240px; height: 121px;" src="http://farm4.static.flickr.com/3506/3237166604_9886c6057d_m_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;In the case of this hat, I'm going to suck it up, live with my mistakes and carry on.  Fortunately, the next step in this project is far less arduous: picking up one stitch per row of ribbing from a knit selvedge.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-1963629640505821413?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/1963629640505821413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=1963629640505821413' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/1963629640505821413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/1963629640505821413'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/two-piece-knotwork-hat-grafting-and.html' title='Two-Piece Knotwork Hat -- Grafting and Failure'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-981446075603726448</id><published>2009-01-27T21:56:00.005-05:00</published><updated>2009-02-02T14:16:59.087-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cables'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Two-piece Knotwork Hat -- Brim 1</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3257/3232705624_f3b7ca7044_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 313px; height: 500px;" src="http://farm4.static.flickr.com/3257/3232705624_f3b7ca7044_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

I'm knitting, flat, the brim of a hat which will eventually be joined together and picked up.  This is the chart that I'm following, a paired three-strand braid.  The left side will be picked up and be knitted with a further knotwork pattern.  The right side will be folded over and sewn together, to make a rolled border.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iq3iNCSmnh8/SX_Ol9fG7fI/AAAAAAAAAEo/qSjlPG3E7Z0/s1600-h/Knotwork+Hat+Brim.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 309px;" src="http://3.bp.blogspot.com/_iq3iNCSmnh8/SX_Ol9fG7fI/AAAAAAAAAEo/qSjlPG3E7Z0/s320/Knotwork+Hat+Brim.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5296178838366514674" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-981446075603726448?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/981446075603726448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=981446075603726448' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/981446075603726448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/981446075603726448'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/two-piece-knotwork-hat-brim-1.html' title='Two-piece Knotwork Hat -- Brim 1'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_iq3iNCSmnh8/SX_Ol9fG7fI/AAAAAAAAAEo/qSjlPG3E7Z0/s72-c/Knotwork+Hat+Brim.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-1031811422571039923</id><published>2009-01-24T19:58:00.008-05:00</published><updated>2009-02-11T12:04:10.835-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cables'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Dogwood Cabled Hat</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3339/3224081404_1afb0643d6_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 500px; height: 410px;" src="http://farm4.static.flickr.com/3339/3224081404_1afb0643d6_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;I've just finished knitting this hat, with a cable pattern of stylised trees.  The trees themselves are based on a binary tree structure, but have twists and knots around themselves and around other branches.  The way the branches converge into a cluster reminded me of &lt;a href="http://en.wikipedia.org/wiki/Flowering_dogwood"&gt;groves of dogwood&lt;/a&gt;, hence the name.

&lt;p&gt;The trunk expands (via a pair of decreases and increases), then splits into two branches.  These branches twine once around themselves then split again, the four split branches twining before dividing yet again into a meshwork of twisting branches that stretch to the top of the hat.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ravelry.com/dl/kearsley-schieder-wethy-designs/16909?filename=Dogwood_Cabled_Hat.pdf"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 108px; height: 60px;" src="http://2.bp.blogspot.com/_iq3iNCSmnh8/SYdBZ2tJj_I/AAAAAAAAAFY/zq60iaC3dHM/s400/download_free_button_rav.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5298275399062097906" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-1031811422571039923?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/1031811422571039923/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=1031811422571039923' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/1031811422571039923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/1031811422571039923'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/dogwood-cabled-hat.html' title='Dogwood Cabled Hat'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iq3iNCSmnh8/SYdBZ2tJj_I/AAAAAAAAAFY/zq60iaC3dHM/s72-c/download_free_button_rav.gif' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-3717124352257080091</id><published>2009-01-24T11:56:00.004-05:00</published><updated>2009-02-02T14:16:01.698-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Joy of Cables Hat -- Completed extension</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3372/3222168951_f04d1a5ac3_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 500px; height: 337px;" src="http://farm4.static.flickr.com/3372/3222168951_f04d1a5ac3_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

Here is the travelling cable hat after I got done adding eight rounds of k2p2 rib to it.  It's warmer, especially around the ears.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-3717124352257080091?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/3717124352257080091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=3717124352257080091' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/3717124352257080091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/3717124352257080091'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/travelling-cale-hat-increases.html' title='Joy of Cables Hat -- Completed extension'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-3648393825785247815</id><published>2009-01-22T17:32:00.002-05:00</published><updated>2009-01-22T17:58:44.650-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tinkering'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Joy of Cables Hat -- extension</title><content type='html'>&lt;p&gt;I've worn the &lt;a href="http://wetpixels.blogspot.com/2009/01/joy-of-cables-hat.html"&gt;Joy of Cables Hat&lt;/a&gt; for a few days now, and am finding that my fear of running out of yarn made for a hat that was a little too shallow.  It just covers my ears and does so loosely.

&lt;p&gt;Fortunately, I have plenty of yarn in other colours, so I'm going to extend the hat by 5cm or so.  The edge is a simple k2p2 rib, so what I'll do is pick up stitches, purl one row to give the hat a line where it'll fold easily, then knit a brim in the same rib.

&lt;p&gt;Because I'm trying to tighten the hat a bit as well, I'll keep the rib the same.  Were it already a snug fit, I'd increase on rows 4 and 8, in the purl part of the ribbing.

&lt;p&gt;The hat was knit on 5mm needles, so I'll pick up with much smaller needles.  The closest smallercircular needles at hand were 3.5mm, so I'm using those.  Picking up stitches is a simple enough prospect: there's a hole just right of each stitch, so I insert a needle under both threads of the cast on, insert the point of my circular needle and knit a stitch.  Then I repeat that 120 times, one per stitch.

&lt;p&gt;After that, I'll knit from the 3.5mm needles onto 6mm ones, as that was the size used for the hat.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-3648393825785247815?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/3648393825785247815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=3648393825785247815' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/3648393825785247815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/3648393825785247815'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/joy-of-cables-hat-extension.html' title='Joy of Cables Hat -- extension'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-6460177303439788638</id><published>2009-01-22T11:23:00.004-05:00</published><updated>2009-01-22T14:45:57.228-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gloves'/><category scheme='http://www.blogger.com/atom/ns#' term='tinkering'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Broad Street Mittens - Sleeve part 2</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3461/3217438897_73b7911eb0_m_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 240px; height: 231px;" src="http://farm4.static.flickr.com/3461/3217438897_73b7911eb0_m_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;I have knit the right sleeve now.  To fit my arm, it took a total of 68 rounds on 5mm DPNs.  As well, to work the increases that were necessary to making the sleeve taper outward, I chose a style of increase that fit the pattern.

&lt;ol&gt;
&lt;li&gt; Starting at the beginning of a rib, k3, p1, purl the front of the next stitch then knit the back (pfb). (6 stitches)
&lt;li&gt; k1, s1, k1, p3
&lt;li&gt; k2, p1, knit the front loop, then the back, of the next stitch (kfb), p1 (7 stitches)
&lt;li&gt; k1, s1, k1, p1, k2, p1
&lt;li&gt; k3, pfb, k2, pfb (9 stitches)
&lt;li&gt; k1, s1, k1, p2, k2, p2
&lt;li&gt; k3, p2, k1, kfb, p2 (10 stitches)
&lt;li&gt; k1, s1, k1, p2, k1, s1, k1, p2
&lt;li&gt; k3, p2, k3, p2
&lt;/ol&gt;

&lt;p&gt;At this point, another rib has been added, appearing as a line of knit stitches in the middle of a column of purl stitches.  

&lt;p&gt;I did this twice, once after knitting 30 rounds and again after knitting 50.  This allowed me to keep the glove tight around the wrist, flaring slightly as it approached my elbow.

&lt;p&gt;Because I like the zigzag that the ribbing pattern gives, I alternated green and brown yarns for the majority of it, ending the upper sleeve with a change to green and grey for ten rounds each.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-6460177303439788638?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/6460177303439788638/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=6460177303439788638' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/6460177303439788638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/6460177303439788638'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/broad-street-mittens-sleeve-part-2.html' title='Broad Street Mittens - Sleeve part 2'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-1514477396832317165</id><published>2009-01-21T11:26:00.004-05:00</published><updated>2009-01-21T12:10:20.252-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gloves'/><category scheme='http://www.blogger.com/atom/ns#' term='tinkering'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Broad Street Mittens -- Sleeve</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3401/3214982729_c8a448c560_m_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 240px; height: 223px;" src="http://farm4.static.flickr.com/3401/3214982729_c8a448c560_m_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;I've now knitted one pair of Janis Cortese's &lt;a href="http://farm4.static.flickr.com/3401/3214982729_c8a448c560_m_d.jpg"&gt;Broad Street Mittens&lt;/a&gt; in worsted yarn.  They fit nicely, but, unfortunately, only come to my wrist as I've not yet started knitting the cuff/sleeve.

&lt;p&gt;I want the sleeve to be at least 30 cm, so left it out of knitting the mittens until I saw how they turned out.  Though, I suppose that I could have started with the sleeve and converted it into arm warmers after the fact.

&lt;p&gt;I know that the current cuff of the mittens is 40 stitches around.  I also know that my wrist is tiny, so what I intend to do is reduce to 30 stitches around (I pulled the cuff of the glove tight and counted the number of stitches around my wrist) and then add 5 stitches halfway up my arm.

&lt;p&gt;Why 5?  Well, I've found myself knitting a &lt;i&gt;lot&lt;/i&gt; of k2p2 rib recently, so want to do something different, especially seeing as it looks serviceable but ultimately uninteresting when worked in multiple colours.  I have a nice olive drab yarn that I bought when I was first considering these mittens, and I'd like the sleeves to be striped.

&lt;p&gt;With those two constraints in mind, I considered various ribbings and decided that I'd work the following pattern:

&lt;ol&gt;
&lt;li&gt;knit 1, slip 1 purlwise with yarn in back, knit 1, purl 2 (repeat from start)
&lt;li&gt;knit 3, purl 2 (repeat from start)
&lt;/ol&gt;

&lt;p&gt;That way, the slipped stitches break the monotony of simple circular stripes, forming a slight wave pattern with the purl stitches, while still providing the texture and stretchiness of ribbing.

&lt;p&gt;The final consideration is what gauge to use.  I'd considered knitting the sleeve on 3.75mm needles, but gradually decided that, since it's a layer that will be worn along with a shirt and coat, that I might be wise to use 5mm needles to get a looser fabric.  That means that, rather than using 30 stitches as I'd intended, I'll need to use fewer.

&lt;p&gt;My gauge on the gloves was 8 stitches / inch and my gauge on the 5mm needles with worsted yarn is 5 stitches/inch.  From there, it's simple algebra to figure out how many I need:

&lt;blockquote&gt;
&lt;p&gt;desired stitches / 30 == 5 st/in / 8 st/in
&lt;p&gt;desired stitches == ( 5 / 8 ) * 30
&lt;p&gt;desired stitches = 18.75
&lt;/blockquote&gt;

&lt;p&gt;Since the pattern I'm using for the ribbing is a repeat of 5 stitches, I round 18.75 to 20 and know that I need to decrease half the stitches to make it fit.  In order to keep the glove from puffing out, I'm going to try picking up 40 stitches then decreasing ten of them the next row, knitting one row straight, then decreasing ten times on the next row.

&lt;p&gt;If that doesn't work, I'll rip it out, pick up and knit a round with 3.75mm needles, decrease to 30 stitches  and then knit onto the 5mm needles.

&lt;p&gt;A note, though: to keep the fabric from stretching as I pick up, that will be done on 3.75mm needles and the second round will be knit onto the 5mm ones.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-1514477396832317165?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/1514477396832317165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=1514477396832317165' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/1514477396832317165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/1514477396832317165'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/broad-street-mittens-sleeve.html' title='Broad Street Mittens -- Sleeve'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-7219440969362277573</id><published>2009-01-20T11:37:00.003-05:00</published><updated>2009-01-22T11:40:30.294-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gloves'/><category scheme='http://www.blogger.com/atom/ns#' term='tinkering'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Broad Street Mittens (errata)</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3508/3212345915_f909479846_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 500px; height: 473px;" src="http://farm4.static.flickr.com/3508/3212345915_f909479846_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;I'm currently knitting Janis Cortese's lovely Broad Street mittens, &lt;a href="http://www.knitty.com/ISSUEfall02/PATTbroadstreet.html"&gt;from the fall 2002 issue of Knitty&lt;/a&gt;.  In looking over the pattern, I decided to make a few adjustments in the interest of warmth.

&lt;p&gt;This is not a pattern so much as it is a list of modifications to the Broad Street pattern.

&lt;p&gt;Firstly, the pattern is meant to be knit with small needles and fingering-weight wool.  I decided that I wanted worsted wool, partly for warmth and partly because, when contemplating the pattern, I bought two balls of worsted in preparation.

&lt;p&gt;In what could be considered a moderately silly gauge swatch, I knit the palm, following the pattern.  Then, comparing the half-glove hat I had to the size of my hand, I worked out that it was about 50% too big.

&lt;p&gt;I cast on again, starting from the wrist as before.  This time, knowing the difference in size, I used 40 stitches of worsted weight on 3.75 mm needles, for a tight, dense fabric.  The reason for starting at the wrist rather than the cuff is that I'm planning to knit elbow-length sleeves onto the gloves, so will pick up around the wrist and knit until I'm satisfied.

&lt;p&gt;I knit two rows before getting to my second change: rather than knitting the palm in stockingette, I want it to be a thicker, denser fabric.  A quick browse of Barbara Walker's &lt;i&gt;Treasury of Knitting Patterns&lt;/i&gt; gave me k1s1 rib, or heel stitch.

&lt;p&gt;Thus the pattern for the palm became:

&lt;ol&gt;
  &lt;li&gt;knit the whole round
  &lt;li&gt;knit the whole round
  &lt;li&gt;k2, *k1, slip one stitch purlwise with the yarn in back, repeat from * until the second-last stitch on the second needle.  p1, knit the last stith front and back.  Knit the rest of the round.
  &lt;li&gt;knit the whole round
  &lt;li&gt;k2, *k1, sl1 wyib, repeat from * until reaching the purled stitch.  p1, kfb.  Knit the rest of the round.
  &lt;li&gt;knit the whole round.
&lt;/ol&gt;

&lt;p&gt;I repeated steps 5 and 6 until I'd added eight stitches, set those stitches aside and cast on nine stitches on the next row.

&lt;p&gt;For the thumb gusset decrease, I used the SSK/k2tog decrease until I again had ten stitches on the second needle.

&lt;p&gt;To finish the palm, I knit 12 rows with heel stitch on the palm, stockingette on the back.  The glove is longer lengthwise because the heel stitch used makes a far denser fabric vertically.  Also, my hands are very long.  Following the pattern, 8 rows would be more accurate.

&lt;p&gt;Pinky finger was 4 from the palm, 5 from the back, plus one cast-on stitch.

&lt;p&gt;Extending the palm, I picked up 3 stitches from the pinky, rather than 2, to ensure no holes.  Knit 8 rounds, heel stitch on the front, stst on the back.

&lt;p&gt;The other fingers were 12 stitches, 16 stitches and 16 stitches, using 3 stitches picked up from the finger beside them each time.

&lt;p&gt;For the thumb, I picked up 12 stitches from the cast-on stitches and immediately decreased from 22 to 18, at a rate of two decreases every other row.  The thumb was finished in the same way as described in the pattern.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-7219440969362277573?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/7219440969362277573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=7219440969362277573' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/7219440969362277573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/7219440969362277573'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/broad-street-mittens-errata.html' title='Broad Street Mittens (errata)'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-3828206488257763393</id><published>2009-01-19T11:04:00.005-05:00</published><updated>2009-02-02T14:16:59.089-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cables'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='hats'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Joy of Cables Hat</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3476/3209263873_457e133417_m_d.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 240px; height: 180px;" src="http://farm4.static.flickr.com/3476/3209263873_457e133417_m_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;This is a pattern for a hat that just popped into my head.  I thought it would be neat to use cables in a spiral pattern, so that half the cables turned right and the other half turned left.  As I was knitting it, I added a few more things, like the cables being woven into an over/under/over basketweave.

&lt;p&gt;The hat is surprisingly soft and warm (I knit it from heavy worsted weight wool) and, because it is, in essence, a k2 p2 rib all the way around, it has a good amount of give to it.

&lt;p&gt;The pattern has cabling on three rounds of every eight, but it repeats often enough that it's elatively simple to keep in your head.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ravelry.com/dl/kearsley-schieder-wethy-designs/15963?filename=Joy_of_Cables_Hat.pdf"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 108px; height: 60px;" src="http://2.bp.blogspot.com/_iq3iNCSmnh8/SYdBZ2tJj_I/AAAAAAAAAFY/zq60iaC3dHM/s400/download_free_button_rav.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5298275399062097906" /&gt;&lt;/a&gt;

&lt;h3&gt;Requirements:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Double-pointed needles (I used 5mm DPNs)
&lt;li&gt;Optionally circular needles in the same gauge.
&lt;li&gt;100 to 150 metres of worsted weight yarn.  
&lt;/ul&gt;

&lt;p&gt;I knit the hat with a gauge of 2 stitches / cm in k2p2 rib and 5 rounds / 2 cm, but the pattern adapts easily to different sizes by adding or removing repeats both around and vertically.

&lt;p&gt;Cast on enough stitches on circular or double-pointed needles to go loosely around the head, with the number of stitches being a multiple of 8.  The pattern repeats are 8 stitches long, with two cables being worked every 8 stitches.

&lt;p&gt;Join in the round, then knit 2, purl 2 and mark that point as the start of your round.  The pattern from here on will be expressed as a set of eight stitches.  Repeat that as many times as needed to finish the round.

&lt;table&gt;
  &lt;tr&gt;&lt;td&gt;Rows 1-12&lt;/td&gt; &lt;td&gt;k2, p2, k2, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 13&lt;/td&gt; &lt;td&gt;Cable 2 left (c2l: Place two stitches on a cable needle or double-pointed needle, hold them in front of the work.  Purl the third stitch then knit the two stitches off the cable needle.), cable 2 right (c2r: Place one stitch on another needle, holding it to the back of the work.  Knit the next two then purl the stitch off of the cable needle), p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 14&lt;/td&gt; &lt;td&gt;p1, cable 2x2 right (c2x2r: Place two stitches on a cable needle, holding it to the back of the work.  Knit the next two then knit the stitches off of the cable needle), p3&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 15&lt;/td&gt; &lt;td&gt;p1, k4, p3&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 16&lt;/td&gt; &lt;td&gt;C2r, c2l, p2&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;At this point, every pair of cables has moved toward each other and crossed over, with the left cable going over the right.

&lt;table&gt;
  &lt;tr&gt;&lt;td&gt;Rows 17-19&lt;/td&gt; &lt;td&gt;k2, p2, k2, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 20&lt;/td&gt; &lt;td&gt;k2, p2, k2, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Stop this round four stitches before the end and mark this point.  There should be one column of ribbing left.  For the next four rounds, this is the new beginning of the round.&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 21&lt;/td&gt; &lt;td&gt;c2l, c2r, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 22&lt;/td&gt; &lt;td&gt;p1, cable 2x2 left (c2x2l: Place two stitches on a cable needle, holding it to the front of the work.  Knit the next two then knit the stitches off of the cable needle.), p3&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 23&lt;/td&gt; &lt;td&gt;p1, k4, p3&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 24&lt;/td&gt; &lt;td&gt;c2r, c2l, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 25&lt;/td&gt; &lt;td&gt;k2, p2, k2, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;At the end of this round, move the beginning of the round forward four stitches, so that it's back to where it was originally.&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Rows 26-28&lt;/td&gt; &lt;td&gt;k2, p2, k2, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 29&lt;/td&gt; &lt;td&gt;c2l, c2r, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 30&lt;/td&gt; &lt;td&gt;p1, c2x2r, p3&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 31&lt;/td&gt; &lt;td&gt;p1, k4, p3&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 32&lt;/td&gt; &lt;td&gt;c2r, c2l, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Rows 33-35&lt;/td&gt; &lt;td&gt;k2, p2, k2, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 36&lt;/td&gt; &lt;td&gt;k2, p2, k2, p2, marking 4 stitches before the end as the new beginning of the round.&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 37&lt;/td&gt; &lt;td&gt;c2l, c2r, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Row 38&lt;/td&gt; &lt;td&gt;p1, c2x2l, p3&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;This is where I chose to begin decreasing.  If you want a deeper hat, continue the pattern, knitting rows 23-38 until the hat is as long as you want it and stopping on a row where you are either cabling 2x2 left or cabling 2x2 right.

&lt;p&gt;For the decrease rows, the pattern repeats quicker and quicker as you go because the pattern is decreasing in size with every row.  Row 1 repeats every 8 stitches, row 2 every 6, row 3 every 5, etc.  

&lt;p&gt;If you are using circular needles, when the hat becomes too tight on them, switch to double-pointed needles in the same size.

&lt;table&gt;
  &lt;tr&gt;&lt;td&gt;Decrease row 1&lt;/td&gt; &lt;td&gt;Slip slip knit (ssk: slip two stitches, inserting the right needle as if to knit them.  Insert the left needle into the front loops of the slipped stitches, wrap the yarn around the right needle and draw it through the loops), knit two together (k2tog: insert the right needle through the front loops of the first two stitches on the left needle.  Knit these stitches as if they were a single stitch), p4&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Decrease row 2&lt;/td&gt; &lt;td&gt;SSK, p4&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Decrease row 3&lt;/td&gt; &lt;td&gt;SSK, p3&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Decrease row 4&lt;/td&gt; &lt;td&gt;SSK, p2&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Decrease row 5&lt;/td&gt; &lt;td&gt;SSK, p1&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Decrease row 6&lt;/td&gt; &lt;td&gt;SSK&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Repeat row 6 until you have fewer than ten stitches on your needles.  Take the yarn and pull it through all of the remaining stitches before sliding them off the needle.  Pull the yarn inside the hat and tug it tight.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-3828206488257763393?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/3828206488257763393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=3828206488257763393' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/3828206488257763393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/3828206488257763393'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/joy-of-cables-hat.html' title='Joy of Cables Hat'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iq3iNCSmnh8/SYdBZ2tJj_I/AAAAAAAAAFY/zq60iaC3dHM/s72-c/download_free_button_rav.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-5007119799964255689</id><published>2009-01-18T15:30:00.003-05:00</published><updated>2009-02-02T20:47:49.534-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='socks'/><category scheme='http://www.blogger.com/atom/ns#' term='knitting'/><title type='text'>Simple Toe-up Socks</title><content type='html'>&lt;p&gt;This is a pattern for toe-up socks.  I amended several sock patterns and blended them together after finding that none of the patterns that I found on the internet fit my foot exactly.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3373/3206637771_d24443a0d7_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 468px;" src="http://farm4.static.flickr.com/3373/3206637771_d24443a0d7_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;These socks are fitted, so knowing your gauge with the needles and yarn that you'll be using is a must.  As well, you'll need to know the length of the foot, the circumference around the ball of the foot, the circumference around the instep and the circumference around the ankle.
&lt;h3&gt; Casting on &lt;/h3&gt;
&lt;p&gt;The sock starts with a provisional cast on.  The way that I find easiest is to crochet a chain around a needle, that way it incorporates both the crochet chain and picking up the stitches into a single step.  The toe is an adaptation of a &lt;a href="http://www.knitty.com/ISSUEwinter02/FEATtiptoptoes.html"&gt;pattern in Knitty&lt;/a&gt;.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3304/3202045519_70c0dd2827_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 375px;" src="http://farm4.static.flickr.com/3304/3202045519_70c0dd2827_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Using scrap yarn, start by tying a slip knot around a crochet hook.  Then, wrapping the yarn &lt;span style="font-style:italic;"&gt;behind&lt;/span&gt; a knitting needle, draw the yarn through the loop on the crochet hook, making a stitch.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3124/3202894204_f7a293f8d1_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 375px;" src="http://farm4.static.flickr.com/3124/3202894204_f7a293f8d1_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;You should have one loop on the crochet hook and one stitch below it, with the yarn wrapped around your knitting needle.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3125/3202895280_6986eec9e2_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 375px;" src="http://farm4.static.flickr.com/3125/3202895280_6986eec9e2_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Repeat this process until you have at least eight stitches wrapped around the needle, then continue crocheting a chain without wrapping the yarn around the needle.  This tail is useful to show what side you'll pull on to unzip the chain later on.  (&lt;a href="http://www.youtube.com/watch?v=aqWfea8oOH8"&gt;Video of crocheting a provisional cast on&lt;/a&gt;)

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3507/3202896404_536d34b5fa_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 375px;" src="http://farm4.static.flickr.com/3507/3202896404_536d34b5fa_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Next, with your working yarn, knit eight of the stitches on the needle, then continue working in stockingette until you have four rows, two knit and two purl.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3339/3202897700_53cdae4187_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 375px;" src="http://farm4.static.flickr.com/3339/3202897700_53cdae4187_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Separate the eight live stitches onto two double-pointed needles, then pull on the tail of the crochet chain to unfasten it, picking up the stitches of working yarn onto another two needles.

&lt;h3&gt; Knitting the toe &lt;/h3&gt;

&lt;p&gt;The first two needles are the top of the foot and the second two are the bottom.  Knit  the first four stitches, mark the second needle (it will be the start of the round, or needle 1) and continue knitting in the round until you're back to the first needle.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3266/3248940702_bf61f4a0eb_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 388px;" src="http://farm4.static.flickr.com/3266/3248940702_bf61f4a0eb_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;


&lt;p&gt;I like having the tip of the sock sit over my big toe, so I work the increases in a way that makes the toe lopsided.  The pattern for this is:

&lt;p&gt;Knit all but two stitches on needle 1, then knit the front and back (KFB) of the second-last stitch, inserting the right needle for a knit stitch, pulling a loop of yarn through, then inserting the right needle through the back loop of the same stitch, pulling a second loop of yarn through, then sliding the stitches off of the left needle.

&lt;p&gt;Knit the last stitch on needle 1, the first stitch on needle 2, KFB the second stitch, then knit to the second-last stitch on needle 3.  KFB that stitch, knit the last stitch on needle 3, the first stitch on needle 4, KFB the next stitch and knit to the end of the needle.

&lt;p&gt;Next, knit a round normally.  This loosens the stitches that you just made, while slowing the growth of the toe slightly.

&lt;p&gt;For the third round, knit all the stitches on needles 1 and 2, knit to the second-last stitch of needle 3, KFB, knit the last stitch and the first on needle 4, KFB the second and knit to the end of needle 4.

&lt;p&gt;The fourth round is another one of knit stitch.

&lt;span style="font-weight:bold;"&gt;Note&lt;/span&gt;: The above pattern is for the left foot.  For the right foot, the increases on the third row are on the second-last stitch of needle 1 and the second stitch of needle 2 instead.

&lt;p&gt;Work out how many stitches go around the ball of the foot by taking your measurement and multiplying it by your gauge.  In my case, my gauge working in the round is 3 stitches / cm and the ball of my foot is 16 cm in circumference.

&lt;blockquote&gt;16 cm * 3 stitches / cm == 48 stitches&lt;/blockquote&gt;

&lt;p&gt;Knit the above four rounds until your toe has grown to the size measured around the instep, rounded to the nearest even number of stitches.  If the yarn is stretchy, round down, if not, round up.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3506/3203334419_3d0da2c622_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 375px;" src="http://farm4.static.flickr.com/3506/3203334419_3d0da2c622_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;The toe will have a slightly more oblique slant on the side with twice as many increases (in this case, the left).  It's a slight difference, but means that, when on the foot, the stitches will stretch more naturally across your toes.
&lt;h3&gt; The body of the foot &lt;/h3&gt;
&lt;p&gt;With the toe done, knit 3 centimetres of knit stitch (stockingette).  

&lt;p&gt;Now, if the instep is smaller than the ball of the foot, decrease by knitting the second and third last stitches of one needle together and knitting an SSK on the second and third stitches of the next, both on the opposite side to where you did twice as many increases.  Repeat this until you have the right number of stitches for the instep.

&lt;span style="font-weight:bold;"&gt;SSK&lt;/span&gt;: Insert the right needle into the first stitch on the left as if to knit, then slip it.  Repeat for the second.  Insert the left needle through the front loops of the two slipped stitches, wrap the yarn around the right needle and pull it through, slipping the two stitches off the needle.  (&lt;a href="http://www.youtube.com/watch?v=RGwcYW3GG3M"&gt;Video&lt;/a&gt;)

&lt;p&gt;In my case, my instep is 15 cm around and my gauge is 3 stitches/cm, so I calculate the number of stitches for the instep as:

&lt;blockquote&gt;15 cm * 3 stitches / cm == 45 stitches&lt;/blockquote&gt;

&lt;p&gt;As that's an odd number and I'm using somewhat stretchy yarn, I round down to 44 stitches.  To calculate the number of rounds I need to decrease on, I subtract the instep stitches from the stitches around the ball of my foot and divide by 2.

&lt;blockquote&gt;
&lt;p&gt;48 stitches around the ball - 44 stitches around the instep == 4 stitches

&lt;p&gt;4 stitches / 2 decreases/round == 2 rounds of decreases
&lt;/blockquote&gt;

&lt;p&gt;So, on the next two rounds, this being a left sock, I knit the second and third-last stitches of needle 1 together and I SSK the second and third stitches on needle 2.  Were it a right sock, I would knit the second and third-last stitches of needle 3 together and SSK the second and third stitches of needle 4.

&lt;p&gt;Repeat this for as many rounds as needed to get to the instep size, then continue knitting stockingette.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3337/3204366375_de3e8d16d2_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 471px;" src="http://farm4.static.flickr.com/3337/3204366375_de3e8d16d2_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;h3&gt;Shaping a gusseted heel&lt;/h3&gt;
&lt;p&gt;Begin the heel when the sock is between 60% and 70% the length of the foot, shorter for stretchy yarn, longer for more solid.  The heel that I'm using is an adaptation of the &lt;a href="http://maiaspins.typepad.com/maiaspins/2007/05/toeup_gusseted_.html"&gt;pattern found here&lt;/a&gt;.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3297/3205179738_7d5c60beb6_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 471px;" src="http://farm4.static.flickr.com/3297/3205179738_7d5c60beb6_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;My foot is 22 cm long and I'm using stretchy yarn, so I calculate it as follows:

&lt;blockquote&gt;22 cm * 0.6 == 13.2 cm&lt;/blockquote&gt;

&lt;p&gt;Knowing that I have 4 rows of stockingette per centimetre, I knit 13 centimetres of foot, plus one row.

&lt;p&gt;In the last few rows before shaping the heel, I increase back to the size of the ball of the foot, knitting front and back on the second-last stitch of needle 1 and doing another KFB on the second stitch of needle 2.  Were this a right sock, I would do the same with needles 3 and 4 instead.

&lt;p&gt;I want twice as many rows to increase as to decrease, so I do the two KFBs, followed by a round of knit stitch, twice, ending on a round of knit stitch.

&lt;p&gt;Now, place all of the top stitches, plus 2/3 of the bottom stitches, onto another needle or a piece of scrap yarn.

&lt;p&gt;In my case, the sock is 48 stitches around, so I place the 24 top stitches onto a needle, as well as 1/3 the bottom stitches, divided equally between left and right sides.

&lt;blockquote&gt;
&lt;p&gt;24 bottom stitches * 2 / 3 == 16

&lt;p&gt;24 bottom stitches - 16 stitches remaining == 8 stitches set aside

&lt;p&gt;8 stitches set aside / 2 == 4 stitches from each side
&lt;/blockquote&gt;

&lt;p&gt;The stitches set aside are left alone while you knit the heel flap as flat stockingette (knit the right side, purl the wrong side).  Continue knitting that until  the sock plus heel flap is 90% or 95% the length of the foot.

&lt;p&gt;In my case, with a 22 cm foot and stretchy yarn, I want the sock to total:

&lt;blockquote&gt;22 cm * 0.9 == 19.8 cm&lt;/blockquote&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3518/3205178494_21e6c886a2_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 471px;" src="http://farm4.static.flickr.com/3518/3205178494_21e6c886a2_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Once the heel flap is the proper length, starting on the right side, knit all but the two last stitches, turn your work and purl all but the two last stitches.  On the next row, knit all but the four last stitches, turn your work and purl all but the four last stitches.

&lt;p&gt;Repeat this until only half the stitches on the heel flap are live, then, starting on a knit row, knit the live stitches, knitting the last live stitch together with the first one that was left alone.  Finish the row by knitting the second stitch that was left alone.  

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3524/3207475012_8d0a3896ed_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 384px; height: 500px;" src="http://farm4.static.flickr.com/3524/3207475012_8d0a3896ed_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;On the next row, purl the live stitches, purling the last one together with the first one left alone.  Purl the second one left alone.  Repeat these two steps until all the stitches on the heel flap are live again.  At this point, you will be on a knit row.  Knit back across these to position the yarn for picking up the stitches.

&lt;p&gt;Next, divide the stitches on the heel flap onto two double pointed needles and, starting on the side with the yarn, pick up the stitches along the side of the heel flap by lifting the stitch with another needle and knitting into it with the double pointed needle holding the yarn.  (&lt;a href="http://www.youtube.com/watch?v=DF34R6KX-cc"&gt;Video of picking up stitches&lt;/a&gt;)

&lt;p&gt;Repeat this for every row of the heel flap plus one stitch beside your saved stitches.  This ensures that there's no hole where the heel meets the top of the sock.  

&lt;p&gt;With a second double-pointed needle, knit half of the saved stitches.  With a third, knit the other half and pick up along the other side of the heel flap.  Finally, on the fourth needle, knit the remaining half of the heel flap.  You should have two needles with few stitches on them and two needles with quite a lot, having picked up along the heel flap.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3513/3207476862_ac6c3f7a2a_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 381px; height: 500px;" src="http://farm4.static.flickr.com/3513/3207476862_ac6c3f7a2a_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Divide the stitches among your four double-pointed needles so that the two that meet at the back of the heel have the heel stitches, the heel flap stitches and four of the stitches from the front of the sock.  

&lt;p&gt;From now on, the back of the sock is the starting point.  The first needle is the left-hand heel needle, the second and third are the two on the front and the fourth is the other heel needle.

&lt;p&gt;Knit all but 6 stitches on the first double-pointed needle, knit two stitches together, place a marker after that stitch, then knit the next four.  Continue to knit across the top of the sock, placing a marker after the first four stitches on the fourth double-pointed needle.  SSK the next two stitches, then continue to knit.

&lt;p&gt;Continue knitting in the round, knitting the two before the first marker together and SSKing the two after the second marker, until you have the same number of stitches as for the instep.
&lt;h3&gt;Ankle and calf&lt;/h3&gt;
&lt;p&gt;Knit one round after you finish shaping the heel.  Now, you want to increase or decrease to the circumference of the ankle.  

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3422/3206632865_7dae9f5c46_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 381px; height: 500px;" src="http://farm4.static.flickr.com/3422/3206632865_7dae9f5c46_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;To decrease, knit one on the first needle, then SSK, knit the rest of the stitches until the third-last stitch on the fourth needle and knit two together, knitting the final stitch.  Repeat this until you have the correct number of stitches for the ankle.

&lt;p&gt;To increase, knit one on the first needle, knit the second stitch front and back, then knit the rest of the stitches until the second-last stitch on the fourth needle, KFB and knit the last stitch.  Knit the next round normally and repeat these two rounds until you have the correct number of stitches for the ankle.

&lt;p&gt;Continue to knit until you have 5 centimetres less than the desired length.  

&lt;p&gt;If you decreased for the ankle, knit half the stitches on each needle, then knit the next stitch front and back, repeating this for each needle, followed by a round of knit stitch, until you have the same number of stitches as you did for the ball of the foot.

&lt;p&gt;The number of stitches around the calf should be a number evenly divisible by four.

&lt;p&gt;Knit 5 centimetres of ribbing.  The easiest way is to knit two stitches and purl the next two, repeating this around the cuff of the sock for 5 centimetres.  

&lt;p&gt;For these socks, I went with a variant ribbing pattern, where on one row, I knit two, placed the yarn in front of the work as if to purl, slipped two stitches purlwise, then placed the yarn at the back of the work again, repeating that for one round, then knitting the next.

&lt;p&gt;When you have enough ribbing, cast off very loosely.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm4.static.flickr.com/3527/3207481412_6c05267029_d.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 477px;" src="http://farm4.static.flickr.com/3527/3207481412_6c05267029_d.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-5007119799964255689?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/5007119799964255689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=5007119799964255689' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/5007119799964255689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/5007119799964255689'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2009/01/simple-toe-up-socks.html' title='Simple Toe-up Socks'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-4323621346604480595</id><published>2008-02-05T16:03:00.000-05:00</published><updated>2008-02-05T16:04:29.050-05:00</updated><title type='text'>Clojure code, round 2</title><content type='html'>&lt;div class="code"&gt;&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;A simple application that acts as a very primitive time server and
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;client.
&lt;/span&gt;
(&lt;span class="keyword"&gt;import&lt;/span&gt; '(java.net BindException ServerSocket Socket)
        '(java.lang.reflect InvocationTargetException)
        '(java.util Date)
        '(java.io InputStream OutputStream StringWriter)
        '(java.util.concurrent Executors))



&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;Globals
&lt;/span&gt;
(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;DEFAULT-PORT&lt;/span&gt; 51345)

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;A structure defining the data in a unit test, as well as a global
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;list of all the tests.
&lt;/span&gt;(defstruct unit-test &lt;span class="builtin"&gt;:name&lt;/span&gt; &lt;span class="builtin"&gt;:description&lt;/span&gt; &lt;span class="builtin"&gt;:function&lt;/span&gt; &lt;span class="builtin"&gt;:after&lt;/span&gt;)
(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;ALL-TESTS&lt;/span&gt; {})



&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;Testing functions
&lt;/span&gt;
&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Unit test accessors
&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-name&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:name&lt;/span&gt;))
(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-description&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:description&lt;/span&gt;))
(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-function&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:function&lt;/span&gt;))
(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-after&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:after&lt;/span&gt;))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Add a new test structure to the list of unit tests, or replaces the
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;existing test of that name if it already exists.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;unit-tests-add&lt;/span&gt; [test]
  (&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;ALL-TESTS&lt;/span&gt;
       (assoc ALL-TESTS (unit-test-name test) test)))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Takes an unsorted and a sorted list of unit tests and moves / sorts
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;some of the tests in the unsorted list over to the sorted list
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-list-helper&lt;/span&gt; [unsorted sorted]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [nils (filter (comp not unit-test-after)
                     unsorted)
        alls (filter (comp (appl eql? &lt;span class="builtin"&gt;:all&lt;/span&gt;) unit-test-after)
                     unsorted)
        others (filter (fn [t] (not-any? (fn [x] (eql? (unit-test-after t)
                                                       (unit-test-after x)))
                                         (concat nils alls)))
                       unsorted)
        in-sorted (fn [t] (some (fn [x] (eql? (unit-test-name x)
                                              (unit-test-after t)))
                                (concat nils sorted)))]
    (&lt;span class="keyword"&gt;cond&lt;/span&gt; (first nils)
          (list (concat alls
                        (filter (complement in-sorted)
                                others))
                (concat nils
                        (filter in-sorted others)))
          (== (count alls)
              (count unsorted))
          (list nil
                (concat sorted alls))
          &lt;span class="builtin"&gt;:t&lt;/span&gt;
          (list (concat alls
                        (filter (complement in-sorted)
                                others))
                (concat sorted
                        (filter in-sorted others))))))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Returns a list of unit tests, sorted according to their :after
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;statement.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-list&lt;/span&gt;
  ([]
   (unit-test-list (vals ALL-TESTS) nil))
  ([unsorted sorted]
   (&lt;span class="keyword"&gt;if&lt;/span&gt; (not (first unsorted))
     (map (fn [test] (list (unit-test-description test)
                           (unit-test-function test)))
          sorted)
     (&lt;span class="keyword"&gt;let&lt;/span&gt; [helped-list (unit-test-list-helper unsorted sorted)
           unsorted (first helped-list)
           sorted (second helped-list)]
       (&lt;span class="keyword"&gt;recur&lt;/span&gt; unsorted sorted)))))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Run all the defined tests
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-all&lt;/span&gt; []
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [test-out (new StringWriter)]
    (&lt;span class="keyword"&gt;loop&lt;/span&gt; [test-list (unit-test-list)
                     failure false]
      (&lt;span class="keyword"&gt;let&lt;/span&gt; [test (first test-list)
            test-list (rest test-list)]
        (&lt;span class="keyword"&gt;cond&lt;/span&gt; (not test)
              (&lt;span class="keyword"&gt;do&lt;/span&gt; (&lt;span class="keyword"&gt;if&lt;/span&gt; failure
                    (println &lt;span class="string"&gt;"---\nSome tests failed."&lt;/span&gt;)
                    (println &lt;span class="string"&gt;"---\nAll tests passed."&lt;/span&gt;))
                  (list failure test-out))
              &lt;span class="builtin"&gt;:t&lt;/span&gt;
              (&lt;span class="keyword"&gt;let&lt;/span&gt; [test-result (&lt;span class="keyword"&gt;time&lt;/span&gt; (&lt;span class="keyword"&gt;binding&lt;/span&gt; [*out* test-out]
                                        (eval (list (second test)))))]
                (println &lt;span class="string"&gt;"Testing"&lt;/span&gt; (first test) &lt;span class="string"&gt;":"&lt;/span&gt; test-result)
                (&lt;span class="keyword"&gt;recur&lt;/span&gt; test-list
                       (&lt;span class="keyword"&gt;when&lt;/span&gt; (&lt;span class="keyword"&gt;or&lt;/span&gt; (not test-result)
                                 failure)
                         true))))))))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Define a testing function.  Same syntax as defn, only with a
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;description string and a list of extras (may be empty) 
&lt;/span&gt;(&lt;span class="keyword"&gt;defmacro&lt;/span&gt; &lt;span class="function-name"&gt;deftest&lt;/span&gt; [fname description extras &amp;amp; fdecl]
  `(&lt;span class="keyword"&gt;do&lt;/span&gt; (&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;~fname&lt;/span&gt; ~@fdecl)
       (unit-tests-add (struct unit-test
                               &lt;span class="builtin"&gt;:name&lt;/span&gt; (name '~fname)
                               &lt;span class="builtin"&gt;:description&lt;/span&gt; ~description
                               &lt;span class="builtin"&gt;:function&lt;/span&gt; ~fname
                               ~@extras))
       #'~fname))



&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;Utility functions
&lt;/span&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;current-time&lt;/span&gt; []
  (str (new Date)))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Generate an array of bytes from a string, suitable for passing to a
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;write() method.
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Has a unit test.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;byte-arr-from-string&lt;/span&gt; [#^String str]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; str (getBytes)))

(deftest test-byte-array-from-string &lt;span class="string"&gt;"string-&amp;gt;byte array conversion"&lt;/span&gt; ()
  ([]
   (test-byte-array-from-string (current-time)))
  ([str]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [barr (byte-arr-from-string str)
         bseq (map (comp char (appl aget barr))
                   (range (alength barr)))
         chseq (map char str)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (== (alength barr)
              (count bseq)
              (count chseq))
          (some true?
                (map eql?
                     bseq
                     chseq))))))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Takes a sequence of bytes (not a byte array, but a sequence) and
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;concatenates it into a string.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;string-from-byte-sequence&lt;/span&gt; [coll]
  (reduce strcat
          (map char coll)))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Gets the integer length of a string.  Returns nil for "" and nil.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; #^Int length-of-string [#^String string]
  (&lt;span class="keyword"&gt;if&lt;/span&gt; string
    (&lt;span class="keyword"&gt;.&lt;/span&gt; string (length))
    0))



&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;Listener functions
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;These control the server
&lt;/span&gt;
&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Make a new listener.  Returns that listener or nil if no listener
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;can be created on that port.
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Has a unit test.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; #^ServerSocket listener-new
  ([]
   (listener-new DEFAULT-PORT))
  ([port]
   (try (new ServerSocket port)
        (catch BindException except
               (println &lt;span class="string"&gt;"Address is already in use."&lt;/span&gt;)))))

(deftest test-listener-new &lt;span class="string"&gt;"creating a listener"&lt;/span&gt; ()
  ([]
   (test-listener-new DEFAULT-PORT))
  ([port]
   (with-open listener (listener-new port)
     (&lt;span class="keyword"&gt;when&lt;/span&gt; listener
       true))))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Logical predicates for whether a listener is open or closed.
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Have unit tests.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; #^Boolean listener-closed? [#^ServerSocket listener]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (isClosed)))
(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;listener-open?&lt;/span&gt; (complement listener-closed?))

(deftest test-listener-predicates &lt;span class="string"&gt;"listener open?/closed? predicates"&lt;/span&gt;
  (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="string"&gt;"test-listener-new"&lt;/span&gt;)
  ([]
   (test-listener-predicates DEFAULT-PORT))
  ([port]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)
         tests (&lt;span class="keyword"&gt;and&lt;/span&gt; (not (listener-closed? listener))
                    (listener-open? listener))]
     (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (close))
     (&lt;span class="keyword"&gt;and&lt;/span&gt; tests
          (not (listener-open? listener))
          (listener-closed? listener)))))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Wait for a connection to a given listener the return the socket to
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;that connection.
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;NOTE: This function is blocking.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; #^Socket listener-wait [#^ServerSocket listener]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (accept)))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Closes a given listener.  Really only for use from the REPL or from
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;unit tests, as actual code should be using (with-open ...)
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Has a unit test.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-close&lt;/span&gt; [#^ServerSocket listener]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (close)))

(deftest test-listener-close &lt;span class="string"&gt;"closing a listener"&lt;/span&gt;
  (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="string"&gt;"test-listener-predicates"&lt;/span&gt;)
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new DEFAULT-PORT)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (listener-open? listener)
          (not (listener-close listener))
          (listener-closed? listener)))))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Takes a socket, sends the current time through it, closes the
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;socket's output and returns the socket.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; #^Socket listener-send [#^Socket lsocket]
  (&lt;span class="keyword"&gt;..&lt;/span&gt; lsocket
      (getOutputStream)
      (write (byte-arr-from-string (current-time))))
  (&lt;span class="keyword"&gt;..&lt;/span&gt; lsocket (getOutputStream) (close))
  lsocket)

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Launches the supplied listener and then loops, waiting for
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;connections.
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;NOTE: Because it depends of (listener-wait ...), which is blocking,
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;this is qlso blocking.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run&lt;/span&gt; [listener port]
  (&lt;span class="keyword"&gt;loop&lt;/span&gt; [socket nil]
    (&lt;span class="keyword"&gt;if&lt;/span&gt; (listener-closed? listener)
      listener
      (&lt;span class="keyword"&gt;do&lt;/span&gt; (&lt;span class="keyword"&gt;when&lt;/span&gt; socket
            (&lt;span class="keyword"&gt;.&lt;/span&gt; (listener-send socket) (close)))
          (&lt;span class="keyword"&gt;recur&lt;/span&gt; (listener-wait listener))))))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Launches a listener as a background thread.  Returns that listener.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run-in-background&lt;/span&gt;
  ([]
   (listener-run-in-background DEFAULT-PORT))
  ([port]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)
                  exec (&lt;span class="keyword"&gt;.&lt;/span&gt; Executors (newSingleThreadExecutor))
                  run (appl listener-run listener port)]
     (&lt;span class="keyword"&gt;when&lt;/span&gt; listener
       (&lt;span class="keyword"&gt;.&lt;/span&gt; exec (submit run)))
     listener)))



&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;Connection functions
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;These control the client.
&lt;/span&gt;
&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Makes a new connection to a listener.  Times out in 5 seconds if no
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;connection is made.
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Has a unit test.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-new&lt;/span&gt;
  ([]
   (connection-new DEFAULT-PORT))
  ([port]
   (connection-new &lt;span class="string"&gt;"127.0.0.1"&lt;/span&gt; port))
  ([address port]
   (try (doto (new Socket address port)
          (setSoTimeout 5000))
        (catch InvocationTargetException except
               (println (strcat &lt;span class="string"&gt;"Could not connect to "&lt;/span&gt;
                                address
                                &lt;span class="string"&gt;" on port "&lt;/span&gt;
                                port))))))

(deftest test-connection-new &lt;span class="string"&gt;"creating a connection"&lt;/span&gt;
  (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="string"&gt;"test-listener-close"&lt;/span&gt;)
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-run-in-background)
         connection (connection-new)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (connection-new)
          (not (listener-close listener))
          (not (connection-new))))))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Reads data from a supplied socket as an array of bytes.  Stops on
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;timeout and when receiving the -1 end of stream byte.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-read&lt;/span&gt; [#^Socket conn]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [instream (&lt;span class="keyword"&gt;.&lt;/span&gt; conn (getInputStream))
        reader (fn [] (try (&lt;span class="keyword"&gt;.&lt;/span&gt; instream (read))
                           (catch InvocationTargetException except
                                  -1)))]
    (&lt;span class="keyword"&gt;loop&lt;/span&gt; [bytes nil
           current-byte (reader)]
      (&lt;span class="keyword"&gt;if&lt;/span&gt; (== current-byte -1)
        bytes
        (&lt;span class="keyword"&gt;recur&lt;/span&gt; (concat bytes (list current-byte))
               (reader))))))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Closes an open socket.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-close&lt;/span&gt; [#^Socket conn]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; conn (close)))

&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Opens a connection to a listener, reads out a byte sequence, then
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;returns that sequence as a string.
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Has a unit test.
&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-run&lt;/span&gt;
  ([]
   (connection-run DEFAULT-PORT))
  ([port]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [conn (connection-new port)
         str (&lt;span class="keyword"&gt;when&lt;/span&gt; conn
               (string-from-byte-sequence (connection-read conn)))]
     (&lt;span class="keyword"&gt;when&lt;/span&gt; conn 
       (connection-close conn))
     str)))

(deftest test-connection-run &lt;span class="string"&gt;"running a complete connection"&lt;/span&gt;
  (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="builtin"&gt;:all&lt;/span&gt;)
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-run-in-background)
         result (connection-run)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (listener-open? listener)
          (not (listener-close listener))
          (listener-closed? listener)
          (&amp;lt;= 0 (length-of-string result))
          (== 0 (length-of-string (connection-run)))))))
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-4323621346604480595?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/4323621346604480595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=4323621346604480595' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/4323621346604480595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/4323621346604480595'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2008/02/clojure-code-round-2.html' title='Clojure code, round 2'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-4828660414211471753</id><published>2008-02-05T15:55:00.000-05:00</published><updated>2008-02-05T16:02:33.229-05:00</updated><title type='text'>Clojure: continuing to look</title><content type='html'>&lt;h1&gt;My second look at Clojure&lt;/h1&gt;

&lt;h2&gt;Casting and complements&lt;/h2&gt;

&lt;p&gt;As demonstrated to me, &lt;code&gt;(. listener (isClosed))&lt;/code&gt; returns a fresh
boolean, rather than &lt;code&gt;Boolean.TRUE&lt;/code&gt; or &lt;code&gt;Boolean.FALSE&lt;/code&gt;.  So, while
the symbol looks fine in the REPL, when passed to &lt;code&gt;(if (. listener
(isClosed)) ...)&lt;/code&gt;, it is always true.&lt;/p&gt;

&lt;p&gt;So, I made the following pair of complementary&lt;sup&gt;1&lt;/sup&gt; utility functions:&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; #^Boolean listener-closed? [#^ServerSocket listener]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (isClosed)))

&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;listener-open?&lt;/span&gt; (complement listener-closed?))
&lt;/div&gt;

&lt;p&gt;&lt;code&gt;complement&lt;/code&gt; takes a function as its argument and returns a function
that does exactly the same thing as that function, only with its
return value inverted. Thus, (complement listener-closed?) returns a
function that does exactly what &lt;code&gt;listener-closed?&lt;/code&gt; does and then
returns the opposite value.&lt;/p&gt;

&lt;p&gt;In this case, it saves me from having to repeat &lt;code&gt;listener-closed?&lt;/code&gt;'s
details.  That way, if I ever need to change &lt;code&gt;listener-closed&lt;/code&gt;, in
order, say, to handle more than simple Java ServerSockets, I can do so
without having to make any changes to &lt;code&gt;listener-open?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note, though, that &lt;code&gt;listener-open?&lt;/code&gt; is a &lt;code&gt;def&lt;/code&gt; and &lt;em&gt;not&lt;/em&gt; a
&lt;code&gt;defn&lt;/code&gt;.  That's because &lt;code&gt;defn&lt;/code&gt; is a macro that wraps an &lt;code&gt;fn&lt;/code&gt;
around its body.  &lt;code&gt;complement&lt;/code&gt;, on the other hand, returns an
&lt;code&gt;fn&lt;/code&gt;, so I only need to bind it to a Var.&lt;/p&gt;

&lt;p&gt;I then amended &lt;code&gt;listener-run&lt;/code&gt; so that it uses this explicit cast
rather than just taking what ``ServerSocket gives it.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run&lt;/span&gt; [listener port]
  (&lt;span class="keyword"&gt;loop&lt;/span&gt; [socket nil]
    (&lt;span class="keyword"&gt;if&lt;/span&gt; (listener-closed? listener)
      listener
      (&lt;span class="keyword"&gt;do&lt;/span&gt; (&lt;span class="keyword"&gt;when&lt;/span&gt; socket
            (&lt;span class="keyword"&gt;.&lt;/span&gt; (listener-send socket) (close)))
          (&lt;span class="keyword"&gt;recur&lt;/span&gt; (listener-wait listener))))))
&lt;/div&gt;

&lt;p&gt;So, while I'm assigning casting, I should likely take care of the
warnings on loading this file, if for no reason other than that
they're starting to get a little excessively verbose.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (load-file &lt;/span&gt;&lt;span class="string"&gt;"/clojure/src/sockets.clj"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;)&lt;/span&gt;
Reflection warning, line: 17 - call to getBytes can't be resolved.
Reflection warning, line: 53 - call to accept can't be resolved.
Reflection warning, line: 56 - call to close can't be resolved.
Reflection warning, line: 397 - call to getOutputStream can't be resolved.
Reflection warning, line: 396 - call to write can't be resolved.
Reflection warning, line: 397 - call to getOutputStream can't be resolved.
Reflection warning, line: 396 - call to close can't be resolved.
Reflection warning, line: 70 - call to close can't be resolved.
Reflection warning, line: 78 - call to submit can't be resolved.
Reflection warning, line: 88 - call to java.net.Socket ctor can't be resolved.
Reflection warning, line: 97 - call to getInputStream can't be resolved.
Reflection warning, line: 98 - call to read can't be resolved.
Reflection warning, line: 109 - call to close can't be resolved.
#&amp;lt;Var: user/connection-run&amp;gt;
&lt;/div&gt;

&lt;p&gt;Simply, I went through and placed type hints on functions that call
out to Java in order to ensure that their methods resolve on load.&lt;/p&gt;

&lt;p&gt;Since I also noticed a few new things while reformatting the &lt;a href="http://clojure.sourceforge.net/reference/"&gt;Clojure
manual&lt;/a&gt; into a single
texinfo document for my own use, I'll also change my use of &lt;code&gt;(. var
(toString)&lt;/code&gt; to use Clojure's &lt;code&gt;str&lt;/code&gt; function:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;(str x)
    Returns x.toString(). (str nil) returns ""&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Building a testing framework&lt;/h2&gt;

&lt;p&gt;All of those casts are fairly minor refactorings that just make the
statement of what a &lt;code&gt;listener&lt;/code&gt; and &lt;code&gt;connection&lt;/code&gt; are to the
compiler.  On the other hand, the bug that I started with this time
would have been caught by the other thing I've been putting off.
Namely, actual an testing framework, rather than just eyeballing
results in the REPL.&lt;/p&gt;

&lt;p&gt;Now, I could go find JUnit, install that, and then see how well
Clojure links into it.  But, well, that sounds like a new project&lt;a
name="note1"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;So, instead, what I'll look at is defining what it is that my
functions are supposed to be doing, write a few tests, then add a
framework to glue those tests together.&lt;/p&gt;

&lt;h3&gt;Ugliness ensues...&lt;/h3&gt;

&lt;p&gt;Which ended up looking like:&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;DEFAULT-PORT&lt;/span&gt; 51345)

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-byte-array-from-string&lt;/span&gt;
  ([]
   (test-byte-array-from-string (current-time)))
  ([str]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [barr (byte-arr-from-string str)
         bseq (map (comp char (appl aget barr))
                   (range (alength barr)))
         chseq (map char str)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (== (alength barr)
              (count bseq)
              (count chseq))
          (nil? (first (filter false?
                               (map eql?
                                    bseq
                                    chseq))))))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-listener-new&lt;/span&gt;
  ([]
   (test-listener-new DEFAULT-PORT))
  ([port]
   (with-open listener (listener-new port)
     (&lt;span class="keyword"&gt;when&lt;/span&gt; listener
       true))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-listener-predicates&lt;/span&gt; [])
&lt;/div&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-all&lt;/span&gt; []
  (&lt;span class="keyword"&gt;loop&lt;/span&gt; [test-list '((&lt;span class="string"&gt;"string-&amp;gt;byte array conversion"&lt;/span&gt;
                      test-byte-array-from-string)
                     (&lt;span class="string"&gt;"creating a listener"&lt;/span&gt;,
                      test-listener-new)
                     (&lt;span class="string"&gt;"listener open?/closed? predicates"&lt;/span&gt;
                      test-listener-predicates))
         failure false]
    (&lt;span class="keyword"&gt;let&lt;/span&gt; [this-test (first test-list)
          test-list (rest test-list)]
      (&lt;span class="keyword"&gt;if&lt;/span&gt; (not this-test)
        (&lt;span class="keyword"&gt;if&lt;/span&gt; failure
          (println &lt;span class="string"&gt;"---\nSome tests failed."&lt;/span&gt;)
          (println &lt;span class="string"&gt;"---\nAll tests succeeded."&lt;/span&gt;))
        (&lt;span class="keyword"&gt;let&lt;/span&gt; [test-result (&lt;span class="keyword"&gt;time&lt;/span&gt; (eval (rest this-test)))]
          (println &lt;span class="string"&gt;"Testing"&lt;/span&gt; (first this-test) &lt;span class="string"&gt;":"&lt;/span&gt; test-result
                     (&lt;span class="keyword"&gt;if&lt;/span&gt; (first test-list) &lt;span class="string"&gt;"\n"&lt;/span&gt; &lt;span class="string"&gt;""&lt;/span&gt;))
            (&lt;span class="keyword"&gt;recur&lt;/span&gt; test-list
                   (&lt;span class="keyword"&gt;when&lt;/span&gt; (&lt;span class="keyword"&gt;or&lt;/span&gt; failure
                             (not test-result))
&lt;/div&gt;

&lt;p&gt;And, running it, I get:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(test-all)&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 8.437664 msecs"&lt;/span&gt;
Testing string-&amp;gt;byte array conversion : true 

&lt;span class="string"&gt;"Elapsed time: 68.38411 msecs"&lt;/span&gt;
Testing creating a listener : true 

&lt;span class="string"&gt;"Elapsed time: 2.831645 msecs"&lt;/span&gt;
Testing listener open?/closed? predicates : nil 
---
Some tests failed.
nil
&lt;/div&gt;

&lt;p&gt;So, it works.  (Noting that I deliberately built one of those tests to
fail, to make sure that the testing function catches failure.)  Except
that, well, how best to put it... Eww.  I know that so far this is
only 150 lines, but I'm not going to remember to update the list of
tests down in the testing function every time I make a new one.  So,
I'll run &lt;code&gt;test-all&lt;/code&gt;, realise that my new test is missing, then go
back and add the new test.&lt;/p&gt;

&lt;h3&gt;Adding structure...&lt;/h3&gt;

&lt;p&gt;No, I think what I need here is for the test itself to hold its own
payload.  Sounds like a reasonable time to add in a struct, really.  A
struct is just a defined hashmap taking keywords as arguments.  For
starters, I'll build one that just duplicates the list that I have
below:&lt;/p&gt;

&lt;div class="code"&gt;(defstruct unit-test &lt;span class="builtin"&gt;:string&lt;/span&gt; &lt;span class="builtin"&gt;:function&lt;/span&gt;)
&lt;/div&gt;

&lt;p&gt;Well, that &lt;em&gt;does&lt;/em&gt; let me wrap tests into structures, but doesn't
exactly let me manipulate them:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(struct unit-test :string &lt;/span&gt;&lt;span class="string"&gt;"creating a listener"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; :function test-listener-new)&lt;/span&gt;
{&lt;span class="builtin"&gt;:function&lt;/span&gt; user.test_listener_new@d5eb7, &lt;span class="builtin"&gt;:string&lt;/span&gt; &lt;span class="string"&gt;"creating a listener"&lt;/span&gt;}
&lt;/div&gt;

&lt;p&gt;What I'm going to need is a way to build these tests and load them
when I load the file, otherwise I'm just making the process of
eyeballing my results in the REPL harder on myself.&lt;/p&gt;

&lt;p&gt;After a bit of thought, I settle on this as my test list:&lt;/p&gt;

&lt;div class="code"&gt;(defstruct unit-test &lt;span class="builtin"&gt;:name&lt;/span&gt; &lt;span class="builtin"&gt;:string&lt;/span&gt; &lt;span class="builtin"&gt;:function&lt;/span&gt;)

(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;ALL-TESTS&lt;/span&gt; {})

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;unit-tests-add&lt;/span&gt; [test]
  (&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;ALL-TESTS&lt;/span&gt;
       (assoc ALL-TESTS (get test &lt;span class="builtin"&gt;:name&lt;/span&gt;) test)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-new&lt;/span&gt;
  ([description function]
   (unit-tests-add (struct unit-test
                           &lt;span class="builtin"&gt;:name&lt;/span&gt; function
                           &lt;span class="builtin"&gt;:string&lt;/span&gt; description
                           &lt;span class="builtin"&gt;:function&lt;/span&gt; function))))
&lt;/div&gt;

&lt;p&gt;Nothing special at the moment.  Just a simple structure defining a
unit test as a name, description and function.  Now, let's use that
one one of the three rudimentary tests that I already have:&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-listener-new&lt;/span&gt;
  ([]
   (test-listener-new DEFAULT-PORT))
  ([port]
   (with-open listener (listener-new port)
     (&lt;span class="keyword"&gt;when&lt;/span&gt; listener
       true))))

(unit-test-new &lt;span class="string"&gt;"creating a listener"&lt;/span&gt; test-listener-new)
&lt;/div&gt;

&lt;p&gt;All right.  Improving a tiny bit.  Except that, after evaluating the
file twice, I still have:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;ALL-TESTS&lt;/span&gt;
{user.test_listener_new@1a0d866 {&lt;span class="builtin"&gt;:function&lt;/span&gt; user.test_listener_new@1a0d866, &lt;span class="builtin"&gt;:string&lt;/span&gt; &lt;span class="string"&gt;"creating a listener"&lt;/span&gt;, &lt;span class="builtin"&gt;:name&lt;/span&gt; user.test_listener_new@1a0d866}, user.test_listener_new@3f96ee {&lt;span class="builtin"&gt;:function&lt;/span&gt; user.test_listener_new@3f96ee, &lt;span class="builtin"&gt;:string&lt;/span&gt; &lt;span class="string"&gt;"creating a listener"&lt;/span&gt;, &lt;span class="builtin"&gt;:name&lt;/span&gt; user.test_listener_new@3f96ee}}
&lt;/div&gt;

&lt;p&gt;Makes sense, really.  My new instance of test-listener-new has a new
symbol.  So, even though &lt;em&gt;I&lt;/em&gt; know that they're the same function,
there's no good reason for the compiler to.&lt;/p&gt;

&lt;p&gt;What I really want, though, is to make defining a new test as simple
as adding a new (albeit specialised) function, rather than playing
around with remembering to call unit-test-new after.  So, rather than
trying to get &lt;code&gt;unit-test-new&lt;/code&gt; to parse out the name of the function,
I'll rethink my approach.&lt;/p&gt;

&lt;p&gt;What do I &lt;em&gt;actually&lt;/em&gt; want?  Well, the function, name and description
added to my set of tests seamlessiy.  I think it's fair to assume that
before I'm done, I'll want a few more qualifiers on tests as well.
Since I don't know what those are, I won't add them to my structure yet.&lt;/p&gt;

&lt;h3&gt;Admitting that I need macros...&lt;/h3&gt;

&lt;p&gt;However, I'm in a conundrum here, because I don't want to add logic to
my test definition every time I think of something new.  Really, this
is starting to sound like a good argument for a macro.&lt;/p&gt;

&lt;p&gt;I'll start by just imitating what &lt;code&gt;defn&lt;/code&gt; does.  Because if I can't
imitate that in a macro, the rest of this is going to start smelling
like week-old moose.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defmacro&lt;/span&gt; &lt;span class="function-name"&gt;deftest&lt;/span&gt; [fname description extras &amp;amp; fdecl]
  `(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;~fname&lt;/span&gt; ~@fdecl))
&lt;/div&gt;

&lt;p&gt;So that takes a function name, a descriptive string and a bunch of
unspecified "extras" and then proceeds to ignore the second two before
shoving the function name and the declaration into a &lt;code&gt;defn&lt;/code&gt;.  The
backtick (`) marks the following list as a template, meaning that the
&lt;code&gt;defn&lt;/code&gt; won't be resolved right away.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;~&lt;/code&gt; and &lt;code&gt;~@&lt;/code&gt; macro characters inside that template mean,
respectively, to unquote &lt;code&gt;fname&lt;/code&gt; (so that I'm not defining a
function called &lt;code&gt;user/fname&lt;/code&gt;) and to resolve &lt;code&gt;fdecl&lt;/code&gt; into the
sequence of values which it represents.&lt;/p&gt;

&lt;p&gt;I have to do this because the &lt;code&gt;&amp;amp; rest&lt;/code&gt; argument to an &lt;code&gt;fn&lt;/code&gt; is
considered to be a sequence.  Were I simply passing it as an unquoted
symbol, I'd end up with an extra set of parentheses around the
function body when it's evaluated, which I don't want.&lt;/p&gt;

&lt;p&gt;So, having rationalised every jot and tittle of what I just did, I'm
going to dump &lt;code&gt;test-listener-new&lt;/code&gt; - that is to say, a working
function - into deftest via macroexpand-1 and see if it generates a
plausible &lt;code&gt;defn&lt;/code&gt;.  (macroexpand-1 because I don't really want to see
the full expanion of &lt;code&gt;defn&lt;/code&gt;'s internals, just this first layer that
I added.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(macroexpand-1 '(deftest test-listener-new &lt;/span&gt;&lt;span class="string"&gt;"creating a listener"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; '()
                         ([]
                          (test-listener-new DEFAULT-PORT))
                         ([port]
                          (with-open listener (listener-new port)
                                     (&lt;/span&gt;&lt;span class="keyword"&gt;when&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; listener
                                       true)))))&lt;/span&gt;
(clojure/defn test-listener-new ([] (test-listener-new DEFAULT-PORT)) ([port] (with-open listener (listener-new port) (&lt;span class="keyword"&gt;when&lt;/span&gt; listener true))))
&lt;/div&gt;

&lt;p&gt;And that resulting definition looks just like the definition of
&lt;code&gt;test-listener-new&lt;/code&gt;, only on one line and with &lt;code&gt;defn&lt;/code&gt; as a
qualified namespace/symbol pair.&lt;/p&gt;

&lt;p&gt;Seeing as that worked, it means that all I should have to do is wrap
defining the function in a &lt;code&gt;do&lt;/code&gt; and add, as the second half, a
function call adding the test to my list of tests.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defmacro&lt;/span&gt; &lt;span class="function-name"&gt;deftest&lt;/span&gt; [fname description extras &amp;amp; fdecl]
  `(&lt;span class="keyword"&gt;do&lt;/span&gt; (&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;~fname&lt;/span&gt; ~@fdecl)
       (unit-tests-add (struct unit-test
                               &lt;span class="builtin"&gt;:name&lt;/span&gt; (name '~fname)
                               &lt;span class="builtin"&gt;:string&lt;/span&gt; ~description
                               &lt;span class="builtin"&gt;:function&lt;/span&gt; ~fname
                               ~@extras))))
&lt;/div&gt;

&lt;p&gt;Which, when expanded, gats me:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(macroexpand-1 '(deftest test-listener-new &lt;/span&gt;&lt;span class="string"&gt;"creating a listener"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; '()
                         ([]
                          (test-listener-new DEFAULT-PORT))
                         ([port]
                          (with-open listener (listener-new port)
                                     (&lt;/span&gt;&lt;span class="keyword"&gt;when&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; listener
                                       true)))))&lt;/span&gt;
(&lt;span class="keyword"&gt;do&lt;/span&gt; (clojure/defn test-listener-new ([] (test-listener-new DEFAULT-PORT)) ([port] (with-open listener (listener-new port) (&lt;span class="keyword"&gt;when&lt;/span&gt; listener true)))) (user/unit-tests-add (clojure/struct user/unit-test &lt;span class="builtin"&gt;:name&lt;/span&gt; (clojure/name (quote test-listener-new)) &lt;span class="builtin"&gt;:string&lt;/span&gt; &lt;span class="string"&gt;"creating a listener"&lt;/span&gt; &lt;span class="builtin"&gt;:function&lt;/span&gt; test-listener-new quote ())))
&lt;/div&gt;

&lt;p&gt;Which counts as an almost-but-not-quite.  Because I'm quoting the
empty list in the arguments that I'm passing to &lt;code&gt;deftest&lt;/code&gt;, it
expands to &lt;code&gt;(quote ())&lt;/code&gt;, which is then unquoted to &lt;code&gt;quote ()&lt;/code&gt;.
Which isn't exactly what I want.&lt;/p&gt;

&lt;p&gt;On the other hand, the working syntax:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(macroexpand-1 '(deftest test-listener-new &lt;/span&gt;&lt;span class="string"&gt;"creating a listener"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; ()
                         ([]
                          (test-listener-new DEFAULT-PORT))
                         ([port]
                          (with-open listener (listener-new port)
                                     (&lt;/span&gt;&lt;span class="keyword"&gt;when&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; listener
                                       true)))))&lt;/span&gt;
(&lt;span class="keyword"&gt;do&lt;/span&gt; (clojure/defn test-listener-new ([] (test-listener-new DEFAULT-PORT)) ([port] (with-open listener (listener-new port) (&lt;span class="keyword"&gt;when&lt;/span&gt; listener true)))) (user/unit-tests-add (clojure/struct user/unit-test &lt;span class="builtin"&gt;:name&lt;/span&gt; (clojure/name (quote test-listener-new)) &lt;span class="builtin"&gt;:string&lt;/span&gt; &lt;span class="string"&gt;"creating a listener"&lt;/span&gt; &lt;span class="builtin"&gt;:function&lt;/span&gt; test-listener-new)))
&lt;/div&gt;

&lt;p&gt;It works fine, and saves me a spurious quote.  Furthermore, values in a
struct default to &lt;code&gt;nil&lt;/code&gt;, so if I add more bits to the &lt;code&gt;unit-test&lt;/code&gt;
structure later, I don't have to cope with accounting for them in any
way other than doing nothing for &lt;code&gt;nil&lt;/code&gt;, and my previously-defined
tests will still work.&lt;/p&gt;

&lt;h3&gt;Applying these new tests.&lt;/h3&gt;

&lt;p&gt;So, I modify my test to use this macro and get:&lt;/p&gt;

&lt;div class="code"&gt;(deftest test-listener-new &lt;span class="string"&gt;"creating a listener"&lt;/span&gt; ()
  ([]
   (test-listener-new DEFAULT-PORT))
  ([port]
   (with-open listener (listener-new port)
     (&lt;span class="keyword"&gt;when&lt;/span&gt; listener
       true))))
&lt;/div&gt;

&lt;p&gt;And evaluating that adds it to &lt;code&gt;ALL-TESTS&lt;/code&gt;.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;ALL-TESTS&lt;/span&gt;
{&lt;span class="string"&gt;"test-listener-new"&lt;/span&gt; {&lt;span class="builtin"&gt;:function&lt;/span&gt; user.test_listener_new@1dcc2a3, &lt;span class="builtin"&gt;:string&lt;/span&gt; &lt;span class="string"&gt;"creating a listener"&lt;/span&gt;, &lt;span class="builtin"&gt;:returns&lt;/span&gt; nil, &lt;span class="builtin"&gt;:name&lt;/span&gt; &lt;span class="string"&gt;"test-listener-new"&lt;/span&gt;}}
&lt;/div&gt;

&lt;p&gt;I &lt;em&gt;could&lt;/em&gt; have put the &lt;code&gt;extras&lt;/code&gt; (that part that I have a suspicion
that I'll need, but don't know why yet,) at the end of the &lt;code&gt;deftest&lt;/code&gt;
macro.  However, that means that I'd likely forget to add them.  Also,
it means that I have to make more changes to an existing test function
than simply adding two pieces of information.&lt;/p&gt;

&lt;p&gt;On the other hand, because it returns the result of
&lt;code&gt;unit-tests-add&lt;/code&gt;, &lt;code&gt;deftest&lt;/code&gt; isn't &lt;em&gt;quite&lt;/em&gt; a drop-in replacement to
&lt;code&gt;defn&lt;/code&gt; yet.  Time to get it to return the function instead.&lt;/p&gt;

&lt;p&gt;So, knowing the function name, and establishing the reasonable
qualification that the function has been defined (which it should have
been, as defining it is a part of the macro, what I want to return is
the Var named by &lt;code&gt;fname&lt;/code&gt;.  Which leads me to:&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defmacro&lt;/span&gt; &lt;span class="function-name"&gt;deftest&lt;/span&gt; [fname description extras &amp;amp; fdecl]
  `(&lt;span class="keyword"&gt;do&lt;/span&gt; (&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;~fname&lt;/span&gt; ~@fdecl)
       (unit-tests-add (struct unit-test
                               &lt;span class="builtin"&gt;:name&lt;/span&gt; (name '~fname)
                               &lt;span class="builtin"&gt;:string&lt;/span&gt; ~description
                               &lt;span class="builtin"&gt;:function&lt;/span&gt; ~fname
                               ~@extras))
       #'~fname))
&lt;/div&gt;

&lt;p&gt;Which, when I evaluate my test, returns the test function, ensuring
that this is now a wrapper around defn that actually returns the right
values.&lt;/p&gt;

&lt;p&gt;That done, I can finally get to converting my remaining two tests and
the &lt;code&gt;test-all&lt;/code&gt; function.  The tests are easy:&lt;/p&gt;

&lt;div class="code"&gt;(deftest test-byte-array-from-string &lt;span class="string"&gt;"string-&amp;gt;byte array conversion"&lt;/span&gt; ()
  ([]
   (test-byte-array-from-string (current-time)))
  ([str]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [barr (byte-arr-from-string str)
         bseq (map (comp char (appl aget barr))
                   (range (alength barr)))
         chseq (map char str)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (== (alength barr)
              (count bseq)
              (count chseq))
          (nil? (first (filter false?
                               (map eql?
                                    bseq
                                    chseq))))))))

(deftest test-listener-predicates &lt;span class="string"&gt;"listener open?/closed? predicates"&lt;/span&gt; () [])
&lt;/div&gt;

&lt;p&gt;To make the testing function work, it needs to be able to get at my
vector of tests and to examine the tests.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-name&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:name&lt;/span&gt;))
(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-string&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:string&lt;/span&gt;))
(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-function&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:function&lt;/span&gt;))
&lt;/div&gt;

&lt;h3&gt;A side-trip into accessors...&lt;/h3&gt;

&lt;p&gt;Here, however, I'm noticing that I'm duplicating what's already
written once in my struct, just to have accessors.  Also, &lt;code&gt;:string&lt;/code&gt;
is a daft name.&lt;/p&gt;

&lt;p&gt;So, I'll make &lt;code&gt;:string&lt;/code&gt; into &lt;code&gt;:description&lt;/code&gt; and generate my
accessors based directly off of the structure.&lt;/p&gt;

&lt;div class="code"&gt;(map (fn [key] (&lt;span class="keyword"&gt;def&lt;/span&gt; (sym (name *current-namespace*)
                         (strcat &lt;span class="string"&gt;"unit-test-"&lt;/span&gt; (name key)))
                    key))
     (keys unit-test))
&lt;/div&gt;

&lt;p&gt;And testing that:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;clojure.lang.Compiler$CompilerException: REPL:1026: Second argument to def must be a Symbol
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:3065)
        at clojure.lang.Compiler.analyze(Compiler.java:3011)
        at clojure.lang.Compiler.analyze(Compiler.java:2986)
        at clojure.lang.Compiler.access$400(Compiler.java:38)
        at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:2740)
        at clojure.lang.Compiler$FnMethod.parse(Compiler.java:2626)
        at clojure.lang.Compiler$FnMethod.access$1300(Compiler.java:2540)
        at clojure.lang.Compiler$FnExpr.parse(Compiler.java:2327)
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:3056)
        at clojure.lang.Compiler.analyze(Compiler.java:3011)
        at clojure.lang.Compiler.analyze(Compiler.java:2986)
        at clojure.lang.Compiler.access$400(Compiler.java:38)
        at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:2255)
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:3060)
        at clojure.lang.Compiler.analyze(Compiler.java:3011)
        at clojure.lang.Compiler.analyze(Compiler.java:2986)
        at clojure.lang.Compiler.eval(Compiler.java:3085)
        at clojure.lang.Repl.main(Repl.java:59)
Caused by: java.lang.Exception: Second argument to def must be a Symbol
        at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:296)
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:3058)
        ... 17 more
&lt;/div&gt;

&lt;p&gt;Hmm, not so good.  Ok, time to poke at what exactly it is that I'm
doing wrong here.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(sym &lt;/span&gt;&lt;span class="string"&gt;"user"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; &lt;/span&gt;&lt;span class="string"&gt;"a"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;)&lt;/span&gt;
user/a
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def (sym &lt;/span&gt;&lt;span class="string"&gt;"a"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;) 1)&lt;/span&gt;
clojure.lang.Compiler$CompilerException: REPL:1030: Second argument to def must be a Symbol
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:3065)
        at clojure.lang.Compiler.analyze(Compiler.java:3011)
        at clojure.lang.Compiler.analyze(Compiler.java:2986)
        at clojure.lang.Compiler.eval(Compiler.java:3085)
        at clojure.lang.Repl.main(Repl.java:59)
Caused by: java.lang.Exception: Second argument to def must be a Symbol
        at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:296)
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:3058)
        ... 4 more        
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(instance? clojure.lang.Symbol (sym &lt;/span&gt;&lt;span class="string"&gt;"user"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; &lt;/span&gt;&lt;span class="string"&gt;"a"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;))&lt;/span&gt;
clojure.lang.Compiler$CompilerException: REPL:3: Unable to resolve classname: clojure.lang.PersistentList@d165fe67
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:3065)
        at clojure.lang.Compiler.analyze(Compiler.java:3011)
        at clojure.lang.Compiler.analyze(Compiler.java:2986)
        at clojure.lang.Compiler.eval(Compiler.java:3085)
        at clojure.lang.Repl.main(Repl.java:59)
Caused by: java.lang.IllegalArgumentException: Unable to resolve classname: clojure.lang.PersistentList@d165fe67
        at clojure.lang.Compiler$InstanceExpr$Parser.parse(Compiler.java:1868)
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:3058)
        ... 4 more
&lt;/div&gt;

&lt;p&gt;So, it appears that both &lt;code&gt;def&lt;/code&gt; and &lt;code&gt;instance?&lt;/code&gt; are seeing the
unexpanded list &lt;em&gt;before&lt;/em&gt; it gets turned into a symbol.  Curiouser and
curiouser.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(map (fn [key] (let [my-sym (sym (name *current-namespace*)
                                        (strcat &lt;/span&gt;&lt;span class="string"&gt;"unit-test-"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (name key)))]
                                        my-sym))
            (keys unit-test))&lt;/span&gt;
(user/unit-test-name user/unit-test-function user/unit-test-description)
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(map (fn [key] (let [my-sym (sym (name *current-namespace*)
                                        (strcat &lt;/span&gt;&lt;span class="string"&gt;"unit-test-"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (name key)))]
                                 (def my-sym 1)))
            (keys unit-test))&lt;/span&gt;
(#&amp;lt;Var: user/my-sym&amp;gt; #&amp;lt;Var: user/my-sym&amp;gt; #&amp;lt;Var: user/my-sym&amp;gt;)
&lt;/div&gt;

&lt;p&gt;Ok, so I redefined my-sym three times.  After I got as far as:&lt;/p&gt;

&lt;div class="code"&gt;(map (fn [li] (&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;~@li&lt;/span&gt;))
     (map (fn [key] (list (sym (name *current-namespace*)
                               (strcat &lt;span class="string"&gt;"unit-test-"&lt;/span&gt; (name key)))
                          (accessor unit-test key)))
          (keys unit-test)))
&lt;/div&gt;

&lt;p&gt;I've decided that I'll no longer make a big deal out of building my
accessors from my structure, as I seem to have a merry clash between
what &lt;code&gt;def&lt;/code&gt; wants and what I know how to offer to it.&lt;/p&gt;

&lt;p&gt;I'll admit that this failure irks me, but I'm going to leave it as
something to poke at later, as I'm getting confused as to operator and
macro precedence.&lt;/p&gt;

&lt;p&gt;Sobeit:&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-name&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:name&lt;/span&gt;))
(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-description&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:description&lt;/span&gt;))
(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-function&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:function&lt;/span&gt;))
&lt;/div&gt;

&lt;h3&gt;Giving up and going back to the test function.&lt;/h3&gt;

&lt;p&gt;Now, on to making the test function actually work with this structure,
rather than playing with trying to be clever with generating
accessors.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-all&lt;/span&gt; []
  (&lt;span class="keyword"&gt;loop&lt;/span&gt; [test-list (vals ALL-TESTS)
         failure false]
    (&lt;span class="keyword"&gt;let&lt;/span&gt; [this-test (first test-list)
          test-list (rest test-list)]
      (&lt;span class="keyword"&gt;if&lt;/span&gt; (not this-test)
        (&lt;span class="keyword"&gt;if&lt;/span&gt; failure
          (println &lt;span class="string"&gt;"---\nSome tests failed."&lt;/span&gt;)
          (println &lt;span class="string"&gt;"---\nAll tests succeeded."&lt;/span&gt;))
        (&lt;span class="keyword"&gt;let&lt;/span&gt; [test-result (&lt;span class="keyword"&gt;time&lt;/span&gt; (unit-test-function this-test))]
          (println &lt;span class="string"&gt;"Testing"&lt;/span&gt; (unit-test-description this-test) &lt;span class="string"&gt;":"&lt;/span&gt; test-result
                     (&lt;span class="keyword"&gt;if&lt;/span&gt; (first test-list) &lt;span class="string"&gt;"\n"&lt;/span&gt; &lt;span class="string"&gt;""&lt;/span&gt;))
            (&lt;span class="keyword"&gt;recur&lt;/span&gt; test-list
                   (&lt;span class="keyword"&gt;when&lt;/span&gt; (&lt;span class="keyword"&gt;or&lt;/span&gt; failure
                             (not test-result))
&lt;/div&gt;

&lt;p&gt;However, testing that, it shows only that the unit test functions
exist.  Nothing more.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(test-all)&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 0.181588 msecs"&lt;/span&gt;
Testing creating a listener : user.test_listener_new@1878144 

&lt;span class="string"&gt;"Elapsed time: 0.028216 msecs"&lt;/span&gt;
Testing string-&amp;gt;byte array conversion : user.test_byte_array_from_string@137d090 

&lt;span class="string"&gt;"Elapsed time: 0.019277 msecs"&lt;/span&gt;
Testing listener open?/closed? predicates : user.test_listener_predicates@15db314 
---
All tests succeeded.
nil
&lt;/div&gt;

&lt;p&gt;I need it to evaluate the returned function, preferably with the
capacity to insert arguments as needed.  Hmm.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-all&lt;/span&gt; []
  (&lt;span class="keyword"&gt;loop&lt;/span&gt; [test-list (map (fn [x] (list (unit-test-description x)
                                      (unit-test-function x)))
                        (vals ALL-TESTS))
         failure false]
    (&lt;span class="keyword"&gt;let&lt;/span&gt; [test (first test-list)
          test-list (rest test-list)]
      (&lt;span class="keyword"&gt;if&lt;/span&gt; (not test)
        (&lt;span class="keyword"&gt;if&lt;/span&gt; failure
          (println &lt;span class="string"&gt;"---\nSome tests failed."&lt;/span&gt;)
          (println &lt;span class="string"&gt;"---\nAll tests passed."&lt;/span&gt;))
        (&lt;span class="keyword"&gt;let&lt;/span&gt; [test-result (&lt;span class="keyword"&gt;time&lt;/span&gt; (eval (list (second test))))]
          (println &lt;span class="string"&gt;"Testing"&lt;/span&gt; (first test) &lt;span class="string"&gt;":"&lt;/span&gt; test-result)
          (&lt;span class="keyword"&gt;recur&lt;/span&gt; test-list
                 (&lt;span class="keyword"&gt;when&lt;/span&gt; (&lt;span class="keyword"&gt;or&lt;/span&gt; (not test-result)
                           failure)
                   true)))))))
&lt;/div&gt;

&lt;p&gt;Will leave that as a working test framework for the moment and
actually move back to writing tests.&lt;/p&gt;

&lt;div class="code"&gt;(deftest test-listener-predicates &lt;span class="string"&gt;"listener open?/closed? predicates"&lt;/span&gt; ()
  ([]
   (test-listener-predicates DEFAULT-PORT))
  ([port]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)
         tests (&lt;span class="keyword"&gt;and&lt;/span&gt; (not (listener-closed? listener))
                    (listener-open? listener))]
     (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (close))
     (&lt;span class="keyword"&gt;and&lt;/span&gt; tests
          (not (listener-open? listener))
          (listener-closed? listener)))))

(deftest test-listener-close &lt;span class="string"&gt;"closing a listener"&lt;/span&gt; ()
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new DEFAULT-PORT)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (listener-open? listener)
          (not (listener-close listener))
          (listener-closed? listener)))))

(deftest test-connection-new &lt;span class="string"&gt;"creating a connection"&lt;/span&gt; ()
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-run-in-background)
         connection (connection-new)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (connection-new)
          (not (listener-close listener))
          (not (connection-new))))))

(deftest test-connection-run &lt;span class="string"&gt;"running a complete connection"&lt;/span&gt; ()
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-run-in-background)
         result (connection-run)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (listener-open? listener)
          (not (listener-close listener))
          (listener-closed? listener)
          (&amp;gt; 0 (&lt;span class="keyword"&gt;.&lt;/span&gt; result (length)))
          (== 0 (&lt;span class="keyword"&gt;.&lt;/span&gt; (connection-run) (length)))))))
&lt;/div&gt;

&lt;p&gt;So there's my complete set of tests to date.  Which I can then without
changing the &lt;code&gt;test-all&lt;/code&gt; that I had already defined.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(test-all)&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 11.890338 msecs"&lt;/span&gt;
Testing creating a listener : true
Could not connect to 127.0.0.1 on port 51345
&lt;span class="string"&gt;"Elapsed time: 1194.393981 msecs"&lt;/span&gt;
Testing creating a connection : true
&lt;span class="string"&gt;"Elapsed time: 4.478223 msecs"&lt;/span&gt;
Testing string-&amp;gt;byte array conversion : true
&lt;span class="string"&gt;"Elapsed time: 35.4397 msecs"&lt;/span&gt;
Testing running a complete connection : false
&lt;span class="string"&gt;"Elapsed time: 11.453132 msecs"&lt;/span&gt;
Testing closing a listener : true
&lt;span class="string"&gt;"Elapsed time: 13.804548 msecs"&lt;/span&gt;
Testing listener open?/closed? predicates : true
---
Some tests failed.
nil
&lt;/div&gt;

&lt;p&gt;Ok, so I notice two things here.  One is that every test works except
what should be the last one.  The other is that, well, it isn't the
last one.  In fact, the tests are in no particular order when, in
fact, they should have a certain level of ordering in them.&lt;/p&gt;

&lt;h3&gt;Setting up after statements...&lt;/h3&gt;

&lt;p&gt;Sounds like I finally have a use for that &lt;code&gt;extras&lt;/code&gt; argument that,
until now, I haven't been using.&lt;/p&gt;

&lt;div class="code"&gt;(defstruct unit-test &lt;span class="builtin"&gt;:name&lt;/span&gt; &lt;span class="builtin"&gt;:description&lt;/span&gt; &lt;span class="builtin"&gt;:function&lt;/span&gt; &lt;span class="builtin"&gt;:after&lt;/span&gt;)

(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-after&lt;/span&gt; (accessor unit-test &lt;span class="builtin"&gt;:after&lt;/span&gt;))

(deftest test-listener-predicates &lt;span class="string"&gt;"listener open?/closed? predicates"&lt;/span&gt;
  (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="string"&gt;"test-listener-new"&lt;/span&gt;)
  ([]
   (test-listener-predicates DEFAULT-PORT))
  ([port]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)
         tests (&lt;span class="keyword"&gt;and&lt;/span&gt; (not (listener-closed? listener))
                    (listener-open? listener))]
     (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (close))
     (&lt;span class="keyword"&gt;and&lt;/span&gt; tests
          (not (listener-open? listener))
          (listener-closed? listener)))))

(deftest test-listener-close &lt;span class="string"&gt;"closing a listener"&lt;/span&gt;
  (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="string"&gt;"test-listener-predicates"&lt;/span&gt;)
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new DEFAULT-PORT)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (listener-open? listener)
          (not (listener-close listener))
          (listener-closed? listener)))))

(deftest test-connection-new &lt;span class="string"&gt;"creating a connection"&lt;/span&gt;
  (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="string"&gt;"test-listener-close"&lt;/span&gt;)
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-run-in-background)
         connection (connection-new)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (connection-new)
          (not (listener-close listener))
          (not (connection-new))))))

(deftest test-connection-run &lt;span class="string"&gt;"running a complete connection"&lt;/span&gt;
  (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="builtin"&gt;:all&lt;/span&gt;)
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-run-in-background)
         result (connection-run)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (listener-open? listener)
          (not (listener-close listener))
          (listener-closed? listener)
          (&amp;gt; 0 (&lt;span class="keyword"&gt;.&lt;/span&gt; result (length)))
          (== 0 (&lt;span class="keyword"&gt;.&lt;/span&gt; (connection-run) (length)))))))
&lt;/div&gt;

&lt;p&gt;There.  Now tests that should have sequence can have them.  But this
means that I need to actually extract my function for generating the
list of unit tests and make it respect the rules that I just added.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-list&lt;/span&gt;
  ([]
   (map (fn [x] (list (unit-test-description x)
                      (unit-test-function x)))
        (vals ALL-TESTS))))
&lt;/div&gt;

&lt;p&gt;Which gives me the same result for &lt;code&gt;test-all&lt;/code&gt;.  Now, to sort this
data rather than just dropping it in a list.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-list-helper&lt;/span&gt; [unsorted sorted]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [test (first unsorted)
        unsorted (rest unsorted)]
    (&lt;span class="keyword"&gt;cond&lt;/span&gt; (&lt;span class="keyword"&gt;or&lt;/span&gt; (not (unit-test-after test))
              (&lt;span class="keyword"&gt;and&lt;/span&gt; (eql? &lt;span class="builtin"&gt;:all&lt;/span&gt; (unit-test-after test))
                   (not unsorted))
              (first (filter (fn [x] (eql? (unit-test-name x)
                                           (unit-test-after test)))
                             unsorted)))
          (list unsorted
                (concat sorted
                        (list test)))
          &lt;span class="builtin"&gt;:t&lt;/span&gt;
          (list (concat unsorted
                        (list test))
                sorted))))
&lt;/div&gt;

&lt;p&gt;So what that's supposed to do is run through the unsorted list, adding
things to the sorted list when they either have no after statement
&lt;em&gt;or&lt;/em&gt; their after statement is met.&lt;/p&gt;

&lt;p&gt;Now, I'll bind that helper into a loop:&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-list&lt;/span&gt;
  ([]
   (&lt;span class="keyword"&gt;cond&lt;/span&gt; (rest (filter (fn [test] (eql? &lt;span class="builtin"&gt;:all&lt;/span&gt;
                                        (unit-test-after test)))))
         (&lt;span class="keyword"&gt;do&lt;/span&gt; (println &lt;span class="string"&gt;"Error: Only one test may be marked as"&lt;/span&gt;
                      &lt;span class="string"&gt;"coming after all others."&lt;/span&gt;)
             [])
         &lt;span class="builtin"&gt;:t&lt;/span&gt;
         (unit-test-list (vals ALL-TESTS) (list))))
  ([unsorted sorted]
   (&lt;span class="keyword"&gt;if&lt;/span&gt; (not (first unsorted))
     (map (fn [test] (list (unit-test-description test)
                           (unit-test-function test)))
          sorted)
     (&lt;span class="keyword"&gt;let&lt;/span&gt; [helped-list (unit-test-list-helper unsorted sorted)
           unsorted (first helped-list)
           sorted (second helped-list)]
       (&lt;span class="keyword"&gt;recur&lt;/span&gt; unsorted sorted)))))
&lt;/div&gt;

&lt;p&gt;And running it:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(unit-test-list (vals ALL-TESTS) nil)&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;It hangs.&lt;/p&gt;

&lt;p&gt;Stepping through the helper function in a long series of examinations
tells me that it's hanging at the last step.  Then, after changing it
to reflect my actual intent (I typoed &lt;code&gt;sorted&lt;/code&gt; as &lt;code&gt;unsorted&lt;/code&gt;. I
start to think about whether this is actually a good way to build a
list.  After all, it will take up to the factorial of the length of
the list of tests to actually build it.&lt;/p&gt;

&lt;p&gt;I poke with comparators for a bit and find that my somewhat fuzzy
requirements don't exactly meet comparator's exacting demands&lt;a name="note2"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;.  Then I
decide to revisit my iffy list function, but move blocks of tests at a
time.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;unit-test-list-helper&lt;/span&gt; [unsorted sorted]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [nils (filter (comp not unit-test-after)
                     unsorted)
        alls (filter (comp (appl eql? &lt;span class="builtin"&gt;:all&lt;/span&gt;) unit-test-after)
                     unsorted)
        others (filter (fn [t] (not-any? (fn [x] (eql? (unit-test-after t)
                                                       (unit-test-after x)))
                                         (concat nils alls)))
                       unsorted)
        in-sorted (fn [t] (some (fn [x] (eql? (unit-test-name x)
                                              (unit-test-after t)))
                                (concat nils sorted)))]
    (&lt;span class="keyword"&gt;cond&lt;/span&gt; (first nils)
          (list (concat alls
                        (filter (complement in-sorted)
                                others))
                (concat nils
                        (filter in-sorted others)))
          (== (count alls)
              (count unsorted))
          (list nil
                (concat sorted alls))
          &lt;span class="builtin"&gt;:t&lt;/span&gt;
          (list (concat alls
                        (filter (complement in-sorted)
                                others))
                (concat sorted
                        (filter in-sorted others))))))
&lt;/div&gt;

&lt;p&gt;This one takes the unsorted list, breaks it into three parts, and
moves what it can over to &lt;code&gt;sorted&lt;/code&gt; at each step.  It sorts my list
of functions in three steps, rather than twenty.  However, those steps
are relatively expensive.  I might as well compare the two functions'
performances while I've them both on my screen.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(do (dotimes x 10 (time (unit-test-list-old))) (println &lt;/span&gt;&lt;span class="string"&gt;"----------"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;) (dotimes x 10 (time (unit-test-list))))&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 3.240635 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 0.478832 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 0.459835 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 0.713778 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 0.462908 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 0.450616 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 0.433575 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 0.506489 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 0.453689 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 5.946846 msecs"&lt;/span&gt;
----------
&lt;span class="string"&gt;"Elapsed time: 8.428725 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 1.182832 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 1.732902 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 1.130031 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 1.121931 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 1.130869 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 1.137016 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 1.390959 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 1.163555 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 1.132546 msecs"&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Interesting.  The old one actually did &lt;em&gt;better&lt;/em&gt; than the new.  Now, I
could count their operations, but it would be more fun to get the REPL
testing this for me.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(dotimes x 100 (eval `(deftest ~(gensym) &lt;/span&gt;&lt;span class="string"&gt;"generated fake test"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (:after nil) [] true)))&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;There.  Made a hundred test macros with no structure to them.
&lt;code&gt;gensym&lt;/code&gt; just makes a symbol with a guaranteed-unique name.  That
ensures that, in generating these tests, I don't have to first come up
with my own means to make unique nmes.&lt;/p&gt;

&lt;p&gt;Now to try again:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(do (dotimes x 10 (time (unit-test-list-old))) (println &lt;/span&gt;&lt;span class="string"&gt;"----------"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;) (dotimes x 10 (time (unit-test-list))))&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 108.745944 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 44.778876 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 38.915002 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 47.836247 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 41.699434 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 40.098393 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 41.917059 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 40.536157 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 39.040995 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 39.437135 msecs"&lt;/span&gt;
----------
&lt;span class="string"&gt;"Elapsed time: 21.603863 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 17.80338 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 17.744992 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 19.674568 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 13.584687 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 19.662834 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 17.736891 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 18.160967 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 13.494174 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 16.875608 msecs"&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;A gap is starting to form, I think.  What about adding some test macros that do rely on other tests?&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(import '(java.util Random))&lt;/span&gt;
nil
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def RNG (new Random))&lt;/span&gt;
#&amp;lt;Var: user/RNG&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. RNG (nextInt))&lt;/span&gt;
Reflection warning, line: 948 - call to nextInt can't be resolved.
1410779829
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;`(deftest ~(gensym) &lt;/span&gt;&lt;span class="string"&gt;"z"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (:after nil) [] true))&lt;/span&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;`(deftest ~(gensym) &lt;/span&gt;&lt;span class="string"&gt;"z"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (:after nil) [] true)&lt;/span&gt;
(user/deftest G__2659 &lt;span class="string"&gt;"z"&lt;/span&gt; (&lt;span class="builtin"&gt;:after&lt;/span&gt; nil) [] true)
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;`(deftest ~(gensym) &lt;/span&gt;&lt;span class="string"&gt;"z"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (:after ~(let [keys (keys ALL-TESTS)] (first (drop (rem (. RNG (nextInt)) (count keys)) keys)))) [] true)&lt;/span&gt;
Reflection warning, line: 951 - call to nextInt can't be resolved.
(user/deftest G__2665 &lt;span class="string"&gt;"z"&lt;/span&gt; (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="string"&gt;"G__2491"&lt;/span&gt;) [] true)
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(dotimes x 1000 (eval `(deftest ~(gensym) &lt;/span&gt;&lt;span class="string"&gt;"z"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (:after ~(let [keys (keys ALL-TESTS)] (first (drop (rem (. RNG (nextInt)) (count keys)) keys)))) [] true)))&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;So, that adds a thousand tests in that &lt;em&gt;do&lt;/em&gt; follow a structure, as
they all have an &lt;code&gt;after&lt;/code&gt; statement this time.&lt;/p&gt;

&lt;p&gt;And I run the test again ...&lt;/p&gt;

&lt;p&gt;And I go get coffee ...&lt;/p&gt;

&lt;p&gt;5 minutes...&lt;/p&gt;

&lt;p&gt;It seems to be still running...&lt;/p&gt;

&lt;p&gt;Maybe a thousand was a bad seed...&lt;/p&gt;

&lt;p&gt;Oh, there it is:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(do (dotimes x 10 (time (unit-test-list-old))) (println &lt;/span&gt;&lt;span class="string"&gt;"----------"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;) (dotimes x 10 (time (unit-test-list))))&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 21438.660779 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 24259.176236 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 20528.833693 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 20170.246777 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 23642.198659 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 20390.313015 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 19931.102975 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 22232.556093 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 21692.653954 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 20286.386119 msecs"&lt;/span&gt;
----------
&lt;span class="string"&gt;"Elapsed time: 5885.515896 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 7089.577027 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 6119.980053 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 6135.949681 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 6105.716229 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 6035.137985 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 6120.137894 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 5858.970903 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 5882.34203 msecs"&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 6120.462796 msecs"&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;So, definitely, as the structure gets more complicated, the slightly
more sensible approach is pulling ahead.&lt;/p&gt;

&lt;p&gt;But just for fun, as I'm going to bed:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;#&amp;lt;Var: user/ALL-TESTS&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(dotimes x 100 (eval `(deftest ~(gensym) &lt;/span&gt;&lt;span class="string"&gt;"generated fake test"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (:after nil) [] true)))&lt;/span&gt;
nil
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(dotimes x 100000 (eval `(deftest ~(gensym) &lt;/span&gt;&lt;span class="string"&gt;"generated fake test"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (:after ~(let [keys (keys ALL-TESTS)] (first (drop (rem (. RNG (nextInt)) (count keys)) keys)))) [] true)))&lt;/span&gt;
Reflection warning, line: 957 - call to nextInt can't be resolved.
&lt;span class="comint-highlight-input"&gt;(do (dotimes x 10 (time (unit-test-list-old))) (println &lt;/span&gt;&lt;span class="string"&gt;"----------"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;) (dotimes x 10 (time (unit-test-list))))&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Ok, somewhere before generating a 100000-length tree of tests, it
crashed, due to a lack of symbols.  Fair enough.  That test was just
waving things around to see if I can.&lt;/p&gt;

&lt;div class="code"&gt;clojure.lang.Compiler$CompilerException: REPL:749: PermGen space
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(count (keys ALL-TESTS))&lt;/span&gt;
42577
&lt;/div&gt;

&lt;h3&gt;Revisiting generating my accessors.&lt;/h3&gt;

&lt;p&gt;However, going back one step, all that silly mucking around with
&lt;code&gt;gensyms&lt;/code&gt; and defines gives me an idea:&lt;/p&gt;

&lt;div class="code"&gt;(map (fn [key] (eval `(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;~&lt;/span&gt;(sym (name *current-namespace*)
                                 (strcat &lt;span class="string"&gt;"unit-test-"&lt;/span&gt;
                                         (name key)))
                           (accessor unit-test ~key))))
     (keys unit-test))
&lt;/div&gt;

&lt;p&gt;There.  Now I know that, should I later decide to add more keys to
that structure, the accessors will be there and waiting for me.
Except that, in a freshly-loaded REPL (with this file loaded via
&lt;code&gt;load-file&lt;/code&gt; rather than dumping it in, I find that my accessors are
no longer loaded.&lt;/p&gt;

&lt;p&gt;All right, I'll take the hint, stop picking at this, and leave them as
normal functions rather than generated ones.&lt;/p&gt;

&lt;h3&gt;Revisiting actually running the tests&lt;/h3&gt;

&lt;p&gt;So, I try running all my tests again.  And the test function (which I
haven't changed since I started that little digression into sorting my
tests) still does what it's told, albeit with a tiny wart and a failed
test.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(test-all)&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 306.707138 msecs"&lt;/span&gt;
Testing creating a listener : true
&lt;span class="string"&gt;"Elapsed time: 216.1839 msecs"&lt;/span&gt;
Testing string-&amp;gt;byte array conversion : true
&lt;span class="string"&gt;"Elapsed time: 11.579405 msecs"&lt;/span&gt;
Testing listener open?/closed? predicates : true
&lt;span class="string"&gt;"Elapsed time: 10.170846 msecs"&lt;/span&gt;
Testing closing a listener : true
Could not connect to 127.0.0.1 on port 51345
&lt;span class="string"&gt;"Elapsed time: 1064.018472 msecs"&lt;/span&gt;
Testing creating a connection : true
&lt;span class="string"&gt;"Elapsed time: 46.276552 msecs"&lt;/span&gt;
Testing running a complete connection : false
---
Some tests failed.
&lt;/div&gt;

&lt;p&gt;And here's the offending test.  I'll step through it one bit at a time
and see what's going wrong in actuality.&lt;/p&gt;

&lt;div class="code"&gt;(deftest test-connection-run &lt;span class="string"&gt;"running a complete connection"&lt;/span&gt;
  (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="builtin"&gt;:all&lt;/span&gt;)
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-run-in-background)
         result (connection-run)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (listener-open? listener)
          (not (listener-close listener))
          (listener-closed? listener)
          (&amp;gt; 0 (&lt;span class="keyword"&gt;.&lt;/span&gt; result (length)))
          (== 0 (&lt;span class="keyword"&gt;.&lt;/span&gt; (connection-run) (length)))))))

&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def listener (listener-run-in-background))&lt;/span&gt;
#&amp;lt;Var: user/listener&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def result (connection-run))&lt;/span&gt;
#&amp;lt;Var: user/result&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(listener-open? listener)&lt;/span&gt;
true
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(listener-close listener)&lt;/span&gt;
nil
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(listener-closed? listener)&lt;/span&gt;
true
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(&amp;gt; 0 (. result (length)))&lt;/span&gt;
Reflection warning, line: 306 - call to length can't be resolved.
false
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. result (length))&lt;/span&gt;
Reflection warning, line: 307 - call to length can't be resolved.
28
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(&amp;gt; (. result (length)) 0)&lt;/span&gt;
Reflection warning, line: 308 - call to length can't be resolved.
true
&lt;/div&gt;

&lt;p&gt;Ok, so I messed up the ordering of greater-than and less-than.  I find
that I do this a lot in Lisp, because of how I read &lt;code&gt;(&amp;gt; 0 ...&lt;/code&gt;
mentally.  Namely, as a single function, testing if what follows is
greater than the integer that I've put there.  Or, in other words,
exactly backwards.&lt;/p&gt;

&lt;p&gt;So, change that to &lt;code&gt;(&amp;gt; (. result (length)) 0)&lt;/code&gt; and re-run the test
function:&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(test-all)&lt;/span&gt;
java.lang.NullPointerException
        at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:24)
        at user.test_connection_run.invoke(Unknown Source)
        at clojure.lang.AFn.applyToHelper(AFn.java:171)
        at clojure.lang.AFn.applyTo(AFn.java:164)
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2213)
        at clojure.lang.Compiler.eval(Compiler.java:3086)
        at clojure.eval.invoke(boot.clj:635)
        at user.test_all.invoke(Unknown Source)
        at clojure.lang.AFn.applyToHelper(AFn.java:171)
        at clojure.lang.AFn.applyTo(AFn.java:164)
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2213)
        at clojure.lang.Compiler.eval(Compiler.java:3086)
        at clojure.lang.Repl.main(Repl.java:59)
&lt;span class="string"&gt;"Elapsed time: 9.756547 msecs"&lt;/span&gt;
Testing creating a listener : true
&lt;span class="string"&gt;"Elapsed time: 4.988344 msecs"&lt;/span&gt;
Testing string-&amp;gt;byte array conversion : true
&lt;span class="string"&gt;"Elapsed time: 26.513984 msecs"&lt;/span&gt;
Testing listener open?/closed? predicates : true
&lt;span class="string"&gt;"Elapsed time: 10.239011 msecs"&lt;/span&gt;
Testing closing a listener : true
Could not connect to 127.0.0.1 on port 51345
&lt;span class="string"&gt;"Elapsed time: 997.681828 msecs"&lt;/span&gt;
Testing creating a connection : true
Could not connect to 127.0.0.1 on port 51345
&lt;/div&gt;

&lt;p&gt;Erk.  All right, that's getting a bit odd.  Changing it back gets me
the previous, broken test, but that's not exactly helpful.  Looking at
that dump, I can see that, first off, the error happened in
&lt;code&gt;test-connection-run&lt;/code&gt;, but, secondly, it happened when trying to
invoke an instance method.&lt;/p&gt;

&lt;p&gt;Further, on that line, the only one I've been changing, there is
indeed an instance method.  However, on a successful connection, even
one with no data, it should return an empty string.&lt;/p&gt;

&lt;p&gt;The answer here lies with the next line.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(== 0 (. (connection-run) (length)))&lt;/span&gt;
Reflection warning, line: 894 - call to length can't be resolved.
java.lang.NullPointerException
        at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:24)
        at clojure.lang.Compiler$InstanceMethodExpr.eval(Compiler.java:950)
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2212)
        at clojure.lang.Compiler.eval(Compiler.java:3086)
        at clojure.lang.Repl.main(Repl.java:59)
Could not connect to 127.0.0.1 on port 51345
&lt;/div&gt;

&lt;p&gt;Before, the failure at the successful length was causing and to stop
and return false, in a "short-circuiting" behaviour that's fairly
normal&lt;a name="note3"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Now, what that reminds me is that &lt;code&gt;(connection-run)&lt;/code&gt; is going to
return &lt;code&gt;nil&lt;/code&gt; when it can't open a connection at all.  So thus, I'm
calling &lt;code&gt;(length)&lt;/code&gt; on &lt;code&gt;nil&lt;/code&gt;: &lt;code&gt;(. nil (length))&lt;/code&gt; which,
deservedly, throws an error.  So, in this case, the reflection
warnings about &lt;code&gt;length&lt;/code&gt; not being resolved were helping me rather
than nagging.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; #^Int length-of-string [#^String string]
  (&lt;span class="keyword"&gt;if&lt;/span&gt; string
    (&lt;span class="keyword"&gt;.&lt;/span&gt; string (length))
    0))

&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(length-of-string &lt;/span&gt;&lt;span class="string"&gt;"asdf"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;)&lt;/span&gt;
4
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(length-of-string nil)&lt;/span&gt;
0

(deftest test-connection-run &lt;span class="string"&gt;"running a complete connection"&lt;/span&gt;
  (&lt;span class="builtin"&gt;:after&lt;/span&gt; &lt;span class="builtin"&gt;:all&lt;/span&gt;)
  ([]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-run-in-background)
         result (connection-run)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (listener-open? listener)
          (not (listener-close listener))
          (listener-closed? listener)
          (&amp;lt;= 0 (length-of-string result))
          (== 0 (length-of-string (connection-run)))))))

&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(test-all)&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 75.76773 msecs"&lt;/span&gt;
Testing creating a listener : true
&lt;span class="string"&gt;"Elapsed time: 3.349029 msecs"&lt;/span&gt;
Testing string-&amp;gt;byte array conversion : true
&lt;span class="string"&gt;"Elapsed time: 9.635583 msecs"&lt;/span&gt;
Testing listener open?/closed? predicates : true
&lt;span class="string"&gt;"Elapsed time: 9.517131 msecs"&lt;/span&gt;
Testing closing a listener : true
Could not connect to 127.0.0.1 on port 51345
&lt;span class="string"&gt;"Elapsed time: 944.630393 msecs"&lt;/span&gt;
Testing creating a connection : true
Could not connect to 127.0.0.1 on port 51345
&lt;span class="string"&gt;"Elapsed time: 1001.659708 msecs"&lt;/span&gt;
Testing running a complete connection : true
---
All tests passed.
&lt;/div&gt;

&lt;p&gt;And, testing all of that, it does indeed work out the way it ought to,
except for the aforementioned wart.  To point it out, "Could not
connect to 127.0.0.1 on port 51345" would appear to indicate an error,
whereas I know that it's actually a valid part of both the tests for
which it appears.&lt;/p&gt;

&lt;p&gt;So, here's the problem: those errors are useful rather than throwing
an exception when connecting manually, but they give the wrong
indication (to me at least) when connecting automatically.&lt;/p&gt;

&lt;p&gt;So, what I'd like is to shove any messages generated into something
other than standard output, where I can inspect them if I so choose.&lt;/p&gt;

&lt;div class="code"&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-all&lt;/span&gt; []
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [test-out (new StringWriter)]
    (&lt;span class="keyword"&gt;loop&lt;/span&gt; [test-list (unit-test-list)
                     failure false]
      (&lt;span class="keyword"&gt;let&lt;/span&gt; [test (first test-list)
            test-list (rest test-list)]
        (&lt;span class="keyword"&gt;cond&lt;/span&gt; (not test)
              (&lt;span class="keyword"&gt;do&lt;/span&gt; (&lt;span class="keyword"&gt;if&lt;/span&gt; failure
                    (println &lt;span class="string"&gt;"---\nSome tests failed."&lt;/span&gt;)
                    (println &lt;span class="string"&gt;"---\nAll tests passed."&lt;/span&gt;))
                  (list failure test-out))
              &lt;span class="builtin"&gt;:t&lt;/span&gt;
              (&lt;span class="keyword"&gt;let&lt;/span&gt; [test-result (&lt;span class="keyword"&gt;time&lt;/span&gt; (&lt;span class="keyword"&gt;binding&lt;/span&gt; [*out* test-out]
                                        (eval (list (second test)))))]
                (println &lt;span class="string"&gt;"Testing"&lt;/span&gt; (first test) &lt;span class="string"&gt;":"&lt;/span&gt; test-result)
                (&lt;span class="keyword"&gt;recur&lt;/span&gt; test-list
                       (&lt;span class="keyword"&gt;when&lt;/span&gt; (&lt;span class="keyword"&gt;or&lt;/span&gt; (not test-result)
                                 failure)
                         true))))))))
&lt;/div&gt;

&lt;p&gt;So, what that does is, before doing anything, creates a StringWriter
&lt;em&gt;outside&lt;/em&gt; the loop.  Then, when it comes time to perform the test,
temporarily re-binds &lt;em&gt;out&lt;/em&gt; (the variable telling Clojure where to
print to) to that StringWriter.&lt;/p&gt;

&lt;p&gt;This means, now, that I can return the success/failure of the set of
tests, as well as any error messages, as a list.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def test-results (test-all))&lt;/span&gt;
&lt;span class="string"&gt;"Elapsed time: 8.808941 msecs"&lt;/span&gt;
Testing creating a listener : true
&lt;span class="string"&gt;"Elapsed time: 3.364394 msecs"&lt;/span&gt;
Testing string-&amp;gt;byte array conversion : true
&lt;span class="string"&gt;"Elapsed time: 8.342401 msecs"&lt;/span&gt;
Testing listener open?/closed? predicates : true
&lt;span class="string"&gt;"Elapsed time: 63.791348 msecs"&lt;/span&gt;
Testing closing a listener : true
&lt;span class="string"&gt;"Elapsed time: 982.201928 msecs"&lt;/span&gt;
Testing creating a connection : true
&lt;span class="string"&gt;"Elapsed time: 1002.468191 msecs"&lt;/span&gt;
Testing running a complete connection : true
---
All tests passed.
#&amp;lt;Var: user/test-results&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;test-results&lt;/span&gt;
(nil Could not connect to 127.0.0.1 on port 51345
Could not connect to 127.0.0.1 on port 51345
)
&lt;/div&gt;

&lt;h2&gt;Afterthoughts&lt;/h2&gt;

&lt;p&gt;So, now I have a very basic (albeit ostensibly extensible) testing
framework, as well as a setup that generates that framework
automatically.&lt;/p&gt;

&lt;p&gt;So, now a few (code-dump-free) thoughts as I actually make sure that
my in-file commentary is up to date.&lt;/p&gt;

&lt;h3&gt;Mistakes&lt;/h3&gt;

&lt;p&gt;What are the current downsides to this system and this approach?
Well, for starters, the test framework only recognises &lt;code&gt;nil&lt;/code&gt; and
&lt;code&gt;true&lt;/code&gt;.  This means that, when an early test manages to hang and
throw an exception, it brings down the test framework as well.&lt;/p&gt;

&lt;p&gt;In laziness, I chose to use return values in order to not have to play
too much with caught/thrown errors, and instead passed truth/falsity
around.  Not necessarily the best approach, but I haven't decided
whether throwing/catching is better &lt;em&gt;in this case&lt;/em&gt;&lt;a
name="note5"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Also, I'll be the first to admit that I'm handling errors in a bit of
a cheap way, and one that, were I actually turning this into a real
component, rather than something that I'm building as the "build one
to throw away" of my learning process, I'd have started to question at
about the point that I was wrapping a &lt;code&gt;binding&lt;/code&gt; around &lt;code&gt;println&lt;/code&gt;
in order to isolate my error handling away from my testing function.&lt;/p&gt;

&lt;p&gt;Further, the 100 lines defining my simple testing framework should
really be extracted from this client-server application.  They're only
loosely attached to each other, so I &lt;em&gt;should&lt;/em&gt; be able to give them
their own namespaces with minimal hassle.  (I'll wait for the next
Clojure release to do that, though, because I know I'll have to change
a bunch in order to handle upcoming changes, and would prefer to
discuss namespaces with myself once the new system is in.)&lt;/p&gt;

&lt;h3&gt;Lessons&lt;/h3&gt;

&lt;p&gt;On contrast, what have I learned?  Well, for one, do &lt;em&gt;not&lt;/em&gt; try to
generate 17 000 lines of Lisp at once via an elisp command.  Or, at
least, save your document first.  (I lost all of my poking at
comparators via that gaffe.)&lt;/p&gt;

&lt;p&gt;Also, that macros really aren't especially terrifying.  Believe me or
don't, but &lt;code&gt;deftest&lt;/code&gt; was the first Lisp macro that I've ever
written.  I'm still tripping over order of operations and how forms
get expanded and names get resolved, especially when dealing with
things like &lt;code&gt;def&lt;/code&gt; and &lt;code&gt;load_file&lt;/code&gt;, but I do think that that falls
simultaneously with me trying to be too clever and not actually
understanding what it is that I'm doing.&lt;/p&gt;

&lt;p&gt;As I write more, I keep finding new boot.clj functions that let me
write a verbose expression a lot more succinctly and clearly.  My new
ones are &lt;code&gt;with-open&lt;/code&gt;, &lt;code&gt;some&lt;/code&gt;, &lt;code&gt;not-any?&lt;/code&gt; and anything beginning
with &lt;code&gt;sort&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I'm finding that having the manual as a single, &lt;em&gt;indexed&lt;/em&gt; document is
making me try harder to use Clojure's functions for doing something,
rather than rolling my own off of Java's library.&lt;/p&gt;

&lt;p&gt;As I've found before, having a single unified environment in which to
write code, then evaluate it &lt;em&gt;selectively&lt;/em&gt; is a great asset.  It
means, for me at least, that I spend less time having to mentally
page-swap as I try to remember what I was going to do next.&lt;/p&gt;

&lt;p&gt;There's some caveats to that, though: Number one is that my current
environment state doesn't &lt;em&gt;necessarily&lt;/em&gt; match what I have written
down.  I found myself, this session, killing by REPL on occasion just
to make sure that it was matching my work as exactly as possible.&lt;/p&gt;

&lt;p&gt;Also, it makes me lazy about making sure that, e.g., functions are
declared before another function references them.  Which works just
fine, right up until I try to load the file and realise that my
selective evaluation has (yet again) created a file that needs minor
reordering in order to load.&lt;/p&gt;

&lt;p&gt;But that's a trivial irritation.  And far outweighed by being able to
write this (as HTML-heavy
&lt;a href="http://daringfireball.net/projects/markdown/"&gt;Markdown&lt;/a&gt;), manipulate
the actual source of this program and run the REPL, all in the same
environment, and all sharing data&lt;a
name="note6"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn6"&gt;6&lt;/a&gt;&lt;/sup&gt;.  &lt;/p&gt;

&lt;h3&gt;Future / Goals&lt;/h3&gt;

&lt;p&gt;Well, beyond the nebulous goals I dropped at the end of my initial
look, I now have a few more.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cease using &lt;code&gt;nil&lt;/code&gt; as an error value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move to separate test / application namespaces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Look at existing functions that do the same thing (the &lt;code&gt;close&lt;/code&gt;s
and &lt;code&gt;length-of-string&lt;/code&gt; come to mind) and push them into
multimethods instead.&lt;/p&gt;

&lt;p&gt;(Yes, the long-term geal here is to meander through all 21
chapters of the manual as I find needs.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Explore wrapping an extant Java unit testing facility in Clojure
rather than rolling my own (a nice learning exercise but not exactly
a valid solution to anything beyond making myself try out the
language.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn1"&gt;&lt;/a&gt;Ok, it sounds like a fine idea for a project, but
I'm trying not to let my focus wander all over the place, so I'll keep
this experiment/application self-contained.  &lt;a href="#note1"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn2"&gt;&lt;/a&gt;To clarify my failure to use comparators a little
bit, a comparator is an object/function that grabs some items,
compares them, and replies which one is greater.&lt;/p&gt;

&lt;div class="code"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (sort (comparator &gt;) [5 4 8 4 3 8 4 6])&lt;/span&gt;
(8 8 6 5 4 4 4 3)
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt; (sort (comparator (fn [x y] (println x y (&gt; x y)) &gt;)) [5 4 8 4 3 8 4 6])&lt;/span&gt;
5 4 true
4 8 false
8 4 true
3 8 false
8 4 true
4 6 false
4 3 true
(5 4 8 4 3 8 4 6)
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(sort (comparator (fn [x y] (println x y (&amp;gt;= x y)) &amp;gt;)) [5 4 4 4])&lt;/span&gt;
5 4 true
4 4 true
4 4 true
(5 4 4 4)
&lt;/div&gt;

&lt;p&gt;Here's where that falls apart for &lt;em&gt;my&lt;/em&gt; purposes, though: when
sorting numbers, letters, names, etc., I know the relative
ordering of any two.  On the other hand, with these tests, unless
one of four conditions is met, the ordering of the two items is
unknown.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:after&lt;/code&gt; is nil.  The test comes before all others.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:after&lt;/code&gt; is &lt;code&gt;:all&lt;/code&gt;.  The test comes after all others.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Both tests have the same &lt;code&gt;:after&lt;/code&gt;.  They are equivalent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One test's &lt;code&gt;:name&lt;/code&gt; is the other test's &lt;code&gt;:after&lt;/code&gt;.  They have
to go in that order.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My problem is that most of my comparisons do not meet these
standards.  Hence my sort functions both having a means to defer
looking at an item until a condition is met.  &lt;a href="#note2"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn3"&gt;&lt;/a&gt;This meaning, in a logical condition, to stop
evaluating the condition as soon as its truth / falsity becomes known.
Here, and in other tests, I was using it as somewhat of a shorthand to
say, "If the test fails at any point, the entire test has failed."&lt;/p&gt;

&lt;p&gt;On the other hand, using logical predicates (&lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;,
etc.) as control structure can quickly get
unreadable at a glance.&lt;/p&gt;

&lt;div class="code"&gt;(or (or (and (test1) (test2))
(test3))
(or (and (test4) (test5) (test6))
    (and (test6) (test7) (or (test8)
                             (test8a)
                             (test8b)))
    (test9)))
&lt;/div&gt;

&lt;p&gt;A contrived example, sure, but I lost the flow of that logical
tree midway through writing the test.  I also tried to devise it
so that the tree structure would bear at least a passing
resemblance to something that had been modified to deal with a
later condition&lt;a name="note4"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt; &lt;a href="#note3"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn4"&gt;&lt;/a&gt;(For what it's worth, it says: Perform test1.  On
success, perform test2.  On success of test1 &lt;em&gt;and&lt;/em&gt; test2, return
success.  Otherwise, perform test3.  On success of test3, return
success.  On failure of test3, try test4, test5, test6, stopping if
there's failure.  And so on, until, if all other tests have failed,
return the success/failute of test9.)  &lt;a href="#note4"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn5"&gt;&lt;/a&gt;Yes, I'm aware that the consistent (and possibly
even correct) answer is throw/catch.  However, for the purposes of a
simple demo application, building Throwables to toss around strikes me
as an unnecessarily obfuscating the mechanics of what I'm
doing.  &lt;a href="#note5"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn6"&gt;&lt;/a&gt;Emacs, 164 characters wide, divided into two
columns, with a full column devoted to the REPL, 20 lines to the
source and 40 to this text.  Which raises a question: With the
admonition to not write any function longer than a single screen,
with whose screen length?&lt;/p&gt;

&lt;p&gt;For the record, the longest function in this example is 28 lines
and the shortest is 1 line long.  That's &lt;em&gt;likely&lt;/em&gt; a direct
consequence to my having kept my source scrunched up with only a
little window into it&lt;a name="note7"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn7"&gt;7&lt;/a&gt;&lt;/sup&gt;.
&lt;a href="#note6"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn7"&gt;&lt;/a&gt;Done via the script:&lt;/p&gt;

&lt;div class="code"&gt;(save-excursion
(goto-char (point-min))
(re-search-forward "^ *$" (point-max) nil)
(message (mapconcat (lambda (lc) (format "%d" lc))
                  (let ((lcount nil))
                    (while (not (eobp))
                      (forward-sexp)
                      (setq lcount
                            (append lcount
                                    (list (count-lines
                                           (save-excursion
                                            (backward-sexp) (point))
                                            (point))))))
                    lcount)
                  " ")))
&lt;/div&gt;

&lt;p&gt;&lt;p&gt;And that's why Emacs one-liners are scary.  Because before you
know it, they're &lt;em&gt;actually&lt;/em&gt; 15 lines long, all scrunched into an
Eval: prompt.  &lt;a href="#note7"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-4828660414211471753?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/4828660414211471753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=4828660414211471753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/4828660414211471753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/4828660414211471753'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2008/02/clojure-continuing-to-look.html' title='Clojure: continuing to look'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-2500107895881759696</id><published>2008-02-02T22:42:00.001-05:00</published><updated>2009-02-17T17:46:48.793-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>My first look at Clojure: Source</title><content type='html'>Here's the resulting source code from my experimentation.

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;import&lt;/span&gt; '(java.net BindException ServerSocket Socket)
        '(java.lang.reflect InvocationTargetException)
        '(java.util Date)
        '(java.io InputStream OutputStream)
        '(java.util.concurrent Executors))


&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;Utility functions
&lt;/span&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;current-time&lt;/span&gt; []
  (&lt;span class="keyword"&gt;.&lt;/span&gt; (new Date) (toString)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;byte-arr-from-string&lt;/span&gt; [str]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; str (getBytes)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-byte-array-from-string&lt;/span&gt;
  ([]
   (test-byte-array-from-string (current-time)))
  ([str]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [barr (byte-arr-from-string str)
         bseq (map (comp char (appl aget barr))
                   (range (alength barr)))
         chseq (map char str)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (== (alength barr)
              (count bseq)
              (count chseq))
          (nil? (first (filter false?
                               (map eql?
                                    bseq
                                    chseq))))))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;string-from-byte-sequence&lt;/span&gt; [coll]
  (reduce strcat
          (map char coll)))


&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;Listener functions
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;These control the server
&lt;/span&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-new&lt;/span&gt; [port]
  (try (new ServerSocket port)
       (catch BindException except
              (println &lt;span class="string"&gt;"Address is already in use."&lt;/span&gt;))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-wait&lt;/span&gt; [listener]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (accept)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-close&lt;/span&gt; [listener]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (close)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-send&lt;/span&gt; [lsocket] 
  (&lt;span class="keyword"&gt;..&lt;/span&gt; lsocket
      (getOutputStream)
      (write (byte-arr-from-string (current-time))))
  (&lt;span class="keyword"&gt;..&lt;/span&gt; lsocket (getOutputStream) (close))
  lsocket)

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run&lt;/span&gt; [listener port]
  (&lt;span class="keyword"&gt;loop&lt;/span&gt; [socket nil]
    (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (isClosed))
      listener
      (&lt;span class="keyword"&gt;do&lt;/span&gt; (&lt;span class="keyword"&gt;when&lt;/span&gt; socket
            (&lt;span class="keyword"&gt;.&lt;/span&gt; (listener-send socket) (close)))
          (&lt;span class="keyword"&gt;recur&lt;/span&gt; (listener-wait listener))))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run-in-background&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)
        exec (&lt;span class="keyword"&gt;.&lt;/span&gt; Executors (newSingleThreadExecutor))
        run (appl listener-run listener port)]
    (&lt;span class="keyword"&gt;when&lt;/span&gt; listener
      (&lt;span class="keyword"&gt;.&lt;/span&gt; exec (submit run)))
    listener))

&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;Connection functions
&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;; &lt;/span&gt;&lt;span class="comment"&gt;These control the client.
&lt;/span&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-new&lt;/span&gt;
  ([port]
   (connection-new &lt;span class="string"&gt;"127.0.0.1"&lt;/span&gt; port))
  ([address port]
   (try (doto (new Socket address port)
          (setSoTimeout 5000))
        (catch InvocationTargetException except
               (println (strcat &lt;span class="string"&gt;"Could not connect to "&lt;/span&gt;
                                address
                                &lt;span class="string"&gt;" on port "&lt;/span&gt;
                                port))))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-read&lt;/span&gt; [conn]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [instream (&lt;span class="keyword"&gt;.&lt;/span&gt; conn (getInputStream))
        reader (fn [] (try (&lt;span class="keyword"&gt;.&lt;/span&gt; instream (read))
                           (catch InvocationTargetException except
                                  -1)))]
    (&lt;span class="keyword"&gt;loop&lt;/span&gt; [bytes nil
           current-byte (reader)]
      (&lt;span class="keyword"&gt;if&lt;/span&gt; (== current-byte -1)
        bytes
        (&lt;span class="keyword"&gt;recur&lt;/span&gt; (concat bytes (list current-byte))
               (reader))))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-close&lt;/span&gt; [conn]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; conn (close)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-run&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [conn (connection-new port)
        str (&lt;span class="keyword"&gt;when&lt;/span&gt; conn
              (string-from-byte-sequence (connection-read conn)))]
    (&lt;span class="keyword"&gt;when&lt;/span&gt; conn 
      (connection-close conn))
    str))
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-2500107895881759696?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/2500107895881759696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=2500107895881759696' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/2500107895881759696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/2500107895881759696'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2008/02/my-first-look-at-clojure-source.html' title='My first look at Clojure: Source'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12109108.post-7720410740161699717</id><published>2008-02-02T19:00:00.002-05:00</published><updated>2009-02-17T17:45:25.087-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>My first look at Clojure</title><content type='html'>&lt;h2&gt;Preliminaries&lt;/h2&gt;

&lt;p&gt;So, &lt;a href="http://clojure.sourceforge.net"&gt;&lt;em&gt;Clojure&lt;/em&gt;&lt;/a&gt; is a pretty little
language, a Lisp&lt;sup&gt;&lt;a name="note1"&gt;&lt;/a&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;
for the Java Virtual Machine.  That, in and of itself, doesn't say
much for or against it.&lt;/p&gt;

&lt;p&gt;I've been playing with it for a few days now and really finding that I
like more than I dislike and that the bits that I found to be
difficult were, well, being fixed or changed.&lt;sup&gt;&lt;a
name="note2"&gt;&lt;/a&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;In the spirit of &lt;a href="http://diveintopython.org"&gt;Dive Into Python&lt;/a&gt;, this
is the place where I should offer up a snippet of finished code and
then walk through it.  Unfortunately, only having used Clojure a few
days, I'm still in the first romance stage, rather than the stacks of
working code stage.&lt;/p&gt;

&lt;p&gt;So, rather than offering a block of code and then dissecting it, or
alternately doing the thing that seems common in ruminations on
functional languages&lt;sup&gt;&lt;a name="note3"&gt;&lt;/a&gt;&lt;a
href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; and offering up an example like:&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;fibs&lt;/span&gt;
  ([] (fibs 0 1))
  ([a] (fibs a 1))
  ([a b]
   (&lt;span class="keyword"&gt;lazy-cons&lt;/span&gt; a (fibs b (+ a b)))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;nthfib&lt;/span&gt; [n]
  (first (reverse (take n (fibs)))))
&lt;/pre&gt;

&lt;p&gt;That, while pretty in demonstrating infinite sequences and a simple
form of multiple dispatch, does little to offer a reason to actually
&lt;em&gt;use&lt;/em&gt; the language&lt;sup&gt;&lt;a name="note4"&gt;&lt;/a&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt;.
Instead, I'm going to try my hand at two things that have frustrated
me in the past with Lisp.  Namely sockets and threads&lt;sup&gt;&lt;a
name="note5"&gt;&lt;/a&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h2&gt;Goals&lt;/h2&gt;

&lt;p&gt;So, what I want is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A client that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Connects to a server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Listens and prints out what it hears.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A server that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Listens on a port&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creates a new thread on connection.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sends the current ctime to the client.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Disconnects.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or, essentially, the most primitive version of NTP imaginable.&lt;/p&gt;

&lt;p&gt;As Clojure runs on the JVM, first step becomes to open up
&lt;a href="http://java.sun.com/javase/6/docs/api/"&gt;JavaDoc&lt;/a&gt; and check what
objects I actually want.  I'll start by importing
&lt;a href="http://java.sun.com/javase/6/docs/api/java/net/ServerSocket.html"&gt;ServerSocket&lt;/a&gt;
and
&lt;a href="http://java.sun.com/javase/6/docs/api/java/net/Socket.html"&gt;Socket&lt;/a&gt;.&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(import '(java.net ServerSocket Socket))&lt;/span&gt;
nil
&lt;/pre&gt;

&lt;h2&gt;The most primitive client and server possible&lt;/h2&gt;

&lt;p&gt;At this point, all I want to do is make functions to open the
connections, so:&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-new&lt;/span&gt; [port]
  (new ServerSocket port))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-new&lt;/span&gt;
  ([port]
   (connection-new &lt;span class="string"&gt;"127.0.0.1"&lt;/span&gt; port))
  ([address port]
   (new Socket address port)))
&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;listener-new&lt;/code&gt; is a function that binds on a port and returns a Java
ServerSocket bound to that port.  &lt;code&gt;connection-new&lt;/code&gt; is a function
that takes either a port (in which case it connects to localhost) or
an address and a port and returns a Socket connected to that.&lt;/p&gt;

&lt;p&gt;I'll try to explain new terms and forms as I go.  The ones introduced
here are &lt;code&gt;defn&lt;/code&gt;, which creates a function, with the arguments in
square brackets, returning whatever the last value in its body is.&lt;/p&gt;

&lt;p&gt;So, &lt;code&gt;(defn [port] (new ServerSocket port))&lt;/code&gt; makes a function that
takes one argument and then calls the &lt;code&gt;new&lt;/code&gt; function, which
instantiates a Java object with whatever arguments are passed.  It
then returns whatever &lt;code&gt;new&lt;/code&gt; returns, which, unless there's an error,
should be a ServerSocket.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;defn&lt;/code&gt; can also accept multiple sets of arguments, in order to
either do a certain amount of pattern matching on them or, in this
case, provide a default value to a function.&lt;/p&gt;

&lt;p&gt;The next step, then, is to try each of these and see if they work.&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def serversocket (listener-new 56894))&lt;/span&gt;
#&amp;lt;Var: user/serversocket&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;serversocket&lt;/span&gt;
ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=56894]
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. serversocket (close))&lt;/span&gt;
Reflection warning, line: 17 - call to close can't be resolved.
nil
&lt;/pre&gt;

&lt;p&gt;So, the serversocket will open just fine, though I receive a
(relatively harmless) type warning when I close it.  That can be
removed either by ensuring that the close method call ensures (via a
type annotation) that what is passed to it is indeed a serversocket
and that what is returned by &lt;code&gt;listener-new&lt;/code&gt; is also a
serversocket.&lt;/p&gt;

&lt;p&gt;For the present, though, I don't actually care about this warning.
Let's try &lt;code&gt;connection-new&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def socket (connection-new 56894))&lt;/span&gt;
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at clojure.lang.Reflector.invokeConstructor(Reflector.java:125)
        at user.connection_new.invoke(Unknown Source)
        at user.connection_new.invoke(Unknown Source)
        at clojure.lang.AFn.applyToHelper(AFn.java:173)
        at clojure.lang.AFn.applyTo(AFn.java:164)
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2213)
        at clojure.lang.Compiler$DefExpr.eval(Compiler.java:253)
        at clojure.lang.Compiler.eval(Compiler.java:3086)
        at clojure.lang.Repl.main(Repl.java:59)
Caused by: java.net.ConnectException: Connection refused: connect
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.PlainSocketImpl.doConnect(Unknown Source)
        at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
        at java.net.PlainSocketImpl.connect(Unknown Source)
        at java.net.SocksSocketImpl.connect(Unknown Source)
        at java.net.Socket.connect(Unknown Source)
        at java.net.Socket.connect(Unknown Source)
        at java.net.Socket.&amp;lt;init&amp;gt;(Unknown Source)
        at java.net.Socket.&amp;lt;init&amp;gt;(Unknown Source)
        ... 13 more
&lt;/pre&gt;

&lt;p&gt;Oh dear.  Well, that didn't work.  Though, I suppose having a port
open to connect to might just help.&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def ssocket (listener-new 56894))&lt;/span&gt;
#&amp;lt;Var: user/ssocket&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def socket (connection-new 56894))&lt;/span&gt;
#&amp;lt;Var: user/socket&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. socket close)&lt;/span&gt;
Reflection warning, line: 45 - reference to field close can't be resolved.
java.lang.IllegalArgumentException: No matching field found
        at clojure.lang.Reflector.getInstanceField(Reflector.java:175)
        at clojure.lang.Compiler$InstanceFieldExpr.eval(Compiler.java:744)
        at clojure.lang.Compiler.eval(Compiler.java:3086)
        at clojure.lang.Repl.main(Repl.java:59)
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. socket (close))&lt;/span&gt;
Reflection warning, line: 53 - call to close can't be resolved.
nil
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. ssocket (close))&lt;/span&gt;
Reflection warning, line: 54 - call to close can't be resolved.
nil
&lt;/pre&gt;

&lt;p&gt;And that does it.  The error in that block was because I referred to
close as a field: &lt;code&gt;close&lt;/code&gt;, rather than a method: &lt;code&gt;(close)&lt;/code&gt;.  On
the other hand, this doesn't do anything &lt;em&gt;interesting&lt;/em&gt;.  It just makes
and closes the listener and the connection.&lt;/p&gt;

&lt;p&gt;Now, the &lt;code&gt;.&lt;/code&gt; operator.  I've used it a few times so far, so I should
clarify what it does.  It looks up the second value within the first
one.  Thus, &lt;code&gt;(. socket (close))&lt;/code&gt; looks for a &lt;code&gt;close&lt;/code&gt; method inside
the instance &lt;code&gt;socket&lt;/code&gt;, then calls it.  &lt;/p&gt;

&lt;p&gt;Next, I need to add behaviour to the server to detect connection and
send the ctime, as well as making the client recognise that data is
being passed to it.&lt;/p&gt;

&lt;h2&gt;Adding data&lt;/h2&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;import&lt;/span&gt; '(java.net ServerSocket Socket)
        '(java.util Date))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;current-time&lt;/span&gt; []
  (&lt;span class="keyword"&gt;.&lt;/span&gt; (new Date) (toString)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-new&lt;/span&gt; [port]
  (new ServerSocket port))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-wait&lt;/span&gt; [listener]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (accept)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-send&lt;/span&gt; [lsocket]
  (&lt;span class="keyword"&gt;..&lt;/span&gt; lsocket (getOutputStream) (write (current-time)))
  lsocket)

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-close&lt;/span&gt; [listener]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (close)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)]
    (listener-send (listener-wait listener))
    (listener-close)))
&lt;/pre&gt;

&lt;p&gt;So now I've added a function that dumps the current time as a string,
as well as functions to accept a connection, send that current time
and disconnect.&lt;/p&gt;

&lt;p&gt;Trying it out, I get:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(current-time)&lt;/span&gt;
&lt;span class="string"&gt;"Sat Feb 02 12:16:19 EST 2008"&lt;/span&gt;
&lt;span class="comint-highlight-prompt"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(listener-run 51245)&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;And then it hangs.  Unsurprisingly, really, as it's blocking at
&lt;code&gt;(. listener (accept))&lt;/code&gt;, which waits for a connection before
returning the socket referring to that connection.  While this would
be a good place to make the thread that I was talking about earlier,
for the moment, I just want to see if this actually works.  So, what
I'll do is start the server in a separate REPL&lt;a
name="note6"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn6"&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;So, in the one REPL, I create the server again:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(listener-run 51345)&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;And in the other, I connect to it:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-new 51345)&lt;/span&gt;
Socket[addr=/127.0.0.1,port=51345,localport=1668]
&lt;/pre&gt;

&lt;p&gt;Which results in this in the first REPL.&lt;/p&gt;

&lt;pre class="code"&gt;
java.lang.IllegalArgumentException: No matching method found: write
        at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:59)
        at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:26)
        at user.listener_send.invoke(sockets.clj:15)
        at user.listener_run.invoke(sockets.clj:23)
        at clojure.lang.AFn.applyToHelper(AFn.java:173)
        at clojure.lang.AFn.applyTo(AFn.java:164)
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2213)
        at clojure.lang.Compiler.eval(Compiler.java:3086)
        at clojure.lang.Repl.main(Repl.java:59)
&lt;/pre&gt;

&lt;h2&gt;Debugging data transmission&lt;/h2&gt;

&lt;p&gt;Now, despite this being an error, it does show that the listener made
it to &lt;code&gt;listener-send&lt;/code&gt;, as that's where write is called.  So, I know
that it's accepting network connections.  Unfortunately, it's crashing
when it receives them.&lt;/p&gt;

&lt;p&gt;So, my next step is to look at what that command actually does:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(macroexpand '(.. lsocket (getOutputStream) (write (current-time))))&lt;/span&gt;
(. (. lsocket (getOutputStream)) (write (current-time)))
&lt;/pre&gt;

&lt;p&gt;The macroexpand function takes a macro passed to it and evaluates it
(as well as macros inside that one, recursively).  So I know that
write is being called on the outputstream of the socket.  For
debugging purposes, I'll rewrite &lt;code&gt;listener-send&lt;/code&gt; procedurally.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-send&lt;/span&gt; [lsocket]
  (println lsocket)
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [outputstream (&lt;span class="keyword"&gt;.&lt;/span&gt; lsocket (getOutputStream))]
    (println outputstream (current-time))
    (&lt;span class="keyword"&gt;.&lt;/span&gt; outputstream (write (current-time)))
    lsocket))
&lt;/pre&gt;

&lt;p&gt;This is the same function, only it's spitting out its state at each
stage.&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(listener-run 51345)&lt;/span&gt;
java.lang.IllegalArgumentException: No matching method found: write
        at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:59)
        at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:26)
        at user.listener_send.invoke(sockets.clj:18)
        at user.listener_run.invoke(sockets.clj:26)
        at clojure.lang.AFn.applyToHelper(AFn.java:173)
        at clojure.lang.AFn.applyTo(AFn.java:164)
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2213)
        at clojure.lang.Compiler.eval(Compiler.java:3086)
        at clojure.lang.Repl.main(Repl.java:59)
Socket[addr=/127.0.0.1,port=1789,localport=51345]
java.net.SocketOutputStream@26dbec Sat Feb 02 13:08:22 EST 2008
&lt;/pre&gt;

&lt;p&gt;This time, with output, I can see that I indeed get an OutputStream.
Time to play with it and see what it's doing.&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;(&lt;span class="keyword"&gt;import&lt;/span&gt; '(java.io InputStream OutputStream)
nil
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def li (listener-new 51345))&lt;/span&gt;
#&amp;lt;Var: user/li&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def sock (listener-wait li))&lt;/span&gt;
#&amp;lt;Var: user/sock&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def by (. (current-time) (getBytes)))&lt;/span&gt;
Reflection warning, line: 46 - call to getBytes can't be resolved.
#&amp;lt;Var: user/by&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(map (comp char (appl aget by)) (range (alength by)))&lt;/span&gt;
(\S \a \t \space \F \e \b \space \0 \2 \space \1 \3 \: \4 \9 \: \4 \4 \space \E \S \T \space \2 \0 \0 \8)
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def ostream (. sock (getOutputStream)))&lt;/span&gt;
Reflection warning, line: 48 - call to getOutputStream can't be resolved.
#&amp;lt;Var: user/ostream&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. ostream (write by))&lt;/span&gt;
Reflection warning, line: 49 - call to write can't be resolved.
nil
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(listener-close li)&lt;/span&gt;
nil
&lt;/pre&gt;

&lt;p&gt;So, there's the catch.  When I pass &lt;code&gt;current-time&lt;/code&gt; directly to the
OutputStream's write method, what's expected is a &lt;code&gt;write( String s )&lt;/code&gt;.
What actually exists is &lt;code&gt;write( Byte[] barr )&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The map done on &lt;code&gt;by&lt;/code&gt; is worth looking at, though.  I used it to find
out what exactly &lt;code&gt;by&lt;/code&gt; was set to, it being a Java array.  So, first
off, I get a list of all numbers from 0 to the length of &lt;code&gt;by&lt;/code&gt;:
&lt;code&gt;(range (alength by))&lt;/code&gt;.  That's the indices to the array.  Then
&lt;code&gt;(comp char (appl aget by))&lt;/code&gt;&lt;a
name="note7"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn7"&gt;7&lt;/a&gt;&lt;/sup&gt; is called on each of those.&lt;/p&gt;

&lt;h2&gt;Converting to and from byte arrays.&lt;/h2&gt;

&lt;p&gt;This actually raises a valid assertion.  When creating a byte array
from a string, the character values in the byte array should be the
same as those in the string.&lt;/p&gt;

&lt;p&gt;So, I'll create a function (that I'll use in a minute anyway) that
makes a Java byte array out of a string.  And, because I'm starting to
get more cautious after my repeated bugs, I'll make a simple test to
assert that its results are the same as the string from which it was
made.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;byte-arr-from-string&lt;/span&gt; [str]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; str (getBytes)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;test-byte-array-from-string&lt;/span&gt;
  ([]
   (test-byte-array-from-string (current-time)))
  ([str]
   (&lt;span class="keyword"&gt;let&lt;/span&gt; [barr (byte-arr-from-string str)
         bseq (map (comp char (appl aget barr))
                   (range (alength barr)))
         chseq (map char str)]
     (&lt;span class="keyword"&gt;and&lt;/span&gt; (== (alength barr)
              (count bseq)
              (count chseq))
          (== 0
              (count (filter false?
                             (map eql?
                                  bseq
                                  chseq))))))))
&lt;/pre&gt;

&lt;p&gt;There.  A String to Byte[] converter and a unit test.  Now, to run the test:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(test-byte-array-from-string)&lt;/span&gt;
true
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(test-byte-array-from-string &lt;/span&gt;&lt;span class="string"&gt;"qwertyuiop"&lt;/span&gt;&lt;span class="comint-highlight-input"&gt;)&lt;/span&gt;
true
&lt;/pre&gt;

&lt;p&gt;And the test indicates that there is no loss &lt;em&gt;per se&lt;/em&gt; in converting
the string to a byte array.  That done, I'll add the conversion to a
byte array into &lt;code&gt;listener-send&lt;/code&gt;.  If that works, I'll collapse the
expanded debuggy &lt;code&gt;listener-send&lt;/code&gt; back down.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-send&lt;/span&gt; [lsocket]
  (println lsocket)
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [outputstream (&lt;span class="keyword"&gt;.&lt;/span&gt; lsocket (getOutputStream))]
    (println outputstream
             (current-time)
             (instance? outputstream java.io.OutputStream))
    (&lt;span class="keyword"&gt;.&lt;/span&gt; outputstream (write (byte-arr-from-string (current-time))))
    lsocket))
&lt;/pre&gt;

&lt;p&gt;And now a further round of testing:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(listener-run 51345)&lt;/span&gt;
Socket[addr=/127.0.0.1,port=2564,localport=51345]
java.net.SocketOutputStream@88e2dd Sat Feb 02 15:23:04 EST 2008 true
nil
&lt;/pre&gt;

&lt;p&gt;So, the server says (more or less) that it did its steps and nothing
went wrong.  Let's check this from the other side:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def conn (connection-new 51345))&lt;/span&gt;
#&amp;lt;Var: user/conn&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def ins (. conn (getInputStream)))&lt;/span&gt;
Reflection warning, line: 69 - call to getInputStream can't be resolved.
#&amp;lt;Var: user/ins&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;ins&lt;/span&gt;
java.net.SocketInputStream@453807
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. ins (read))&lt;/span&gt;
Reflection warning, line: 71 - call to read can't be resolved.
83
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. ins (read))&lt;/span&gt;
Reflection warning, line: 72 - call to read can't be resolved.
97
&lt;/pre&gt;

&lt;p&gt;And, at the other end, I get the bytes that (I think) I sent.  Time to
wrap up my client connection and get it to read the entire input stream.&lt;/p&gt;

&lt;h2&gt;Reading the transmitted data&lt;/h2&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;string-from-byte-sequence&lt;/span&gt; [coll]
  (reduce strcat coll))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-new&lt;/span&gt;
  ([port]
   (connection-new &lt;span class="string"&gt;"127.0.0.1"&lt;/span&gt; port))
  ([address port]
   (new Socket address port)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-read&lt;/span&gt; [conn]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [instream (&lt;span class="keyword"&gt;.&lt;/span&gt; conn (getInputStream))]
    (&lt;span class="keyword"&gt;loop&lt;/span&gt; [bytes nil
           current-byte (&lt;span class="keyword"&gt;.&lt;/span&gt; instream (read))]
      (&lt;span class="keyword"&gt;if&lt;/span&gt; (== current-byte -1)
        bytes
        (&lt;span class="keyword"&gt;recur&lt;/span&gt; (conj bytes current-byte)
               (&lt;span class="keyword"&gt;.&lt;/span&gt; instream (read)))))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-close&lt;/span&gt; [conn]
  (&lt;span class="keyword"&gt;.&lt;/span&gt; conn (close)))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-run&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [conn (connection-new port)
        str (string-from-byte-sequence (connection-read conn))]
    (connection-close conn)
    str))
&lt;/pre&gt;

&lt;p&gt;So, what this is trying to do is open a connection, read from it until
the number -1 is found and then returning the resulting sequence of
bytes.&lt;/p&gt;

&lt;p&gt;Why -1?  Because &lt;a href="http://java.sun.com/javase/6/docs/api/java/io/InputStream.html#read("&gt;the JavaDoc for InputStream::Read&lt;/a&gt;)
says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The value byte is returned as an int in the range 0 to 255. If no
  byte is available because the end of the stream has been reached,
  the value -1 is returned. This method blocks until input data is
  available, the end of the stream is detected, or an exception is
  thrown.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I'm trying -1 first, as by the time I'm reading, &lt;code&gt;listener-close&lt;/code&gt;
should have been called, closing the socket.&lt;/p&gt;

&lt;h2&gt;Bugs with reading the data&lt;/h2&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-run 51348)&lt;/span&gt;
&lt;span class="string"&gt;"5648485032848369325048584949585449325048329810170321169783"&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;So, it reads fine, but it appears that something went wrong in
translating the byte sequence into a string again.  Looking at
&lt;code&gt;string-from-byte-sequence&lt;/code&gt;, it concatenates the string values of
the items in the collection.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;string-from-byte-sequence&lt;/span&gt; [coll]
  (reduce strcat coll))
&lt;/pre&gt;

&lt;p&gt;So, I'll try concatenating two numbers:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(strcat 64 65)&lt;/span&gt;
&lt;span class="string"&gt;"6465"&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Right, not what I was intending at all.  So, before I concatenate the
numbers, I'll need to convert them to characters.&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(strcat (char 64) (char 65))&lt;/span&gt;
&lt;span class="string"&gt;"@A"&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;That worked a lot better.  And tells me what I need to do to fix the function:&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;string-from-byte-sequence&lt;/span&gt; [coll]
  (reduce strcat
          (map char coll)))
&lt;/pre&gt;

&lt;p&gt;Because map is lazy, it means that simply using &lt;code&gt;(strcat (map char
coll))&lt;/code&gt; gets me the string value of &lt;code&gt;map&lt;/code&gt;'s returned FnSeq instead
of the concatenated characters.  The &lt;code&gt;reduce&lt;/code&gt; acts to apply
&lt;code&gt;strcat&lt;/code&gt; to every element of the entire sequence.&lt;/p&gt;

&lt;p&gt;And, connecting to a new server, I get:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-run 51349)&lt;/span&gt;
&lt;span class="string"&gt;"8002 TSE 15:13:61 20 beF taS"&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Whoops, almost it!  Only backwards.  Checking the byte sequence as it comes
in, I find that it is indeed reversed when returned from
&lt;code&gt;connection-read&lt;/code&gt;.  So, I test what &lt;code&gt;connection-read&lt;/code&gt; does to
build the byte sequence:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(conj (conj nil 1) 2)&lt;/span&gt;
(2 1)
&lt;/pre&gt;

&lt;p&gt;So I check the documentation for conj and indeed:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Conj[oin]. Returns a new collection with the item 'added'. (conj nil
  item) returns (item). The 'addition' may happen at different
  'places' depending on the concrete type.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An amendment to &lt;code&gt;connection-read&lt;/code&gt; later:&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-read&lt;/span&gt; [conn]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [instream (&lt;span class=";keyword"&gt;.&lt;/span&gt; conn (getInputStream))]
    (&lt;span class="keyword"&gt;loop&lt;/span&gt; [bytes nil
           current-byte (&lt;span class="keyword"&gt;.&lt;/span&gt; instream (read))]
      (&lt;span class="keyword"&gt;if&lt;/span&gt; (== current-byte -1)
        bytes
        (&lt;span class="keyword"&gt;recur&lt;/span&gt; (concat bytes (list current-byte))
               (&lt;span class="keyword"&gt;.&lt;/span&gt; instream (read)))))))
&lt;/pre&gt;

&lt;p&gt;And I finally get the desired result:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-run 51354)&lt;/span&gt;
&lt;span class="string"&gt;"Sat Feb 02 16:44:09 EST 2008"&lt;/span&gt;
&lt;/pre&gt;

&lt;h2&gt;Bugfixing the primitive NTP server&lt;/h2&gt;

&lt;p&gt;So, what I now have is a server that waits for a connection on a given
port, then sends the time and a client that makes a connection and
reads the time.  What I &lt;em&gt;don't&lt;/em&gt; have is a bug-free or elegant version
of this.&lt;/p&gt;

&lt;p&gt;Time for me to run down the list of bugs and desires that I know of
at the moment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The server fails to clean up its port correctly, meaning that
throughout this testing, I've been incrementing ports any time I
choose to keep the server's REPL open.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The client will hang, waiting for data in its stream, when fed a port
that is open but not responding.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The server is single-threaded still.  This is the only one of my six
test-application goals left undone.  But making it not block the
REPL while waiting for input will make testing far easier.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No Java exceptions are currently handled, despite their being
thrown.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ten reflection warnings when I load the file into my REPL.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;test-byte-array-from-string&lt;/code&gt; is the only test attached.  The
behaviour of all the functions &lt;em&gt;should&lt;/em&gt; be testable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It would be nice (though not &lt;em&gt;useful&lt;/em&gt; in this case) to represent the
data stream as a lazy sequence, rather than expecting that it all be
here.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, I'll address these in order, starting with the server port.&lt;/p&gt;

&lt;h3&gt;The server fails to clean up its port...&lt;/h3&gt;

&lt;p&gt;I'll start by looking at what &lt;code&gt;listener-run&lt;/code&gt; actually does.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)]
    (listener-close (listener-send (listener-wait listener)))
    listener))
&lt;/pre&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It binds &lt;code&gt;listener&lt;/code&gt; to a new ServerSocket listening on &lt;code&gt;port&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It passes that ServerSocket to &lt;code&gt;listener-wait&lt;/code&gt;, which calls the
&lt;code&gt;accept&lt;/code&gt; method, returning the opened socket.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That socket is passed to &lt;code&gt;listener-send&lt;/code&gt;, which gets its
OutputStream and writes the current time to the stream, returning the
socket.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That socket is passed on to &lt;code&gt;listener-close&lt;/code&gt;, which closes it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The listener is returned.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And thatfourth step would likely be the problem here.  Rather than
closing the listener, it's closing the socket acquired from
&lt;code&gt;accept&lt;/code&gt;, which means that rather than five, I only have four goals
complete.&lt;/p&gt;

&lt;p&gt;So, I'll try:&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)]
    (listener-send (listener-wait listener))
    (listener-close listener)
    listener))
&lt;/pre&gt;

&lt;p&gt;But that has the net result that now, the server still holds onto that
address, but the client hangs, waiting for data.  A little bit of
prodding later and I have this:&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-send&lt;/span&gt; [lsocket] 
  (&lt;span class="keyword"&gt;..&lt;/span&gt; lsocket
      (getOutputStream)
      (write (byte-arr-from-string (current-time))))
  (&lt;span class="keyword"&gt;..&lt;/span&gt; lsocket (getOutputStream) (close))
  lsocket)

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)]
    (&lt;span class="keyword"&gt;.&lt;/span&gt; (listener-send (listener-wait listener)) (close))
    (listener-close listener)
    listener))
&lt;/pre&gt;

&lt;p&gt;Which successfully sends the time across the (loopback) network, then
releases the port.&lt;/p&gt;

&lt;h3&gt;The client will hang...&lt;/h3&gt;

&lt;p&gt;Not exactly true.  I wrote that forgetting that I had random
ServerSockets poking around.  In fact, what happens when the client is
passed a closed port is:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-new 1500)&lt;/span&gt;
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at clojure.lang.Reflector.invokeConstructor(Reflector.java:125)
        at user.connection_new.invoke(Unknown Source)
        at user.connection_new.invoke(Unknown Source)
        at user.connection_run.invoke(Unknown Source)
        at clojure.lang.AFn.applyToHelper(AFn.java:173)
        at clojure.lang.AFn.applyTo(AFn.java:164)
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2213)
        at clojure.lang.Compiler.eval(Compiler.java:3086)
        at clojure.lang.Repl.main(Repl.java:59)
Caused by: java.net.ConnectException: Connection refused: connect
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.PlainSocketImpl.doConnect(Unknown Source)
        at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
        at java.net.PlainSocketImpl.connect(Unknown Source)
        at java.net.SocksSocketImpl.connect(Unknown Source)
        at java.net.Socket.connect(Unknown Source)
        at java.net.Socket.connect(Unknown Source)
        at java.net.Socket.&amp;lt;init&amp;gt;(Unknown Source)
        at java.net.Socket.&amp;lt;init&amp;gt;(Unknown Source)
        ... 13 more
&lt;/pre&gt;

&lt;p&gt;Conclusion: I need to not only handle connection timeouts but also
refused connections.  As this happens in &lt;code&gt;connection-new&lt;/code&gt;, which
only has one instruction, I need to wrap the new socket in a try/catch
block.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-new&lt;/span&gt;
  ([port]
   (connection-new &lt;span class="string"&gt;"127.0.0.1"&lt;/span&gt; port))
  ([address port]
   (try (new Socket address port)
        (catch InvocationTargetException except
               (println (strcat &lt;span class="string"&gt;"Could not connect to "&lt;/span&gt;
                                address
                                &lt;span class="string"&gt;" on port "&lt;/span&gt;
                                port))))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-run&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [conn (connection-new port)
        str (&lt;span class="keyword"&gt;when&lt;/span&gt; conn (string-from-byte-sequence (connection-read conn)))]
    (&lt;span class="keyword"&gt;when&lt;/span&gt; conn 
      (connection-close conn))
    str))
&lt;/pre&gt;

&lt;p&gt;So now trying to connect to an invalid port spits an error message and
returns nil.  On the other hand, it still hangs when pushed to connect
to a port that doesn't behave like it expects (send data, close
socket).&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-new 1280)&lt;/span&gt;
Could not connect to 127.0.0.1 on port 1280
nil
&lt;/pre&gt;

&lt;p&gt;The answer, then, is to give the client a timeout after which it
assumes that no data is coming.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-new&lt;/span&gt;
  ([port]
   (connection-new &lt;span class="string"&gt;"127.0.0.1"&lt;/span&gt; port))
  ([address port]
   (try (doto (new Socket address port)
          (setSoTimeout 5000))
        (catch InvocationTargetException except
               (println (strcat &lt;span class="string"&gt;"Could not connect to "&lt;/span&gt;
                                address
                                &lt;span class="string"&gt;" on port "&lt;/span&gt;
                                port))))))

(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;connection-read&lt;/span&gt; [conn]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [instream (&lt;span class="keyword"&gt;.&lt;/span&gt; conn (getInputStream))
        reader (fn [] (try (&lt;span class="keyword"&gt;.&lt;/span&gt; instream (read))
                           (catch InvocationTargetException except
                                  -1)))]
    (&lt;span class="keyword"&gt;loop&lt;/span&gt; [bytes nil
           current-byte (reader)]
      (&lt;span class="keyword"&gt;if&lt;/span&gt; (== current-byte -1)
        bytes
        (&lt;span class="keyword"&gt;recur&lt;/span&gt; (concat bytes (list current-byte))
               (reader))))))
&lt;/pre&gt;

&lt;p&gt;So now, if nothing comes in in five seconds, &lt;code&gt;connection-read&lt;/code&gt;
signals an error and flags the current byte as -1, signalling an end
of the transmission.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;doto&lt;/code&gt;, which I used to set the socket timeout, takes an instance,
evaluates the following body on it, then returns the changed instance.
I used it in this case because &lt;code&gt;setSoTimeout&lt;/code&gt; returns void while
changing the object's state.&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-run 80)&lt;/span&gt;
&lt;span class="string"&gt;""&lt;/span&gt;
&lt;/pre&gt;

&lt;h3&gt;The server is single-threaded...&lt;/h3&gt;

&lt;p&gt;Oh bugger.  I really should have put this lower on the list.  I did
&lt;em&gt;not&lt;/em&gt; want to deal with threading today.&lt;/p&gt;

&lt;p&gt;So, that leaves me the question: What should the server do?  For
starters, I'll make its instances persistant.  That way, with a single
server open, I can connect repeatedly without restarting the server
each time.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run&lt;/span&gt;
  ([port]
   (listener-run (listener-new port)
                 port))
  ([listener port]
   (&lt;span class="keyword"&gt;loop&lt;/span&gt; [socket nil]
     (&lt;span class="keyword"&gt;when&lt;/span&gt; socket
       (&lt;span class="keyword"&gt;.&lt;/span&gt; (listener-send socket) (close)))
     (&lt;span class="keyword"&gt;recur&lt;/span&gt; (listener-wait listener)))
   listener))
&lt;/pre&gt;

&lt;p&gt;However, what I &lt;em&gt;want&lt;/em&gt; is for that same function to be pushed into the
background.  So, for starters, I'll give the loop an exit condition:&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run&lt;/span&gt; [listener port]
  (&lt;span class="keyword"&gt;loop&lt;/span&gt; [socket nil]
    (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="keyword"&gt;.&lt;/span&gt; listener (isClosed))
      listener
      (&lt;span class="keyword"&gt;do&lt;/span&gt; (&lt;span class="keyword"&gt;when&lt;/span&gt; socket
            (&lt;span class="keyword"&gt;.&lt;/span&gt; (listener-send socket) (close)))
          (&lt;span class="keyword"&gt;recur&lt;/span&gt; (listener-wait listener))))))
&lt;/pre&gt;

&lt;p&gt;Now, if I happen to have captured the listener, I can kill the server
process by closing the listener.  This isn't useful yet, as the server
will still loop infinitely when it's launched.&lt;/p&gt;

&lt;p&gt;To make sure that I'm not holding on to inaccessable listeners, I also
removed my earlier convenience form that created a listener for me.&lt;/p&gt;

&lt;p&gt;So, time to push listener-run into its own execution thread.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run-in-background&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)]
    (listener-run listener port)
    listener))
&lt;/pre&gt;

&lt;p&gt;There's a starting form.  Though all it does at the moment is run the
listener in the same way as the bits I removed above, I'll now poke at
adding Java's concurrency bits into it.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run-in-background&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)
        exec (&lt;span class="keyword"&gt;.&lt;/span&gt; Executors (newSingleThreadExecutor))
        run (appl listener-run listener port)]
    (&lt;span class="keyword"&gt;.&lt;/span&gt; exec (submit run))
    listener))
&lt;/pre&gt;

&lt;p&gt;So, that's a first attempt.  It creates a pool of one thread, wraps
running the server in an anonymous function and punts the function off
to the thread pool.&lt;/p&gt;

&lt;p&gt;And testing it:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def li (listener-run-in-background 51345))&lt;/span&gt;
#&amp;lt;Var: user/li&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;li&lt;/span&gt;
ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=51345]
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-run 51345)&lt;/span&gt;
&lt;span class="string"&gt;"Sat Feb 02 20:49:15 EST 2008"&lt;/span&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-run 51345)&lt;/span&gt;
&lt;span class="string"&gt;"Sat Feb 02 20:49:16 EST 2008"&lt;/span&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-run 51345)&lt;/span&gt;
&lt;span class="string"&gt;"Sat Feb 02 20:49:17 EST 2008"&lt;/span&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. li (close))&lt;/span&gt;
Reflection warning, line: 560 - call to close can't be resolved.
nil
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;li&lt;/span&gt;
ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=51345]
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. li (isClosed))&lt;/span&gt;
Reflection warning, line: 562 - call to isClosed can't be resolved.
true
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-run 51345)&lt;/span&gt;
Could not connect to 127.0.0.1 on port 51345
nil
&lt;/pre&gt;

&lt;p&gt;You know, I was expecting that to not work.  That really shouldn't
have been that easy.  To be fair, this doesn't do anything with that
thread pool that I created.  So I'll shut it down once I'm done
running the server.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-run-in-background&lt;/span&gt; [port]
  (&lt;span class="keyword"&gt;let&lt;/span&gt; [listener (listener-new port)
        exec (&lt;span class="keyword"&gt;.&lt;/span&gt; Executors (newSingleThreadExecutor))
        run (fn [] (&lt;span class="keyword"&gt;do&lt;/span&gt; (listener-run listener port)
                       (&lt;span class="keyword"&gt;.&lt;/span&gt; exec (shutdown))))]
    (&lt;span class="keyword"&gt;.&lt;/span&gt; exec (submit run))
    (list exec listener)))
&lt;/pre&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-run 51345)&lt;/span&gt;
&lt;span class="string"&gt;""&lt;/span&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;li&lt;/span&gt;
(java.util.concurrent.Executors$FinalizableDelegatedExecutorService@19bb25a ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=51345])
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(connection-run 51345)&lt;/span&gt;
&lt;span class="string"&gt;""&lt;/span&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(. (first li) (isShutdown))&lt;/span&gt;
Reflection warning, line: 114 - call to isShutdown can't be resolved.
true
&lt;/pre&gt;

&lt;p&gt;And that, on the other hand, fails miserably, as do my next six
attempts.  Then it finally occurs that, since in my original version,
the executor is empty and unreferenced, all I'm really doing, as I try
to bind &lt;code&gt;exec&lt;/code&gt; inside itself with increasingly complex combinations
of let, do, appl and fn, is creating circular references, and that I'd
really just be a lot better off letting that
&lt;a href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html"&gt;ExecutorService&lt;/a&gt;
fall on the floor and assuming that, because it can't be reached,
it'll get picked up by the garbage collection&lt;a name="note8"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn8"&gt;8&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h3&gt;No Java exceptions are currently handled...&lt;/h3&gt;

&lt;p&gt;Well, I dealt with two of the three exceptions that I'm seeing
routinely.  Better catch the other one, the BindException when trying
to launch two servers at the same port.&lt;/p&gt;

&lt;pre class="code"&gt;
(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;listener-new&lt;/span&gt; [port]
  (try (new ServerSocket port)
       (catch BindException except
              (println &lt;span class="string"&gt;"Address is already in use."&lt;/span&gt;))))
&lt;/pre&gt;

&lt;p&gt;And checking that with an open server:&lt;/p&gt;

&lt;pre class="code"&gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def li (listener-run-in-background 51345))&lt;/span&gt;
#&amp;lt;Var: user/li&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;(def li (listener-run-in-background 51345))&lt;/span&gt;
Address is already in use.
#&amp;lt;Var: user/li&amp;gt;
&lt;span class="comint-highlight-prompt"&gt;user=&amp;gt; &lt;/span&gt;&lt;span class="comint-highlight-input"&gt;li&lt;/span&gt;
nil
&lt;/pre&gt;

&lt;h2&gt;Afterthoughts&lt;/h2&gt;

&lt;p&gt;I'll count that one as done and take a look back at what needs doing.
Type/reflection warnings, unit tests and cleaning my hacky "just get
it done" code.  Really, not bad for an afternoon's learning.&lt;/p&gt;

&lt;p&gt;Further things to play with, from this tangent at least, seem to be:
serialization: seeing just what I can push as an array of bytes,
poking at java.lang.Concurrent and seeing how it reacts.&lt;/p&gt;

&lt;p&gt;But as someone who's written more Lisp than Java in his life, I have
to say, Clojure had me at the (.) function.  Lisp plus library support
is making this a very neat language to learn, and unlike my previous
forays into Common Lisp, I haven't hit a wall where I found myself
needing to reimplement something common&lt;a name="note9"&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href="#fn9"&gt;9&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Also, despite fairly routinely using (basic) Java objects in this
exercise, I never felt like I was having to coerce things to fit a
foreign function interface.  For that matter, this approach felt more
or less like the right way to use objects: as a very rich system of
types, rather than as a way to control program structure and flow.&lt;/p&gt;

&lt;hr&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn1"&gt;&lt;/a&gt;It's not Common Lisp and it's not Scheme.  It's
its own dialect. &lt;a href="#note1"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn2"&gt;&lt;/a&gt;To wit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Namespace examination and the capacity to work in multiple files
without having to think too hard about how imports interact.
(Fixed in the latest version with namespaces becoming
first-class citizens.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Metadata being applicable to everything, not just symbols and
sequences.  (On the agenda to be added.) &lt;a
href="#note2"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn3"&gt;&lt;/a&gt;Clojure counts, for all intents and purposes, as
a functional language.  It's certainly less strict than Haskell, but
on a par with the ML family in terms of being functional. &lt;a
href="#note3"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn4"&gt;&lt;/a&gt;That naive implementation ran out of heap space
at 100000 numbers.  Likely binding it to a var would help.&lt;/p&gt;

&lt;p&gt;After testing, apparently not.&lt;a href="#note4"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn5"&gt;&lt;/a&gt;I'm aware that there's lisps with good socket
implementations and ones with good threading implementations.  It's
just that, for me at least, I've never found the two things in the
same place at the same time when I needed them. &lt;a href="#note5"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn6"&gt;&lt;/a&gt;&lt;strong&gt;REPL&lt;/strong&gt;: Read Evaluate Print Loop.  A shell in
which you interact with your program and the language.&lt;/p&gt;

&lt;p&gt;In theory, I could have written all of this within the Clojure
REPL.  In practice, it's far simpler to write functions in a
separate file and then send them to the REPL.&lt;/p&gt;

&lt;p&gt;This means that, when I do something silly like causing the REPL
to hang due to waiting for a network connection, I can just reload
my file of functions.&lt;/p&gt;

&lt;p&gt;Also, it &lt;em&gt;does&lt;/em&gt; mean that, at the end of the day, I have my
functions in useable and modifiable form, rather than as java
bytecote that will be lost when I close the REPL.  &lt;a
href="#note6"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn7"&gt;&lt;/a&gt;This is an admittedly Haskellish way to build a
function.  In this case, its results are directly equivalent to
the anonymous function &lt;code&gt;(fn [x] (char (aget by x)))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To dissect this a little more, &lt;code&gt;appl&lt;/code&gt; takes a function and at
least one argument, then returns a new function that takes the
rest of the original function's arguments.  In other words, it
applies the arguments given to it partially.&lt;/p&gt;

&lt;p&gt;This means that my &lt;code&gt;(appl aget by)&lt;/code&gt; creates a new function
equivalent to &lt;code&gt;(fn [a] (aget by a))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;comp&lt;/code&gt;, on the other hand, is function composition.  For f(a)
and g(b) &lt;code&gt;f .comp. g&lt;/code&gt; is equivalent to &lt;code&gt;f( g( b ) )&lt;/code&gt; or &lt;code&gt;(f
(g a))&lt;/code&gt;.  In other words, it takes functions and makes a new
function that applies them from right to left to its arguments.&lt;/p&gt;

&lt;p&gt;Were I expanding out this function completely, on expanding
&lt;code&gt;appl&lt;/code&gt;, it becomes: &lt;code&gt;(comp char (fn [a] (aget by a)))&lt;/code&gt; and
then on composing &lt;code&gt;char&lt;/code&gt; to it, &lt;code&gt;(fn [b] (char ((fn [a] (aget
by a)) b)))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this case, I used &lt;code&gt;comp&lt;/code&gt; and &lt;code&gt;appl&lt;/code&gt; because I found the
resulting form easier to write and apply.  By contrast, there are
many circumstances where I'd prefer a simple anonymous function.
&lt;a href="#note7"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn8"&gt;&lt;/a&gt;In my defense here, I should point out that I was
reading the &lt;a href="http://yosefk.com/c++fqa/"&gt;C++ Frequently Questioned
Answers&lt;/a&gt; last week, and it may have been
channeling a few bad memories.  &lt;a href="#note8"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a name="fn9"&gt;&lt;/a&gt;To be fair, one of those involved the
aforementioned choice between getting sockets or threads, before
throwing up my hands in dismay.&lt;a href="#note9"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12109108-7720410740161699717?l=wetpixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://wetpixels.blogspot.com/feeds/7720410740161699717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12109108&amp;postID=7720410740161699717' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/7720410740161699717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12109108/posts/default/7720410740161699717'/><link rel='alternate' type='text/html' href='http://wetpixels.blogspot.com/2008/02/my-first-look-at-clojure-preliminaries.html' title='My first look at Clojure'/><author><name>Kearsley</name><uri>http://www.blogger.com/profile/18103859141134061664</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://img.photobucket.com/albums/v205/kearsley/wings.jpg'/></author><thr:total>1</thr:total></entry></feed>
