<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>LShift Ltd.</title>
	<atom:link href="http://www.lshift.net/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://www.lshift.net/blog</link>
	<description>What happens at LShift</description>
	<lastBuildDate>Mon, 14 May 2012 10:01:04 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Visualising your web browsing history</title>
		<link>http://www.lshift.net/blog/2012/05/11/web-browsing-history-vis</link>
		<comments>http://www.lshift.net/blog/2012/05/11/web-browsing-history-vis#comments</comments>
		<pubDate>Fri, 11 May 2012 22:33:35 +0000</pubDate>
		<dc:creator>Tom Parker</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=838</guid>
		<description><![CDATA[I&#8217;ve been doing a bit more data visualisation work, with a focus this time on my
web browsing. If you&#8217;re using Firefox or Chrome (not Opera,
as they don&#8217;t provide this data), then it turns out that your local
history also contains referrer data i.e. you have a history record of not just
where you&#8217;ve been, but how you [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been doing a bit more data visualisation work, with a focus this time on my
web browsing. If you&#8217;re using <a href="http://www.forensicswiki.org/wiki/Mozilla_Firefox_3_History_File_Format">Firefox</a> or <a href="http://computer-forensics.sans.org/blog/2010/01/21/google-chrome-forensics/">Chrome</a> (not Opera,
as they <a href="http://www.forensicswiki.org/wiki/Opera">don&#8217;t provide this data</a>), then it turns out that your local
history also contains referrer data i.e. you have a history record of not just
where you&#8217;ve been, but how you got there&#8230;</p> </p>

<p><p>Why is this interesting? Well, because it shows a slightly different view of the
web. There&#8217;s an awful lot of hyperlinks out there, especially when you get to
heavily interconnected places like Wikipedia, but in a way that&#8217;s far too much
data. Instead, we&#8217;ve got some data that shows how you interacted with the web,
and if we&#8217;ve got a reasonable visualisation tool, then we can learn a few
things.<span id="more-838"></span></p>

<p>Enter the <a href="https://github.com/palfrey/datavis/blob/master/hist-crawl.py">history crawler</a>. Give it one or more history databases
from your browsers (defaults to looking only at the local data, but it can be
handed copies from your other machines as well). It then generates <a href="http://www.graphviz.org/">Graphviz</a>
graphs that show your own personal path through the web, sub-dividing them when
we can&#8217;t find a history record that connects two subgraphs.</p>

<p>(Side note: I ended up having to use dot, fdp <em>and</em> neato. Dot gave the most
useful input, but was most likely to crash repeatedly when I handed it something
complex, and fdp and neato made reasonable backup options when that failed so we
at least get something out)</p>

<p>So, let&#8217;s now have a look at some of the results of this.<br />
<a href="http://www.lshift.net/blog/wp-content/uploads/2012/05/en_wikipedia_org_wiki_8_track_tape.png"><img src="http://www.lshift.net/blog/wp-content/uploads/2012/05/en_wikipedia_org_wiki_8_track_tape.png" alt="" title="en_wikipedia_org_wiki_8_track_tape" width="653" height="488" class="alignnone size-full wp-image-840" /></a><br />
This shows me looking for information on the height of a cassette tape (for reasons that may become clear in a later blog post if a certain item eventually turns up&#8230;). It starts with a google search for &#8220;height of cassette&#8221; and then I clicked on the result for the Wikipedia page for &#8220;Compact Cassette&#8221;, and then read a bunch of related Wikipedia pages. A couple of items are of note: firstly, the boxes marked &#8220;www.google.co.uk&#8221; and &#8220;en.wikipedia.org/wiki&#8221; &#8211; these enclose a collection of links with a common prefix, which reduces the amount of extra text needed on screen, and helps to group links. Also, for Wikipedia, and various other similar sites, it happens to give nice labels for pages! For the most part, these nice labels just fall out of the URL parsing, but there&#8217;s a couple of special cases for Google URLs as Google searches were common items in my history and the search terms get buried a bit in the rest of the URL. Overall, it&#8217;s a pretty interesting snapshot of part of my browsing history.</p>

<p>Often the graphs are quite small &#8211; there appears to be more disjointness in a browsing session than you&#8217;d expect, but some are larger<br />
<a href="http://www.lshift.net/blog/wp-content/uploads/2012/05/wh40k_lexicanum_com_wiki_Talos_Pain_Engine__TtZmvTRz1f4.png"><img src="http://www.lshift.net/blog/wp-content/uploads/2012/05/wh40k_lexicanum_com_wiki_Talos_Pain_Engine__TtZmvTRz1f4-300x203.png" alt="" title="wh40k_lexicanum_com_wiki_Talos_Pain_Engine__TtZmvTRz1f4" width="300" height="203" class="alignnone size-medium wp-image-841" /></a><br />
and some get really messy&#8230;<br />
<a href="http://www.lshift.net/blog/wp-content/uploads/2012/05/localhost_8000_search__q_boot.png"><img src="http://www.lshift.net/blog/wp-content/uploads/2012/05/localhost_8000_search__q_boot-300x104.png" alt="" title="localhost_8000_search__q_boot" width="300" height="104" class="alignnone size-medium wp-image-843" /></a></p>

<p>Overall, it was an interesting experiment, and I&#8217;ve certainly got a bit more knowledge about <a href="http://xkcd.com/214/">how long I spend digging around Wikipedia!</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2012/05/11/web-browsing-history-vis/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hylomorphisms through lazy streams</title>
		<link>http://www.lshift.net/blog/2012/04/30/hylomorphisms-through-lazy-streams</link>
		<comments>http://www.lshift.net/blog/2012/04/30/hylomorphisms-through-lazy-streams#comments</comments>
		<pubDate>Mon, 30 Apr 2012 18:28:39 +0000</pubDate>
		<dc:creator>Frank Shearar</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=824</guid>
		<description><![CDATA[A fold is a higher-order function familiar to many programmers. It&#8217;s a function that takes some structure as input, and some function that converts part of that structure into a value. Evaluating the fold then recursively applies the given function to the structure, resulting in some return value. Variants exist which supply an initial &#8220;seed&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p>A <em><a href="http://en.wikipedia.org/wiki/Fold_(higher-order_function)">fold</a></em> is a higher-order function familiar to many programmers. It&#8217;s a function that takes some structure as input, and some function that converts part of that structure into a value. Evaluating the fold then recursively applies the given function to the structure, resulting in some return value. Variants exist which supply an initial &#8220;seed&#8221; value, or just use the first element of the structure as seed. For instance, given a list of numbers

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#(1 2 3 4 5)</div></div>

, and a folding function

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#+</div></div>

,

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#(1 2 3 4 5) inject: 0 into: #+</div></div>

will calculate the sum of the numbers.</p>

<p>Perhaps less well known is the <em><a href="http://en.wikipedia.org/wiki/Unfold_(higher-order_function)">unfold</a></em>, at which we are going to look today.</p>

<p><span id="more-824"></span>
<p>If you read the previous link you&#8217;d see the term &#8220;anamorphism&#8221;, described as the dual or complement or inverse of a &#8220;catamorphism&#8221;. Some folks like to talk fancy, I suppose. Unlike fold, which has a multitude of different non-Greek names (reduce, inject, and so on), I have yet to come across synonyms for unfold.</p></p>

<p></p>So. The name gives a clue: an unfold takes some <em>value</em>, and a function that converts a value of that type into some structure, and then evaluating the unfold recursively, well, unfolds the value into a structure. Ah, and there&#8217;s an important piece missing. With a fold, we recursively apply some function to a structure, and progressively fold it into a simpler/smaller structure, until it disappears and we have some value. There&#8217;s no such intrinsic &#8220;end here&#8221; for an unfold, so if we wish to end up with a finite structure, we need to supply one additional parameter: a predicate that says &#8220;OK, finished.&#8221; In summary, the parts we need to give an unfold are:
<ol>
  <li>A seed value,</li>
  <li>a function expanding a value into some structure,</li>
  <li>a function transforming the seed in some manner,</li>
  <li>a function telling us when we&#8217;re done.</li>
</ol>
</p></p>

<p>Since I&#8217;ve been playing around with Michael Lucas-Smith and Martin Kobetic&#8217;s <a href="http://code.google.com/p/xtreams/">XTreams library</a> on another project (about which I hope to blog in the near future), let&#8217;s use that as a starting point.</p>

<p><p>Verbs in the Smalltalk collection API follow an -ect pattern &#8211; collect, select, reject, inject, detect, etc. &#8211; so let&#8217;s follow in that grand old tradition. Given that we have to supply a next-seed and we&#8217;re-done predicate,</p>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#eject:nextSeed:until:</div></div>

<p>Seems like a good name. Oh, and XTreams uses present participles rather than verbs to emphasise that we&#8217;re working with streams of data, so let&#8217;s use</p>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#ejecting:nextSeed:until:</div></div>

<p>.</p>

<p>Name in hand, let&#8217;s go. First, we need to describe the behaviour we want to see: what should this new-fangled thing actually <em>do</em>?</p>

<pre>    "Turn a number into a (descending) list of numbers."
    self assert: #(3 2 1 0)
        equals: (4
            ejecting: [:n | n - 1] "At each step, return the predecessor of the current seed."
             nextSeed: [:n | n - 1] "Count down"
             until: [:result | result = 0]) rest.
</pre>

<p>What&#8217;s that

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rest</div></div>

? If you recall, the <a href="http://www.lshift.net/blog/2010/11/29/xtreams-framework-for-squeak">last time</a> we looked at Xtreams we saw that

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#injecting:into:</div></div>

returns a stream of values, showing us the interim results of the fold. If we only care about the final fold, we invoke

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#rest</div></div>

, which will run the computation to completion, and give us the final result in the last value of the stream.</p>

<pre>    Object >> ejecting: expansionBlock nextSeed: seedBlock until: predicateBlock
        "Return an XTReadStream that progressively turns self into some
         structure. expansionBlock tells us how to unfold one step, seedBlock
         tells us how to get the next seed value, and predicateBlock returns
         true when the unfolding has finished."
        ^ [:out | | seed |
        seed := self.
        [predicateBlock value: seed] whileFalse:
            [out put: (Expansionblock value: seed).
            seed := seedBlock value: seed]] reading.
</pre>

<p>Note that the above looks just like a normal do-while loop, yet the result is a stream. What gives? XTreams sees that the block takes an argument, and so instantiates an

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">XTBlockClosureGenerateStream</div></div>

. This stream passes itself into the block &#8211; into the

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">out</div></div>

parameter &#8211; and every time you write to it -

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">out put: (Expansionblock value: seed)</div></div>

- it blocks execution of the loop and returns that value.</p>

<p>Unfold in hand, we can now do amazingly useful things like combining an unfold and a fold to transform an integer into its binary representation:</p>

<pre>    (((42
        ejecting: [:n | n // 2]
        nextSeed: [:n | n // 2]
        until: [:n | n < 1])
            collecting: [:n | (n \\ 2) printString])
                injecting: '' into: [:l :r | r , l]) rest. "Note that we PREPEND the bit."
    "=> #('1' '01' '101' '0101' '10101' '010101')"
</pre>

<p>And that, if one wishes to amaze and confound your peers, is what we call a <em>hylomorphism</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2012/04/30/hylomorphisms-through-lazy-streams/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Open-source attribution &amp; contribution</title>
		<link>http://www.lshift.net/blog/2012/04/11/open-source-attribution-and-contribution</link>
		<comments>http://www.lshift.net/blog/2012/04/11/open-source-attribution-and-contribution#comments</comments>
		<pubDate>Wed, 11 Apr 2012 14:55:20 +0000</pubDate>
		<dc:creator>Adam Prescott</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=785</guid>
		<description><![CDATA[It's probably fair to say that a lot of free, open-source projects you can find on the Internet consider the intellectual property aspects of releasing code as an after-thought. There are two issues related to copyright in open-source projects which I think need more attention. One is code made available without an open-source licence, the other is the lack of attribution for contributors.]]></description>
			<content:encoded><![CDATA[<p>There are two things that I keep seeing when I come across open source projects, admittedly mostly on GitHub.
<ol>
    <li>Code which is intended to be open-source but which doesn&#8217;t have any licence on it.</li>
    <li>Attribution and copyright around contributions is lacking.</li>
</ol></p>

<p>These two issues have bothered me with enough frequency lately that maybe it&#8217;s worth explaining in long form. One of them might be seen to be amateur copyright lawyering, at least, although I haven&#8217;t been able to find a definitive answer on the issue of contributions. The attribution part is important, in either case, and it&#8217;s linked to the copyright.</p>

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

<p>There&#8217;s a core fact about copyright which is central to both points: when producing something original which can be copyrighted, then by default you, the author, own the full copyright over that original work, and nobody can legally modify or redistribute it. All rights reserved. <a href="https://en.wikipedia.org/wiki/Berne_convention">The Berne convention</a> makes this international.</p>

<p>This has two consequences. Namely, code needs a licence and contributions should lead to attribution.</p>

<p>The licence is the actual legal weight behind your <em>intent</em> to release code as open source, which probably is your intention if you&#8217;re, say, putting it on GitHub in a public repository.</p>

<p>Without an adequate licence, then, because of the default, technically nobody can use what you&#8217;ve released in the way you probably meant it to be used.</p>

<p>The second consequence is that, if you accept significant contributions from other people, their work can&#8217;t legally be reused. A related aspect of the contribution thing is that, from a moral and ethical standpoint, credit should be given.</p>

<p>If you want your code to be freely modifiable or redistributable, you need to add a licence file that covers your project or your chunk of code, or whatever it is you&#8217;ve produced. If you don&#8217;t, then you&#8217;re leaving a legal obstacle in the way of someone who wants to use your code. They can&#8217;t legally modify and improve it, they can&#8217;t use it in their own projects.</p>

<p>Anyway, the point is, include a licence! Make it clear what your terms of use are, and avoid, from the very start, a situation where someone comes along and forks your project into some derivative work. GitHub, for example, makes it so easy to fork a project that quite quickly a house of cards can start building up with a foundation based on code that didn&#8217;t explicitly grant any right to modification; GitHub doesn&#8217;t concern itself with copyright or licensing of projects — something that <a href="http://zbowling.github.com/blog/2011/11/25/github/">other people have noticed</a> is a <a href="http://mir.aculo.us/2012/04/05/why-id-like-a-license-type-setting-for-github-projects/">slight problem</a>, too.</p>

<p>Whatever you pick, it should be something legal with clear language. Clear language so that it&#8217;s understandable by human beings in a short space of time. Legal language so that it has weight and isn&#8217;t <a href="https://github.com/xdissent/ievms/blob/4076f5f7ab3eeef6ce398ccb4dfb5cdca7222332/README.rst">very vague</a>. It turns out <a href="http://wonko.com/post/jsmin-isnt-welcome-on-google-code">wording is important</a>.</p>

<p>So what about the other side of things? Someone sends you some code they wrote which fixes a ton of bugs and implements a few features you wanted to get around to writing but hadn&#8217;t had a chance to. This is great! Open source software combined with the border-smashing power of the Internet to bring you and someone across the globe together over diffs and code review. Merge right now!</p>

<p>Wait, though. There are two somewhat related things which I think get overlooked too often:</p>

<ol>
    <li>The aforementioned copyright aspects of the author&#8217;s work.</li>
    <li>Attribution.</li>
</ol>

<p>Code someone else wrote and sent to you belongs to the author, <a href="http://answers.onstartups.com/questions/19422/if-im-working-at-a-company-do-they-have-intellectual-property-rights-to-the-st">certain circumstances notwithstanding</a>. Why should you care? Because it carries questions with it. How come it&#8217;s being used in this project? Can someone new to the project make changes to that code freely? If the code was submitted as free software, then, again, why aren&#8217;t they given credit in a copyright notice somewhere, satisfying the licence?</p>

<p>By attribution, I mean that when you go to some projects, you check the software licence being used and, again, the copyright notice says that there&#8217;s only one person involved. But, if you check the number of contributors, there&#8217;s more than one person&#8217;s work. Finding projects like that is really, really easy. What happened to all those people? Why is there only one (or sometimes two) people mentioned? If the code is significant, they should almost certainly get credit. Even if it&#8217;s insignificant and not, in a legal sense, their code, even a <a href="https://en.wikipedia.org/wiki/De_minimis">1-line de minimis contribution</a> which can&#8217;t be legally owned has its value, so I think attribution is a good thing to do regardless of the size of the contribution. Completely separate from any legality, it&#8217;s rewarding to any contributor to get the acknowledgement.</p>

<p>So now the intellectual property side of things.</p>

<p>They wrote that code so by default they own the copyright. Unless they license their contribution, it technically isn&#8217;t allowed to be modified or distributed or any of that good stuff by other people who later make changes to it. But isn&#8217;t this an open source project?</p>

<p>The MIT licence doesn&#8217;t say anything about contributions. The GPL, through its copyleft nature, forces any derivative work (the contribution you&#8217;re merging) to be covered under the same terms as the original. Unless you&#8217;ve got something else in the mix that covers contributions or modifications, the code being sent needs to have some licence covering it.</p>

<p>This isn&#8217;t a new problem, by any means, and there are already <a href="http://producingoss.com/en/copyright-assignment.html">different ways to handle it</a>. Three of them are:</p>

<ol>
    <li>Do nothing and let it be implicit that the contribution is licensed under, well, implicit terms. Rely on the assumption that “it&#8217;s obvious what was intended.”</li>
    <li>Follow a more corporate solution and get a Contributor License Agreement signed by the contributor, or, as a lightweight alternative, just state the terms in the one-off submission. This makes everything explicit.</li>
    <li>Transfer the ownership of the copyright to a specific person or a group or some other entity.</li>
</ol>

<p>If you go for the first solution, it&#8217;s vague, and with a lot of contributors, it means steadily adding more and more code from different people with different levels of understanding about software licences, and different expectations. What does the law even say here? Has it been tackled?</p>

<p>The second solution means having to remember to do this as a contributor, and remembering to check it&#8217;s been done as a project maintainer or developer.</p>

<p>The third is not only paperwork but is probably unpleasant for an open source project; contributors want to keep ownership over their modifications, <a href="http://answers.onstartups.com/questions/19422/if-im-working-at-a-company-do-they-have-intellectual-property-rights-to-the-st">they&#8217;re not employees</a> of the developer.</p>

<p>An alternative fourth option to the above is to make it clear in the description of the project, maybe in the README, how contributions will be treated by default. “Any contributions will be assumed to be under the same terms as this library/application/project.” “Any contributions will be assumed to be licensed under the MIT licence.”</p>

<p>The Apache licence version 2 takes this approach:
<blockquote>Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.</blockquote></p>

<p>Or, in short, “if you send me a patch, it is immediately Apache-licensed unless otherwise stated.”</p>

<p>This almost starts to feel like copyleft, where modifications are forced to have the same strict requirements. But there&#8217;s a difference between hacking on a project as part of a derivative work and submitting contributions back to an upstream project. Copyleft is about what&#8217;s gone out, whereas this is about code coming in.</p>

<p>(Although the licence suggests adding a copyright notice to every file, it doesn&#8217;t strictly require it. Sometimes a file <a href="http://trillian.mit.edu/~jc/humor/ATT_Copyright_true.html">shouldn&#8217;t have a copyright notice</a> asserting ownership over them, because it <a href="https://github.com/linkedin/inject/blob/06d8edafe4febc2108ba4d08de20f5898ff06dd0/examples/deps/math/0.0.1/multiplication.js">doesn&#8217;t make sense</a>.)</p>

<p>So if we take it as given that contributions are now properly licensed, and, say, your MIT-licensed library gets MIT-licensed contributions, there&#8217;s now a community- and legal-focused question of where to make it clear that there&#8217;s more than one person who added code. It should be made clear somewhere because it&#8217;s the polite thing to do, but also because you need to add a copyright notice somewhere covering the contributing authors.</p>

<p>A few options:
<ol>
    <li>Keep a list of all contributors to a file in the file itself.</li>
    <li>List every contributor in the LICENSE file or README, along with the original author.</li>
    <li>Have the LICENSE file or README, in addition to prominent authors, reference a list of people in some CONTRIBUTORS file.</li>
</ol></p>

<p>The first one gives a “permanent” tag on every file, but maybe it&#8217;s too intrusive or too much metawork.</p>

<p>The second one you might not like because it gives equal weight to every single contribution, large and small, whereas one or two people are the main developers. Still, you could be descriptive about it by tweaking the licence text.</p>

<p>The third one seems the cleanest. So, for example, a copyright notice might look like
<blockquote>Copyright © 2012, Adam Prescott and other contributors (see the CONTRIBUTORS file).</blockquote></p>

<p>and the CONTRIBUTORS file can have some broad, plain-english description of who added what, or just simply be a list of people. Since you&#8217;re just referencing a file, CONTRIBUTORS can list those who have contributed code and those who have contributed other ideas.</p>

<p>While it&#8217;s <a href="http://stackoverflow.com/questions/1497756/declaring-copyright-in-a-foss-project-with-major-and-minor-contributors/1498003#1498003">by no means a novel idea</a>, it does allow you to make it very clear that you&#8217;ve received contributions which are okay to modify and reuse, and, secondly, makes it very clear who those people are! Attribution is thus covered. As an extra bonus, if a contributor adds their own name to the CONTRIBUTORS file, then — in combination with some clear, up-front contribution guidelines — that&#8217;s a good, simple indicator that they&#8217;re sending you work under the same terms.</p>

<p>Let&#8217;s summarise.</p>

<p>If you&#8217;re posting code beyond a significant size that you expect people to use, don&#8217;t let it be locked away behind “All Rights Reserved.” Pick a licence for your code so that others can use what you&#8217;ve made without having to come to you for permission. Pick a legally-weighty licence you actually understand.</p>

<p>Take care with contributions, and think about giving credit.</p>

<p>Copyright is pretty much an endlessly deep topic, so there are all sorts of other things to think about. I&#8217;d like to have the answers to some of them. For instance, is it even legally acceptable to just say “contributions will be assumed to be under the MIT licence” unless that&#8217;s expressed in the licence? In the case of GitHub, when someone makes a public fork of a project and makes changes, their changes are immediately viewable and forkable, so if they&#8217;re to be proper about it, should they add themselves to the contributors file before anything is even contributed back upstream?</p>

<p>But that&#8217;s enough words, I think.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2012/04/11/open-source-attribution-and-contribution/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Persuading mercurial-server to work on Windows</title>
		<link>http://www.lshift.net/blog/2012/04/05/persuading-mercurial-server-to-work-on-windows</link>
		<comments>http://www.lshift.net/blog/2012/04/05/persuading-mercurial-server-to-work-on-windows#comments</comments>
		<pubDate>Thu, 05 Apr 2012 21:59:53 +0000</pubDate>
		<dc:creator>Tom Parker</dc:creator>
				<category><![CDATA[mercurial-server]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=771</guid>
		<description><![CDATA[A few years back, needing decent authentication and key management for Mercurial repositories, we wrote mercurial-server. Recently, we were in the position of wanting to use this with one of our clients, but this time it would need to run under Windows. This was a bit of a problem as it was designed for a [...]]]></description>
			<content:encoded><![CDATA[<p>A few years back, needing decent authentication and key management for Mercurial repositories, we wrote <a href="http://www.lshift.net/mercurial-server.html">mercurial-server</a>. Recently, we were in the position of wanting to use this with one of our clients, but this time it would need to run under Windows. This was a bit of a problem as it was designed for a Unix-type environment. On the other hand, it&#8217;s mostly written in Python, and we could use Cygwin, so how bad could it be?</p>

<p>As it turns out, not too awful. I needed to make a few small modifications, and we&#8217;ve now managed to deploy a working mercurial-server under Windows. 
<span id="more-771"></span></p>

<p>Having said that, here&#8217;s a <strong>BIG FAT WARNING</strong>: Windows is <strong><em>not</em></strong> a supported system. We&#8217;ve gotten this guide to work ok on Windows 7 and 2003, but the permissions are still broken in various ways to do with the underlying issues in Windows&#8217; permissions system. Unix-based systems, especially Debian and derivatives are still the main target. This is very much a &#8220;you break it, you keep both pieces&#8221; guide, but patches are welcomed!</p>

<p>Assuming you&#8217;ve made it through that proviso, here&#8217;s how to do it:
<ol>
<li>Checkout a copy of mercurial-server from mercurial (obviously!) with <blockquote>hg clone http://hg.opensource.lshift.net/mercurial-server</blockquote> and checkout the <i>windows</i> branch</li>
<li>Install <a href="http://cygwin.com/">Cygwin</a> using the setup.exe from there. Tested against 1.7.12-1, may work with earlier versions. You&#8217;ll need the base install plus the following additional packages:
<blockquote>
docbook-xsl<br />
libxslt<br />
make<br />
mercurial<br />
openssh<br />
python<br />
</blockquote>
Note that even if you&#8217;ve already got them installed in Windows, Python and Mercurial still need to be installed in Cygwin.</li>
<li>Open a new Cygwin terminal as Adminstrator (under Windows 7, that&#8217;s right click on the &#8220;Cygwin Terminal&#8221; start menu option and pick &#8220;Run as administrator&#8221;)</li>
<li>Run <blockquote>ssh-host-config -y<br />
cygrunsrv -S sshd</blockquote> to get sshd running. We need this because there&#8217;s no proper su in Cygwin (see <a href="http://cygwin.com/faq-nochunks.html#faq.using.su">the Cygwin FAQ</a> for why this is)</li>
<li>Goto the mercurial-server folder and <blockquote>sh windows.sh setup-windows</blockquote>. If you had an external Python installed, this may fail. In which case try <blockquote>unset PYTHONHOME</blockquote> then try again</li>
<li>Run <blockquote>passwd hg</blockquote> and set the password for the hg user (created by setup-windows), then <blockquote>mkpasswd -l > /etc/passwd</blockquote> to add them to the Cygwin password database</li>
<li>Run <blockquote>sh windows.sh inituser-windows</blockquote> to finish setting up the hg user</li>
<li>Following the example from the main mercurial-server documentation (in that your username is <b>jay</b> and your machine is called <b>spoon</b>), but with a few differences for Cygwin, we can now get you initial access. We assume that you&#8217;ve generated a key with <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html">PuTTYgen</a> and then copied the contents of the &#8220;public key&#8221; box into a file called my-key. Run the following, altered as appropriate for your local system:
<blockquote>
mkdir -p /etc/mercurial-server/keys/root/<b>jay</b><br />
cp my-key /etc/mercurial-server/keys/root/<b>jay</b>/<b>spoon</b><br />
chown hg /etc/mercurial-server/keys/root/<b>jay</b>/<b>spoon</b><br />
ssh hg@localhost /usr/local/share/mercurial-server/refresh-auth
</blockquote>
</li>
</ol></p>

<p>The rest of the instructions in the <a href="http://dev.lshift.net/paul/mercurial-server/docbook.html">normal mercurial-server documentation</a> should now work. Note that although it&#8217;s possible to add keys/access info to <i>/etc/mercurial-server</i> it&#8217;s much easier to do things via the hgadmin repository (and can be done from places other than the Cygwin-running server), and doing things via /etc should probably be limited to only if you mess up the setup in hgadmin.</p>

<p>Hope that all worked for you! We&#8217;d love to hear if anyone else ends up using this out in the field, and anything extra you&#8217;ve done to get it working on your particular system.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2012/04/05/persuading-mercurial-server-to-work-on-windows/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Fallacies of Distributed Computing</title>
		<link>http://www.lshift.net/blog/2012/04/02/the-fallacies-of-distributed-computing</link>
		<comments>http://www.lshift.net/blog/2012/04/02/the-fallacies-of-distributed-computing#comments</comments>
		<pubDate>Mon, 02 Apr 2012 11:27:16 +0000</pubDate>
		<dc:creator>Lee Coomber</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=726</guid>
		<description><![CDATA[I recently helped a client take ownership of an application stack produced by a third party. There were various components to this, but the most interesting aspect allowed users to interact with each other by manipulating images in a browser. This was achieved using a small and simple NodeJS application to send events between the [...]]]></description>
			<content:encoded><![CDATA[<p>I recently helped a client take ownership of an application stack produced by a third party. There were various components to this, but the most interesting aspect allowed users to interact with each other by manipulating images in a browser. This was achieved using a small and simple <a title="NodeJS" href="http://nodejs.org/">NodeJS</a> application to send events between the browsers.</p>

<p>We were aware of a few severe problems shortly before our involvement, and during the handover meeting I asked the developer how he had fixed them. He replied that if two or more users tried to manipulate the same object at the same time, it would cause the browser code to crash as multiple conflicting change events would be sent. He therefore added a new event type that was sent out when an action started, e.g., on mouse down. This indicated that all the other browsers should lock their copies of the object in question until the action was finished.</p>

<p>I gently suggested that this might not work well over a network, to which he responded that in testing the lock events took less than 10ms to arrive, so the odds of two people trying to do the same thing within that period were so small as to not be worth worrying about.</p>

<p>Again, I very gently suggested that the benchmark was unlikely to hold across the Internet. He told me that he had tested it on several networks including over the public Internet with someone in the US and it was still good. I gave up at this point, and just noted to the client that this was something that would need attention fairly promptly.</p>

<p>This assertion that there was a latency of 10ms between the UK and the US is clearly false. Even if you could set-up a perfect vacuum between London and New York, it would still take <a title="Wolfram Alpha" href="http://www.wolframalpha.com/input/?i=London+to+New+York+at+speed+of+light+in+a+vacuum">19ms for light to travel that distance</a>. However, the numbers are irrelevant &#8211; there is latency and it must be considered when trying to build a reliable distributed system regardless of magnitude. This and seven other issues were famously covered in the &#8220;Eight Fallacies of Distributed Computing&#8221;, assembled by Peter Deutsch, James Gosling and others.</p>

<p>Anyone building a distributed application should have these fallacies in mind, and <a title="Fallacies of Distributed Computing Explained" href="http://www.rgoarchitects.com/Files/fallacies.pdf">this paper</a> has a good explanation of them with a very readable commentary. NodeJS made this shared browser experience extremely effective and enticingly simple to construct, but even NodeJS apps are not isolated from the effects of the infrastructure they utilise. In fact, until TCP over <a href="http://www.physorg.com/news193551675.html">entangled photon pairs</a> hits the shelves, these fallacies will be relevant regardless of your framework.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2012/04/02/the-fallacies-of-distributed-computing/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>M&#246;bius Transformations in a Tangle</title>
		<link>http://www.lshift.net/blog/2012/03/31/mbius-transformations-in-a-tangle</link>
		<comments>http://www.lshift.net/blog/2012/03/31/mbius-transformations-in-a-tangle#comments</comments>
		<pubDate>Sat, 31 Mar 2012 22:23:06 +0000</pubDate>
		<dc:creator>Frank Shearar</dc:creator>
				<category><![CDATA[Reviews]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=742</guid>
		<description><![CDATA[We saw in a previous post a kind of transformation of complex values, a M&#246;bius transformation. It turns out that we can decompose any M&#246;bius transformation into a series of four separate transformations &#8211; a translation, an inversion, a dilation/rotation, and a final transformation. From a UX perspective, we saw that using input fields and [...]]]></description>
			<content:encoded><![CDATA[<p>We saw in a previous post a kind of transformation of complex values, a M&ouml;bius transformation. It turns out that we can decompose any M&ouml;bius transformation into a series of four separate transformations &#8211; a translation, an inversion, a dilation/rotation, and a final transformation. From a UX perspective, we saw that using input fields and a button to modify the transformation was not slick. Today we&#8217;re going to make things more slick.</p>

<p><span id="more-742"></span>
<p>The blogosphere/twitspace is all abuzz over Bret Victor&#8217;s recent demonstration <a href="http://vimeo.com/36579366">Inventing on Principle</a>. I&#8217;d come across Bret&#8217;s work through his <a href="http://worrydream.com/LadderOfAbstraction/">Up and Down the Ladder of Abstraction</a> active essay. (Bret calls these things &#8220;reactive documents&#8221;. The concept&#8217;s a lot older, of course, and Alan Kay would call these active essays. Given my personal history, I&#8217;ll also call them &#8220;active essays&#8221;.) One of the tricks that makes Ladders of Abstraction so engaging is the ability to, in real time, tweak the model under examination. I won&#8217;t pretend to have the taste that Bret shows, and will restrict myself to one tiny piece of the UX puzzle &#8211; <a href="http://worrydream.com/Tangle/reference.html">TangleKit</a>.</p></p>

<p>TangleKit exists for a single purpose: to allow the simple manipulation of one-dimensional input variables, and the chance to perform arbitrary calculations when those inputs change. The setup is simple: you have a

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">div</div></div>

within which your &#8220;active variables&#8221; (for want of a better term) are tangled together; you have some initialization function; you have some update function.</p>

<p><p>We have six variables in this demo, so let&#8217;s just confine ourselves to the real component of the first translation. The HTML looks like this:</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &lt;div id=&quot;moebius&quot;&gt;<br />
&nbsp; &nbsp; &lt;span data-var=&quot;f1_r&quot; class=&quot;TKAdjustableNumber&quot; data-min=&quot;-2&quot; data-max=&quot;2&quot; data-step=&quot;0.0625&quot;&gt;&lt;/span&gt;<br />
&nbsp; &lt;/div&gt;</div></div>

</pre>

<p>declaring the variable, its range and its resolution. The corresponding Tangle is then</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; function setUpTangle() {<br />
&nbsp; &nbsp; var element = document.getElementById(&quot;moebius&quot;);<br />
<br />
&nbsp; &nbsp; var tangle = new Tangle(element, {<br />
&nbsp; &nbsp; &nbsp; initialize: function () {<br />
&nbsp; &nbsp; &nbsp; &nbsp; this.f1_r = 0;<br />
&nbsp; &nbsp; &nbsp; &nbsp; // Set up the other variables here in a similar fashion.<br />
&nbsp; &nbsp; &nbsp; },<br />
&nbsp; &nbsp; &nbsp; update: function () {<br />
&nbsp; &nbsp; &nbsp; &nbsp; // this.f1_i and friends are set up just like f1_r<br />
&nbsp; &nbsp; &nbsp; &nbsp; var f1c = complex(this.f1_r, this.f1_i);<br />
&nbsp; &nbsp; &nbsp; &nbsp; var f3c = complex(this.f3_r, this.f3_i);<br />
&nbsp; &nbsp; &nbsp; &nbsp; var f4c = complex(this.f4_r, this.f4_i);<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; // Do anything else we might want to do<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; // Now that this.a_r is declared and initialised we can<br />
&nbsp; &nbsp; &nbsp; &nbsp; // now refer to a variable &quot;a_r&quot; within the HTML. this.a_r<br />
&nbsp; &nbsp; &nbsp; &nbsp; // represents the real component of the numerator's<br />
&nbsp; &nbsp; &nbsp; &nbsp; // z co-efficient:<br />
&nbsp; &nbsp; &nbsp; &nbsp; this.a_r = f4c[0];<br />
&nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; });<br />
&nbsp; };</div></div>

</pre>

<p>We can now render our mutated &#8220;output&#8221; variables thusly:

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;span data-var=&quot;a_r&quot;&gt;&lt;/span&gt;</div></div>

</p>

<p>Finally, let&#8217;s play!</p>

<p><iframe src="http://frankshearar.github.com/terrapin/layered-moebius.html" width="500" height="550"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2012/03/31/mbius-transformations-in-a-tangle/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NAntScript, now with added functions</title>
		<link>http://www.lshift.net/blog/2012/03/27/nantscript-now-with-added-functions</link>
		<comments>http://www.lshift.net/blog/2012/03/27/nantscript-now-with-added-functions#comments</comments>
		<pubDate>Tue, 27 Mar 2012 23:02:12 +0000</pubDate>
		<dc:creator>Tom Parker</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=730</guid>
		<description><![CDATA[When we&#8217;re doing C# work, we&#8217;re fairly big fans of NAnt, as it&#8217;s a very good build system for .Net. However, it&#8217;s got a few small flaws, the main one of which is that you often end up repeating yourself a fair few times, and applying any sort of DRY thinking in it is quite [...]]]></description>
			<content:encoded><![CDATA[<p>When we&#8217;re doing C# work, we&#8217;re fairly big fans of <a href="http://nant.sourceforge.net/">NAnt</a>, as it&#8217;s a very good build system for .Net. However, it&#8217;s got a few small flaws, the main one of which is that you often end up repeating yourself a fair few times, and applying any sort of <a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself">DRY</a> thinking in it is quite hard.</p>

<p>Enter <a href="https://github.com/palfrey/NAntScript">NAntScript</a>. Originally from some folks <a href="http://code.google.com/p/nantscript/">elsewhere</a>, but languishing and somewhat abandoned and in need of some work. The core idea being that you can write new tasks for NAnt using existing tasks (it is in fact <a href="http://nant.sourceforge.net/release/0.91/help/tasks/script.html">also possible</a> to write new NAnt tasks using C# or various other languages, but that&#8217;s a pretty messy way to work)
<span id="more-730"></span>
<script src="https://gist.github.com/2221058.js?file=gistfile1.xml"></script></p>

<p>This enables you to write common sets of tasks e.g. a copy with a filter for templating, as a new task which can then be repatedly reused.</p>

<p>However, NAntScript had a few little flaws. It didn&#8217;t work on modern NAnt instances (luckily a small fix), there wasn&#8217;t any online documentation for it (<a href="http://palfrey.github.com/NAntScript/api/index.html">also now fixed</a>), and you couldn&#8217;t write functions with it, and that last one is the really fun new one I&#8217;ve added.</p>

<p>In the same way as the earlier <a href="http://palfrey.github.com/NAntScript/api/tasks/taskdef.html"><i>taskdef</i></a> let you create a custom task, <a href="http://palfrey.github.com/NAntScript/api/tasks/funcdef.html"><i>funcdef</i></a> lets you make a custom function. Functions are a bit different, in that they&#8217;ve got properly typed inputs and outputs, and that you&#8217;ve got to figure out a way how to get a value out without breaking NAnt syntax too badly, but that&#8217;s solvable in a similar way to how variables work in <i>func/taskdef</i>&#8217;s. Variables are defined as being called some &#8220;foo&#8221; and then they are inserted any time you enter the magic text &#8220;&#95;&#95;foo&#95;&#95;&#8221;, and the return works in a similar way, defining a magic return variable called &#8220;&#95;&#95;$return&#95;&#95;&#8221; which must be set at some point during the internals of a function. Here&#8217;s an example of that.
<script src="https://gist.github.com/2221164.js?file=gistfile1.xml"></script>
Source as usual is <a href="https://github.com/palfrey/NAntScript">on github</a>, and I&#8217;ve even added some <a href="https://github.com/palfrey/NAntScript/downloads">precompiled binaries</a> for download.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2012/03/27/nantscript-now-with-added-functions/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>D3 glasses and the Complex Plane</title>
		<link>http://www.lshift.net/blog/2012/03/12/d3-glasses-and-the-complex-plane-2</link>
		<comments>http://www.lshift.net/blog/2012/03/12/d3-glasses-and-the-complex-plane-2#comments</comments>
		<pubDate>Mon, 12 Mar 2012 22:49:38 +0000</pubDate>
		<dc:creator>Frank Shearar</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=665</guid>
		<description><![CDATA[One of the best ways to develop intuition in mathematics is to look at pictures. We often use graphs &#8211; visual representations of functions &#8211; showing the relationship between the domain of a function and the range of a function. With real-valued functions of one variable this is easy: the graph is nice and flat. [...]]]></description>
			<content:encoded><![CDATA[<p>One of the best ways to develop intuition in mathematics is to look at pictures. We often use graphs &#8211; visual representations of functions &#8211; showing the relationship between the domain of a function and the range of a function. With real-valued functions of one variable this is easy: the graph is nice and flat. What about complex-valued functions? What kind of pictures would help?</p>

<p><span id="more-665"></span>
<p>Recall that a complex number may be represented by a pair of real numbers. As such, representing a set of complex numbers &#8211; a region &#8211; is straightforward: an <a href="http://en.wikipedia.org/wiki/Complex_plane">Argand diagram</a> does the job just great. (Think of a Cartesian plane, and label the x-axis &#8220;real&#8221; and the y-axis &#8220;imaginary&#8221;.) Usually we just call this the z-plane, and the plane to which we map &#8211; the range &#8211; we call the w-plane.</p></p>

<p>What about a <em>function</em> though? The obvious visualisation is a bit hard: since visually representing a complex number requires two numbers, we&#8217;d need to use four dimensions to visual a complex function of one variable. Sadly, I left my 4-dimensional graph paper in my other bag.</p>

<p>Several other possibilities spring to mind: split the mapped values into their real and imaginary components and draw each separately. Since we now only have three dimensions left (the domain&#8217;s two, and one for the range), things are a bit easier. Typically we map the third dimension to a colour, giving something like a contour map. MathWorld is filled with examples.</p>

<p>It&#8217;s also easy to show how the shape of some region changes. Define a region in the z-plane &#8211; a disk, say &#8211; and draw in the w-plane the boundary of the region. And we can take it a step further: we can draw the mutations of a <em>grid of lines</em>. Right, enough maths. Let&#8217;s draw!</p>

<iframe src="http://frankshearar.github.com/moebius.html" width="650" height="555"></iframe>

<p>The basic idea in d3 is simple: you have some data in an array, you have a selection of nodes in an array, and you want to map the one onto the other. Today, we&#8217;re going to use SVG

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">path</div></div>

elements &#8211; polylines &#8211; to keep things nice and simple. It has a nice jQuery-like API permitting concise descriptions of things we want to add to the DOM. First, our play area:</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; d3.select(&quot;#z-plane&quot;).append(&quot;svg&quot;)<br />
&nbsp; &nbsp; .attr(&quot;height&quot;, 300)<br />
&nbsp; &nbsp; .attr(&quot;width&quot;, 300)<br />
&nbsp; &nbsp; .append(&quot;g&quot;)<br />
&nbsp; &nbsp; .attr(&quot;fill&quot;, &quot;none&quot;)<br />
&nbsp; &nbsp; .attr(&quot;stroke-width&quot;, 2)<br />
&nbsp; &nbsp; .attr(&quot;stroke&quot;, &quot;black&quot;);</div></div>

</pre>

<p>Next, let&#8217;s make some data. We want some lines forming a grid, and those lines will be polylines with a large number of points on the lines. (<em>Pretty</em> pictures need lots of points for nice smooth curves.)</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; function hlines(gridResolution, pointResolution) {<br />
&nbsp; return gridResolution.map(function(i) {<br />
&nbsp; &nbsp; &nbsp; return pointResolution.map(function(j) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; return complex(j, i);<br />
&nbsp; &nbsp; &nbsp; });<br />
&nbsp; &nbsp; });<br />
&nbsp; }<br />
&nbsp; <br />
&nbsp; function vlines(gridResolution, pointResolution) {<br />
&nbsp; &nbsp; return gridResolution.map(function(i) {<br />
&nbsp; &nbsp; &nbsp; return pointResolution.map(function(j) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; return complex(i, j);<br />
&nbsp; &nbsp; &nbsp; });<br />
&nbsp; &nbsp; });<br />
&nbsp; }<br />
&nbsp; <br />
&nbsp; function makeGrid(gridResolution, pointResolution) {<br />
&nbsp; &nbsp; return hlines(gridResolution, pointResolution)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.concat(vlines(gridResolution, pointResolution));<br />
&nbsp; }<br />
&nbsp; <br />
&nbsp; var min_x = -2.5, max_x = 2.5;<br />
&nbsp; var interline_distance = 0.2;<br />
&nbsp; var interpoint_distance = 0.05;<br />
&nbsp; var grid = d3.range(min_x, max_x + (interline_distance / 2), interline_distance);<br />
&nbsp; var pointsOnLine = d3.range(min_x, max_x + (interpoint_distance / 2), interpoint_distance);<br />
<br />
&nbsp; var zlines = makeGrid(grid, pointsOnLine);<br />
&nbsp; var wlines = makeGrid(grid, pointsOnLine);</div></div>

</pre>

<p>We map the data onto the SVG elements. Now we don&#8217;t have any SVG elements at the moment. That&#8217;s OK. Thanks to

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">enter()</div></div>

, we can create any missing

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">path</div></div>

elements, one per item in our data in the

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">arr</div></div>

array, after we&#8217;ve bound our data to the selection of nodes.</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; function makeLines(planeDiv, arr) {<br />
&nbsp; &nbsp; planeDiv.selectAll(&quot;.line&quot;)<br />
&nbsp; &nbsp; &nbsp; .data(arr) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Bind to all the line class elements<br />
&nbsp; &nbsp; &nbsp; .enter().append(&quot;path&quot;) &nbsp;// and add path.line element as necessary<br />
&nbsp; &nbsp; &nbsp; &nbsp; .attr(&quot;class&quot;, &quot;line&quot;)<br />
&nbsp; &nbsp; &nbsp; &nbsp; .attr(&quot;d&quot;, lineMaker);<br />
&nbsp; }</div></div>

</pre>

<p>But how do we actually display the data? d3&#8217;s scales map our domains &#8211; two continuous ranges of values from -2 to 2 &#8211; to our ranges &#8211; 300 pixel long sides:</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; var x = d3.scale.linear()<br />
&nbsp; &nbsp; .domain([min_x, max_x])<br />
&nbsp; &nbsp; .range([0, h]);<br />
&nbsp; var y = d3.scale.linear()<br />
&nbsp; &nbsp; .domain([min_x, max_x])<br />
&nbsp; &nbsp; .range([h, 0]); // Invert the scale so the origin is in the BOTTOM left corner<br />
&nbsp; var lineMaker = d3.svg.line()<br />
&nbsp; &nbsp; &nbsp; .x(function(d) { return x(d[0]); }) &nbsp;// How we get the x-coord<br />
&nbsp; &nbsp; &nbsp; .y(function(d) { return y(d[1]); }); // How we get the y-coord</div></div>

</pre>

<p>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">lineMaker</div></div>

is a convenience factory for making the polylines. The

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">x</div></div>

and

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">y</div></div>

functions define how to calculate the <em>mapped</em> data: given a complex number

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">d</div></div>

we map the real portion of that number onto the horizontal position of a polyline point, and similarly for the imaginary portion of that number. Note the y scale&#8217;s range: inverted to show the mathematically proper position of the origin instead of SVG&#8217;s standard (top left).</p>

<p>When we press the &#8220;Go&#8221; button, we fire off a click event:</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; d3.select(&quot;#go-button&quot;).on(&quot;click&quot;, function() {<br />
&nbsp; &nbsp; // Recreate our Moebius transformation<br />
&nbsp; &nbsp; f = memoiseF();<br />
&nbsp; <br />
&nbsp; &nbsp; // And warn if our (yes, global) variables indicate that we do not, in<br />
&nbsp; &nbsp; // fact, have a Moebius transformation.<br />
&nbsp; &nbsp; if (czero(csub(cmult(a, d), cmult(b, c)))) {<br />
&nbsp; &nbsp; &nbsp; alert(&quot;Not a Moebius transform!\nMerely a constant function f(z) = &quot; + JSON.stringify(f(complex(1, 0))));<br />
&nbsp; &nbsp; }<br />
&nbsp; <br />
&nbsp; &nbsp; // Mutate the w-plane data in place so d3 can automatically<br />
&nbsp; &nbsp; // pick up the changes.<br />
&nbsp; &nbsp; var lastw = [0,0];<br />
&nbsp; &nbsp; for (var lineI = 0; lineI &lt; wlines.length; lineI++) {<br />
&nbsp; &nbsp; &nbsp; for (var pointI = 0; pointI &lt; wlines[lineI].length; pointI++) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; w = f(zlines[lineI][pointI]);<br />
&nbsp; &nbsp; &nbsp; &nbsp; if (w == Inf) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If f(z) = Inf then we pretend that Inf is really a point<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // outside of visual range that's on the ray drawn from<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // the origin through lastw. Think of the resulting point<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // as being the closest point to lastw on a circle centred<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // on the origin and of infinite radius.<br />
&nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Multiplying by n + 0i (n a real) means scaling without<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // rotating.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; w = cmult(lastw, complex(100, 0));<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; wlines[lineI][pointI] = w;<br />
&nbsp; &nbsp; &nbsp; &nbsp; lastw = w;<br />
&nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; drawLines(wplane, wlines);<br />
&nbsp; });</div></div>

</pre>

<p>And lastly, refreshing our view is trivial:</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; function drawLines(planeDiv, arr) {<br />
&nbsp; &nbsp; planeDiv.selectAll(&quot;.line&quot;)<br />
&nbsp; &nbsp; &nbsp; .transition() &nbsp; // Change the view of the data ...<br />
&nbsp; &nbsp; &nbsp; .ease(&quot;linear&quot;) // ... and make it nice and smooth.<br />
&nbsp; &nbsp; &nbsp; .attr(&quot;d&quot;, lineMaker);<br />
&nbsp; }</div></div>

</pre>

<p>In short, d3 is a neat, powerful tool for visualising data. It&#8217;s highly extensible, well-supported, and can do pretty much anything you might want to out of the box, from <a href="http://mbostock.github.com/d3/ex/bullet.html">bullet charts</a> to <a href="http://mbostock.github.com/d3/ex/voronoi.html">Voronoi diagrams</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2012/03/12/d3-glasses-and-the-complex-plane-2/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Making panel applets for Gnome 2 and 3</title>
		<link>http://www.lshift.net/blog/2012/02/29/making-panel-applets-for-gnome-2-and-3</link>
		<comments>http://www.lshift.net/blog/2012/02/29/making-panel-applets-for-gnome-2-and-3#comments</comments>
		<pubDate>Wed, 29 Feb 2012 00:31:45 +0000</pubDate>
		<dc:creator>Tom Parker</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=657</guid>
		<description><![CDATA[In recent times, there&#8217;s been a lot of changes to the Gnome environment with the 3.x releases, including the introduction of the Gnome Shell and things like the GObject introspection stuff going on in the background. However, the Shell is a bit on the unstable side (even if you&#8217;ve got a good graphics card), and [...]]]></description>
			<content:encoded><![CDATA[<p>In recent times, there&#8217;s been a lot of changes to the Gnome environment with the 3.x releases, including the introduction of the Gnome Shell and things like the GObject introspection stuff going on in the background. However, the Shell is a bit on the unstable side (even if you&#8217;ve got a good graphics card), and so I&#8217;ve been sticking with the &#8220;fallback&#8221; environment which still uses the standard panel layout.</p>

<p>Well, that&#8217;s what it looks like at first glance. Once you start digging around, it turns out that the panel you&#8217;re now seeing is superficially similar to the old one, but it&#8217;s built in a very different way under the hood, and that makes writing applets for it a somewhat different problem. Primary among the changes for the panel is the removal of <a href="http://live.gnome.org/Bonobo">Bonobo</a> in favour of <a href="http://www.freedesktop.org/wiki/Software/dbus">D-Bus</a>, so we&#8217;re going to have to build the services needed for applets in a new way.
<span id="more-657"></span></p>

<p>Now, if you start looking around the web for guides to making Gnome panel applets, you&#8217;ll find two things. a) lots of guides of how to do this in a 2.x environment (e.g. <a href="http://www.pygtk.org/articles/applets_arturogf/">this</a>) but little/no 3.x guides, because of b) that applets are officially deprecated as of 3.x (that, and 2.x has been out since 2002 v.s. 2011 for the 3.0 release). The reason they&#8217;re officially deprecated is that we&#8217;re all meant to be using the Shell now, which is a very different thing, and so needs to do things in a completely different way. However, I (and I suspect a fair chunk of the world) will be sticking with non-Shell environments for a while yet, so there&#8217;s still a need for 3.x panel applets.</p>

<p>Earlier on I noted how the 2.x and 3.x panels were very different things, but despite the major interface changes, your core applet is still going to be the same. In both cases, some form of messaging bus (Bonobo, D-Bus) provides information about what applets are available, and then invokes the launchers for them on demand. For either 2.x or 3.x you&#8217;re going to be writing a whole bunch of messaging system boilerplate, when what you really want to be doing is actually writing your own applet!</p>

<p>I&#8217;ve therefore written a <a href="https://github.com/palfrey/panel-applet-generator">little boilerplate generator</a> that makes applets that work on both 2.x and 3.x panels. Using <a href="http://genshi.edgewall.org/">Genshi</a>, it generates the Bonobo server files, D-Bus service files, a pair of factory helpers that build either a 2.x or 3.x applet, and then a simple applet stub that you can expand that looks like the following:
<script src="https://gist.github.com/1935898.js"></script></p>

<p>It&#8217;ll also generate a bunch of Debian package files so you can package up your applet right away. It&#8217;ll work straight out of the box, with a little label saying &#8220;It works!&#8221;, but you can then customise just the applet stub file and it&#8217;ll happily continue to work with both 2.x and 3.x. One potential issue is making sure that you&#8217;re importing from gi.repository for 3.x and then falling back to the relevant individual modules for 2.x as shown at the top of the applet stub, but otherwise it should be fairly simple to build your applet of choice.</p>

<p>As the interface files need to be hardcoded to a particular path for the applet, the best option for further development is to install the generated package, then make the main applet (/usr/lib/gnome-applets/&lt;applet-name&gt;Applet.py) a symlink to a version of the file that you can edit. If you then add the applet to your panel, the python process for the factory (called &lt;applet-name&gt;-factory{2,3}.py depending on your panel version) can be killed every time you want to refresh the code (don&#8217;t forget to answer yes when the panel asks if you want to reload the applet that just died!). Unfortunately given the process model for panel applets, there aren&#8217;t any easier ways to do development, but this works fairly well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2012/02/29/making-panel-applets-for-gnome-2-and-3/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Transforming Ruby DSLs</title>
		<link>http://www.lshift.net/blog/2012/02/27/transforming-ruby-dsls</link>
		<comments>http://www.lshift.net/blog/2012/02/27/transforming-ruby-dsls#comments</comments>
		<pubDate>Mon, 27 Feb 2012 22:15:15 +0000</pubDate>
		<dc:creator>Frank Shearar</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.lshift.net/blog/?p=656</guid>
		<description><![CDATA[Ruby excels at &#8220;embedded&#8221; DSLs &#8211; domain specific languages that are simultaneously plain Ruby and yet distinctly their own. RSpec springs to mind as an excellent example. At any rate, I have a DSL that recently underwent a fairly invasive change, and I wanted to automate moving model descriptions from the old format to the [...]]]></description>
			<content:encoded><![CDATA[<p>Ruby excels at &#8220;embedded&#8221; DSLs &#8211; domain specific languages that are simultaneously plain Ruby and yet distinctly their own. <a href="http://rspec.info/">RSpec</a> springs to mind as an excellent example. At any rate, I have a DSL that recently underwent a fairly invasive change, and I wanted to automate moving model descriptions from the old format to the new.</p>

<p><span id="more-656"></span>
<p>The DSL describes domain objects in a language-agnostic fashion. For example:</p></p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; in_namespace('Outer') {<br />
&nbsp; &nbsp; in_namespace('Inner') {<br />
&nbsp; &nbsp; &nbsp; define('An Inner Object') {<br />
&nbsp; &nbsp; &nbsp; &nbsp; field 'name', :string<br />
&nbsp; &nbsp; &nbsp; &nbsp; field 'value', :integer<br />
&nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; define('An Outer Object') {<br />
&nbsp; &nbsp; &nbsp; field 'name', :string<br />
&nbsp; &nbsp; &nbsp; field 'wrapping', 'Inner.An Inner Object'<br />
&nbsp; &nbsp; }<br />
&nbsp; }</div></div>

</pre>

<p>defines a pair of objects, one designed to wrap around the other. Using this language, one can generate data objects in some language of your choice: Smalltalk, perhaps, or Haskell.</p>

<p>The DSL has one extra bit: because the language describes a wire contract between two services, it&#8217;s sensible to version the entities, so that one can quickly see that two services have gotten out of sync: one or the other needs upgrading, for instance. So our domain model might look like this:</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; in_namespace('Outer', :version =&gt; &quot;1.0&quot;) {<br />
&nbsp; &nbsp; in_namespace('Inner') {<br />
&nbsp; &nbsp; &nbsp; define('An Inner Object') {<br />
&nbsp; &nbsp; &nbsp; &nbsp; field 'name', :string<br />
&nbsp; &nbsp; &nbsp; &nbsp; field 'value', :integer<br />
&nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; define('An Outer Object', :version =&gt; &quot;2.0&quot;) {<br />
&nbsp; &nbsp; &nbsp; field 'name', :string<br />
&nbsp; &nbsp; &nbsp; field 'wrapping', 'Inner.An Inner Object'<br />
&nbsp; &nbsp; }<br />
&nbsp; }</div></div>

</pre>

<p>This works pretty well: the wrapping object has version &#8220;2.0&#8243; while the wrapped object inherits its version &#8211; &#8220;1.0&#8243; &#8211; from its namespace. Imagine that you have some namespace with a large number of entities. It&#8217;s very easy to accidentally upgrade <em>all</em> objects in a namespace when you only meant to upgrade <em>some</em>. So the per-namespace versioning needed to disappear, forcing the user to explicitly express all versions on a per-definition basis. Clearly, in a large model, that would be an onerous task. However, this <em>is</em> still plain Ruby, and there just happens to be a <a href="https://github.com/seattlerb/parsetree">Ruby->AST translator lying around</a>, so it makes sense to manipulate the AST directly, and not mess around with crazy nonsense like trying to use regular expressions or similar. And given that I just happen to have a <a href="https://github.com/frankshearar/zipr">Ruby zipper library</a> capable of traversing arbitrary hierarchical structures, a plan forms&#8230;</p>

<p>Getting the AST is simplicity itself:</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; require 'rubygems'<br />
&nbsp; require 'sexp'<br />
&nbsp; require 'parse_tree'<br />
&nbsp; require 'zipr/zipper'<br />
<br />
<br />
&nbsp; filename = &quot;my-model.rb&quot;<br />
&nbsp; file = File.read(filename)<br />
&nbsp; sexp = Sexp.from_array(ParseTree.new(false).parse_tree_for_string(file, filename).first)<br />
&nbsp; # I use ParseTree here, but really you want to use ruby_parser:<br />
&nbsp; # it works in Ruby 1.9, for starters.</div></div>

</pre>

<p>which gives us a lovely S-expression:</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; s(:iter,<br />
&nbsp; &nbsp;s(:fcall,<br />
&nbsp; &nbsp; :in_namespace,<br />
&nbsp; &nbsp; s(:array, s(:str, &quot;Outer&quot;), s(:hash, s(:lit, :version), s(:str, &quot;1.0&quot;)))),<br />
&nbsp; &nbsp;nil,<br />
&nbsp; &nbsp;s(:block,<br />
&nbsp; &nbsp; s(:iter,<br />
&nbsp; &nbsp; &nbsp;s(:fcall, :in_namespace, s(:array, s(:str, &quot;Inner&quot;))),<br />
&nbsp; &nbsp; &nbsp;nil,<br />
&nbsp; &nbsp; &nbsp;s(:iter,<br />
&nbsp; &nbsp; &nbsp; s(:fcall, :define, s(:array, s(:str, &quot;An Inner Object&quot;))),<br />
&nbsp; &nbsp; &nbsp; nil,<br />
&nbsp; &nbsp; &nbsp; s(:block,<br />
&nbsp; &nbsp; &nbsp; &nbsp;s(:fcall, :field, s(:array, s(:str, &quot;name&quot;), s(:lit, :string))),<br />
&nbsp; &nbsp; &nbsp; &nbsp;s(:fcall, :field, s(:array, s(:str, &quot;value&quot;), s(:lit, :integer)))))),<br />
&nbsp; &nbsp; s(:iter,<br />
&nbsp; &nbsp; &nbsp;s(:fcall,<br />
&nbsp; &nbsp; &nbsp; :define,<br />
&nbsp; &nbsp; &nbsp; s(:array,<br />
&nbsp; &nbsp; &nbsp; &nbsp;s(:str, &quot;An Outer Object&quot;),<br />
&nbsp; &nbsp; &nbsp; &nbsp;s(:hash, s(:lit, :version), s(:str, &quot;2.0&quot;)))),<br />
&nbsp; &nbsp; &nbsp;nil,<br />
&nbsp; &nbsp; &nbsp;s(:block,<br />
&nbsp; &nbsp; &nbsp; s(:fcall, :field, s(:array, s(:str, &quot;name&quot;), s(:lit, :string))),<br />
&nbsp; &nbsp; &nbsp; s(:fcall,<br />
&nbsp; &nbsp; &nbsp; &nbsp;:field,<br />
&nbsp; &nbsp; &nbsp; &nbsp;s(:array, s(:str, &quot;wrapping&quot;), s(:str, &quot;Inner.An Inner Object&quot;)))))))</div></div>

</pre>

<p>All that remains is (a) transforming the AST and (b) writing the AST out again as Ruby source. The latter&#8217;s pretty boring, so let&#8217;s just stick with the former. We need to do two things: select certain nodes, and transform them. So given some helper methods added to

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Sexpr</div></div>

and

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Enumerable</div></div>

, we need just say</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; class Zipr::Zipper<br />
&nbsp; &nbsp; def version_all_objects(default_version)<br />
&nbsp; &nbsp; &nbsp; current_version = default_version<br />
<br />
&nbsp; &nbsp; &nbsp; # Recall that Zipper's map returns a structure of the same<br />
&nbsp; &nbsp; &nbsp; # shape as that over which we iterate (as opposed to<br />
&nbsp; &nbsp; &nbsp; # Enumerable's map, which returns a list of mapped things).<br />
&nbsp; &nbsp; &nbsp; map {|n|<br />
&nbsp; &nbsp; &nbsp; &nbsp; if n.kind_of?(Enumerable) then<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (n.first == :fcall) and (n[1] == :in_namespace)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Possibly change current_version here<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Remove the per-namespace version, if present<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (n.has_version) then<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; current_version = n.version_from_ns<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; next n.strip_version_from_ns<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; elsif (n.first == :fcall) and (n[1] == :define)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Inject the version, if there isn't one already<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (not n.has_version) then<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; next n.add_version_to_object(current_version)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end<br />
&nbsp; &nbsp; &nbsp; &nbsp; end<br />
&nbsp; &nbsp; &nbsp; &nbsp; n<br />
&nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; end<br />
&nbsp; <br />
&nbsp; &nbsp; puts SexpWriter.new.visit(version_all_objects(z).root)</div></div>

</pre>

<p>which yields the desired, altered, model definition:</p>

<pre>

<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; in_namespace('Outer') {<br />
&nbsp; &nbsp; in_namespace('Inner') {<br />
&nbsp; &nbsp; &nbsp; define('An Inner Object', :version =&gt; &quot;1.0&quot;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; field 'name', :string<br />
&nbsp; &nbsp; &nbsp; &nbsp; field 'value', :integer<br />
&nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; define('An Outer Object', :version =&gt; &quot;2.0&quot;) {<br />
&nbsp; &nbsp; &nbsp; field 'name', :string<br />
&nbsp; &nbsp; &nbsp; field 'wrapping', 'Inner.An Inner Object'<br />
&nbsp; &nbsp; }<br />
&nbsp; }</div></div>

</pre>

<h3>Addendum: what a context&#8217;s path means</h3>

<p><p>In the process of writing the above, I stumbled across some bugs in the zipr library. <a href="https://github.com/frankshearar/zipr/issues/24">First</a>, I realised that a traversal of a complicated tree would have multiple downs and ups. That caused a problem because originally &#8220;rooting&#8221; the zipper &#8211; committing all the edits to build your new structure &#8211; would detect that an edit had occured and invoke a special &#8220;root a changed structure&#8221; path. If one went up after an edit, this &#8220;something has changed&#8221; got lost. But the <a href="https://github.com/frankshearar/zipr/issues/25">second issue</a> turned out to be another instance of the same basic problem.</p></p>

<p>So we know a zipper has two parts, namely a one-hole context, and a value to plug that hole. We also know that a one-hole context is made up of a few parts: nodes to the left of the current focus point, nodes to the right, and so on. One of these pieces of information is the path from the current focus back to the root of the structure &#8211; the <a href="http://learnyouahaskell.com/zippers#a-trail-of-breadcrumbs">trail of breadcrumbs</a>, as Learn You a Haskell calls it. Suppose we&#8217;ve just edited a node, and our path consists of a sequence of nodes a<sub>0</sub>, a<sub>1</sub>, &#8230;, a<sub>n</sub>. If we move up, to node a<sub>n</sub>, the context around that node has not changed. If we root the structure, the rooting process won&#8217;t know that something&#8217;s changed, and we&#8217;ve lost our edit. Suppose instead we move to the left or right. Our parent node is still a<sub>n</sub>, but note that that path does <em>not</em> include the changed node. Again, rooting the structure does not pass through any context that says &#8220;hey, wait a minute, something&#8217;s changed&#8221;, and again our edit is lost!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lshift.net/blog/2012/02/27/transforming-ruby-dsls/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

