<?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-5681827487565088993</id><updated>2012-01-04T00:52:56.664-08:00</updated><category term='role playing'/><category term='scala'/><category term='milestone'/><category term='git'/><category term='rsync'/><category term='xus'/><category term='past'/><category term='pastry'/><category term='programming'/><title type='text'>This Statement is False</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>25</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-3751687736439246034</id><published>2012-01-04T00:51:00.000-08:00</published><updated>2012-01-04T00:51:36.333-08:00</updated><title type='text'></title><content type='html'>I added an intro, a summary, and a few more ideas to the &lt;a href="http://this-statement-is-false.blogspot.com/2011/12/code-google.html"&gt;Code Google post&lt;/a&gt;. &amp;nbsp;It needs a better name that doesn't just mean "search" to people and also doesn't include trademarked words :).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-3751687736439246034?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/3751687736439246034/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2012/01/i-added-intro-summary-and-few-more.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/3751687736439246034'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/3751687736439246034'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2012/01/i-added-intro-summary-and-few-more.html' title=''/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-789768149532422260</id><published>2011-12-27T00:02:00.000-08:00</published><updated>2012-01-04T00:52:56.667-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Code Google</title><content type='html'>UPDATE: Added structure and a few more ideas...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Intro&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Have you ever seen someone include a giant open source library in a project, just to access some small part of its functionality?  It's very important to have someone else write, debug, and maintain a large part of your code, but when you do this over and over, it can add quite a lot of bloat to an app for comparatively little gain in functionality.&lt;br /&gt;&lt;br /&gt;This is a huge problem, as I see it, but maybe there is a solution?&lt;br /&gt;&lt;br /&gt;What about allowing people to integrate only small subsets of modules into their code.  I'm calling this idea "code google," for lack of a better term, although it's a LOT more than just search.  It involves search, analysis, IDE integration, and social networking, so that library developers can track what parts of their code are actually being used.  It's far from trivial to implement, but I think it could be very useful&lt;br /&gt;&lt;br /&gt;Before our company started, a friend and I wrote a fair-sized game in LISP (a couple tens of thousands of lines) and later versions used OO languages (both class-based and prototype-based). &amp;nbsp;My friend and I seem both to be coming to the conclusion that what is happening in the Java world is not a good thing. &amp;nbsp;A lot of modern programming seems actually to be just gluing together libraries and frameworks. &amp;nbsp;Many times, frameworks are chosen because of a few of their features and glued onto other frameworks similarly chosen.&lt;br /&gt;&lt;br /&gt;Module systems concentrate on versioning in the large -- each framework is versioned as a whole, despite the fact that so many people (apparently) pick a small set of features and use that. &amp;nbsp;Programmers achieve modularity by marking off a segment of code and declaring it to be a module. &amp;nbsp;APIs are defined explicitly by developers, but I, on the other hand, often need to use implicit APIs that the developers didn't consider to be "first class," when they wrote their code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code Search&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;What I think is needed, in addition to explicit module declaration, is a "code Google" that searches the vast sea of code and finds a small subset that does what I need at the time. &amp;nbsp;Curiously enough, this already exists, in part, for Haskell programmers, with Hoogle, that lets you search for functions based on their type signatures. &amp;nbsp;It might be hard to imagine how this could possibly work in Java, because you won't necessarily know the name of the actual type you are looking for, but it becomes more practical as Java gets closer to LISP (or Haskell), because it becomes easier to express generic behavior without knowing as many explicit names. &amp;nbsp;A "code Google" for Java could allow you to inline a method signature without knowing the name of the SAM type that the code needs. &amp;nbsp;This could be done before Java actually has a lambda syntax.&lt;br /&gt;&lt;br /&gt;Closures will go a long way toward making Java simpler to use, since so many design patterns are trivial with them -- I made a command-driven framework in Java 1.0.4, before there were even anonymous inner classes and had to make a separate class file for each of several hundred commands. &amp;nbsp;You can look at how much much easier AWT became after the introduction of anonymous inner classes for an example of this detangling; you don't have to subclass Button, anymore, when you make a GUI, you just make an anonymous event handler inner class. &amp;nbsp;In Java 8 (or later?), each of these 1.0.4 files would just be a lambda expression -- same anonymous inner class mechanism as in Java 6, but it's a LOT easier on the eyes.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code Snippet Retrieval&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In addition to search, Code Google should be able to retrieve the dependencies of the code snippet you need and pack it all up for you in a library jar with source included. &amp;nbsp;Hoogle does not do anything like this -- it just gets you to the module version. &amp;nbsp;Again, as Java gets closer to LISP, dependencies won't need to be as tangled up because as closures become easier to use and more prevalent in code, it becomes easier to write code that stands on its own (see the AWT evolution for examples). &amp;nbsp;It's already possible to do this in Java, by using anonymous inner classes, but these are verbose and a lot of people don't like to use them (except when they write event handlers :) ).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Social Networking and IDE integration&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Once you have the snippet, all jarred up, there should be a way to track the search query and the version of the module it came from, so you can automatically update your code. &amp;nbsp;When someone downloads a snippet, there should be a social networking tie-in with tools that the developers use so that they can see an annotation in their code to let them know that people are using that particular API, so that the the developer doesn't unintentionally change or remove that implicit API. If the search does fail because the code is no longer in a module, someone can still spawn another open source module to support it. &amp;nbsp;The social networking support should also indicate how many people are using a piece of functionality and allow people to attach comments to the code so the developers and other users can see them.&lt;br /&gt;&lt;br /&gt;As an alternative to IDE integration, there should also be command line and web-based tools for your project. &amp;nbsp;Mods to Gitweb and Fossil, maybe?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Code Search&lt;/b&gt; indexes vast amounts of code and lets people search for what they need by specifying type signatures in addition to just unstructured text&lt;/li&gt;&lt;li&gt;&lt;b&gt;Code Snippet Retrieval&lt;/b&gt; incorporates a snippet and its dependencies into your project's codebase and includes metadata that describes where the snippet came from (the module, version number, site, etc.)&lt;/li&gt;&lt;li&gt;&lt;b&gt;IDE Integration&lt;/b&gt; puts this information at your fingertips so users can be informed when new versions are available and developers can be informed which pieces of their code that people are finding important and how many people are using the code&lt;/li&gt;&lt;li&gt;&lt;b&gt;Social Networking&lt;/b&gt; lets people comment and collaborate with the developers to keep them connected to the users of their code&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;The &lt;a href="http://code-recommenders.blogspot.com/"&gt;Eclipse Code Recommenders&lt;/a&gt; plugin looks like it's trying to do the search portion, at least.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-789768149532422260?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/789768149532422260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2011/12/code-google.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/789768149532422260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/789768149532422260'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2011/12/code-google.html' title='Code Google'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-6867794707228325800</id><published>2011-09-27T10:13:00.000-07:00</published><updated>2011-09-27T10:13:22.496-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='role playing'/><title type='text'>Podcast interview about Death of the Vele</title><content type='html'>I already blabbed this in a bunch of emails to people, but just in case... Scott Dunphy of New Style interviewed me about Death of the Vele, &lt;a href="http://newstyle.spookyouthouse.com/2011/09/interview-8-bill-burdick-death-of-the-vele/"&gt;here&lt;/a&gt;.  This was the first time I've been interviewed for anything; I was surprised I sounded coherent -- I thought it might come out a lot less cohesive than it did when I listened to it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-6867794707228325800?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/6867794707228325800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2011/09/podcast-interview-about-death-of-vele.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/6867794707228325800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/6867794707228325800'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2011/09/podcast-interview-about-death-of-vele.html' title='Podcast interview about Death of the Vele'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-6498617271389912377</id><published>2011-08-18T10:17:00.000-07:00</published><updated>2011-08-18T10:48:46.120-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='role playing'/><title type='text'>Quick update on The Philosopher's Stone</title><content type='html'>I have changed TPS many times in the past year and a half, but the core idea is still to be a collaborative story telling RPG that feels like a traditional RPG.  The latest version of it is called Death of the Vele and the (lame) website is &lt;a href="https://sites.google.com/site/deathofthevele/"&gt;here&lt;/a&gt; It has a link to the latest rules.&lt;br /&gt;&lt;br /&gt;Wow, taking a look at the old rules, I see that I have streamlined the mechanics a LOT since last year.  They are simpler, lighter weight, and more intuitive.  There are also tools to promote more integrated and structured stories (spotlights, hitting aspects, etc.).  Death of the Vele also adds a back story (which you can remove if you don't like, of course).&lt;br /&gt;&lt;br /&gt;I'm hoping to publish Death of the Vele within the next 12 months.  In the mean time, the rules are out there for free, so anyone who wants to can use them.&lt;br /&gt;&lt;br /&gt;Here is the feature list from the latest copy of the rules:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Collaborative, but feels like a traditional RPG&lt;br /&gt;&lt;li&gt;Your characters are yours&lt;br /&gt;&lt;li&gt;Supports campaign-length stories&lt;br /&gt;&lt;li&gt;Game play stays at the table&lt;br /&gt;&lt;li&gt;Characters don’t always do their best -- sometimes they have an off-day, even if their stats say they’re fine, but this is your decision&lt;br /&gt;&lt;li&gt;The Right of Challenge -- if the other players don’t buy it, you can’t do it&lt;br /&gt;&lt;li&gt;Show, don’t tell -- a lot of communication happens through scenes and events&lt;br /&gt;&lt;li&gt;Answer questions with scenes -- if players want to know, scenes reveal the answer&lt;br /&gt;&lt;li&gt;Characters are naturally “woven together”&lt;br /&gt;&lt;li&gt;Your characters will get the spotlight&lt;br /&gt;&lt;li&gt;Supports visiting gamers&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-6498617271389912377?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/6498617271389912377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2011/08/quick-update-on-philosophers-stone.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/6498617271389912377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/6498617271389912377'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2011/08/quick-update-on-philosophers-stone.html' title='Quick update on The Philosopher&apos;s Stone'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-478362954351335363</id><published>2011-07-08T09:47:00.000-07:00</published><updated>2011-07-08T10:11:12.948-07:00</updated><title type='text'>Applied Lambda Calculus</title><content type='html'>I made a &lt;a href="http://tinyconcepts.com/fs.pl/lambda.fsl/doc/tip/slides.html"&gt;slide presentation introducing Lambda Calculus&lt;/a&gt; and some functional concepts (lazy evaluation, how to represent data, etc.).  It also talks about a &lt;a href="http://tinyconcepts.com/fs.pl/lambda.fsl/doc/tip/evaluator.html"&gt;Lambda Calculator&lt;/a&gt; I wrote, which does LC in three ways:&lt;div&gt;&lt;ul&gt;&lt;li&gt;compiles into JavaScript&lt;/li&gt;&lt;li&gt;interprets through substitution (alpha, beta, and eta) and shows the steps&lt;/li&gt;&lt;li&gt;compiles into virtual machine code (and can execute it)&lt;/li&gt;&lt;/ul&gt;The VM still fails on some complex cases, but when I have that working, I want to make it generate native code, using LLVM.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I open sourced all this, under the ZLIB license.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Oh, I also started on a Lambda Calculus version of &lt;a href="http://tinyconcepts.com/invaders.html"&gt;space invaders&lt;/a&gt;, which is in there, too :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;LC is a really nice language.  I wasn't able to find a modern, untyped, lazy language.  It seems like functional languages have all gone the way of static typing, but I'm hoping it doesn't have to end that way.  Looking at what Anders Møller and co. are doing with &lt;a href="http://www.brics.dk/TAJS/"&gt;TAJS&lt;/a&gt; at Aarhus University and BRICS gives me hope that some day, the computer will tell the type information to the programmer and not the other way around like it is, today.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I wrote my own "Lambda Calculator."  Really, it was so I could teach a friend about computers, but I am relatively new to LC and I thought I really ought to write something in it, which is why I chose Space Invaders.  So far, I have 55 lines of space invader code written.  It doesn't do all that much, but I think it's still informative.  In the mean time, I had to make that slide presentation and fix bugs in the calculator.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had a &lt;b&gt;lot&lt;/b&gt; of fun writing space invaders and I think I'm starting to understand the power of having lazy evaluation, currying, etc. built into a language (shame on me for not using Haskell, yet). Check out the slides for more info :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-478362954351335363?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/478362954351335363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2011/07/applied-lambda-calculus.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/478362954351335363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/478362954351335363'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2011/07/applied-lambda-calculus.html' title='Applied Lambda Calculus'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-10222944363796858</id><published>2010-10-22T04:02:00.001-07:00</published><updated>2010-10-22T05:11:46.792-07:00</updated><title type='text'>Calculator/spreadsheet tool for Acme</title><content type='html'>I got Plan9 from User Space and started messing with it in the hopes of getting a nice toolbench going with Acme.  Since I wrote &lt;a href="http://ober.sourceforge.net/"&gt;Ober&lt;/a&gt;, I've been interested in this idea.  Now, I'll probably rewrite it in Go.  I'm wondering if I can just use named pipes to mimic what Acme does with its 9p interface.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, I wrote a simplified version of the Calc tool I wrote for Ober and I put it, &lt;a href="http://repo.or.cz/w/bills-tools.git/tree/HEAD:/calc"&gt;here&lt;/a&gt;.  The calc tool searches an Acme window for variables and their values and some code at the bottom.  Then, it executes the code, sending the variables and values to its stdin.  The code is expected to output new values for some of the variables.  Calc parses the output and replaces the new values into the window.  I'm also including two wrappers that make it easy to write calc scripts in rc or Go, so you can say something like this:&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;Bob's age=30, he is yearsleft=0 years away from retirement (calc).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;#!/usr/bin/env calcgo&lt;/div&gt;&lt;div&gt;yearsleft = 55 - age&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;If you middle-click "calc" in the text, it will update the window to show yearsleft=25.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-10222944363796858?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/10222944363796858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/10/calculatorspreadsheet-tool-for-acme.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/10222944363796858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/10222944363796858'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/10/calculatorspreadsheet-tool-for-acme.html' title='Calculator/spreadsheet tool for Acme'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-1664586056838598820</id><published>2010-04-17T10:31:00.000-07:00</published><updated>2010-04-17T11:57:35.635-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='role playing'/><title type='text'>The Philosopher's Stone</title><content type='html'>&lt;span style="font-style:italic;"&gt;I've been searching for the "Philosopher's Stone" of role playing for years -- a role playing system that combines traditional role playing with the collaborative story telling of Universalis.  I think the Blood Red Sands system might allow this.  By replacing the coins of Universalis with dice, BRS introduces relative differences between traits, an element of risk into contesting for narrative control, and a competitive framework for play.  I think this difference can allow it to support traditional role playing better than Universalis.&lt;/span&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;That's how the document for the new game I'm working on starts.  I found Ralph Mazza's Blood Red Sands about 5 weeks ago, when I checked out the Ramshead Publishing site, to see if there was anything new going on.  Wow, was there ever!  Blood Red Sands is a highly stylized, competitive role playing/story telling game about heroes and their ordeals as they strive to confront the evil, despotic Witch King in a blasted land called Abalahn.  My summary of Blood Red Sands is &lt;/span&gt;&lt;a href="http://spreadsheets.google.com/pub?key=0An2MRkbkRMqbdHFYVk9QS2lPYzVpaXhpaTQwM3pPWXc&amp;amp;gid=14"&gt;here&lt;/a&gt;&lt;span&gt; and the play test rules are &lt;/span&gt;&lt;a href="http://ramsheadpublishing.com/index.php?module=Pagesetter&amp;amp;tid=4&amp;amp;filter=category^sub^20&amp;amp;cv=20"&gt;here&lt;/a&gt;&lt;span&gt;.  There are some discussions about BRS on &lt;/span&gt;&lt;a href="http://story-games.com/forums/"&gt;Story-Games.com&lt;/a&gt;&lt;span&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Universalis is really a different type of game (which is why it was named "most innovative indie game" of 2002).  It's not really a role playing game; it's a story telling game.  Theory From the Closet interviews Mike Holmes (coauthor)  and he talks quite a bit about Universalis &lt;a href="http://theoryfromthecloset.com/2008/05/07/show037-interview-with-mike-holmes/"&gt;here&lt;/a&gt;.  A later podcast interviews Ralph Mazza about Blood Red Sands, Universalis, and other things &lt;a href="http://theoryfromthecloset.com/2008/05/19/show039-interview-with-ralph-mazza/"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I started playing Universalis in December, 2005.  In December, 2007, I combined Universalis with FATE and PDQ in a campaign we ran for over a year.  We started every session with a few Universalis scenes (usually 20-40 minutes of play), then we played a mashup of PDQ and FATE, incorporating the new information from the Universalis scenes, and we ended a lot of the sessions with Universalis, too.  It worked really well.  During the Universalis sessions, there were a few ground-rules (enforced by Universalis gimmicks), but other than that, the players had free-reign with the story.  They could define NPC motivations, stage events that took place "meanwhile", etc.  I was tag-team GMing with a friend and we had to deal with all of the curves the players threw at us -- the players introduced some things into the story we really hadn't thought of. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Universalis is also how we did all of our cut-scenes.  What made it radically different from the way MOST GMs do their cut-scenes is that the players could take over in mid-scene and change things.  You can look at a bunch of the Universalis logs &lt;a href="https://spreadsheets.google.com/pub?key=0An2MRkbkRMqbcEd1TDdTY2NNRWFNUnRBSDdMTXhQYkE&amp;amp;hl=en&amp;amp;output=html"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I loved the Universalis integration so much, that I've been searching for "clean" system ever since; one that allows story telling &lt;i&gt;and&lt;/i&gt; role playing &lt;b&gt;all the time&lt;/b&gt;.  I tried &lt;a href="http://groups.google.com/group/fsharprpg"&gt;F#&lt;/a&gt;, which is a great game (you should check it out).  It comes close, but it doesn't quite do what I want.  Then I saw Blood Red Sands.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In Blood Red Sands, one player plays their "hero" character, going through ordeals on the way to confronting the Witch King, while the other each play a "faction" which may be aligned with the Witch King, opposed, or neutral.  BRS is played on two levels at the same time: the story level, where the characters' loyalties are defined by the ordeal and the game level, where the players are all competing, even though their characters may be allies in the story.  This can lead to some interesting story twists and it can support behavior like Pippin's in The Lord of the Rings (check this &lt;a href="http://www.story-games.com/forums/comments.php?DiscussionID=5438"&gt;post&lt;/a&gt;, for example).  BRS is a great game and I consider the underlying system to be the next generation of Universalis.  Also, I think it can lend itself well to traditional role playing, in which &lt;i&gt;every&lt;/i&gt; player gets to role play their character during a session.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, my entry in the mix, &lt;a href="http://spreadsheets.google.com/pub?key=tqXVOPKiOc5iixii403zOYw&amp;amp;output=html"&gt;The Philosopher's Stone&lt;/a&gt;.  It uses the system from Blood Red Sands, so please by Blood Red Sands when it comes out, but it packages it in a different framework that (hopefully) supports traditional role playing.  In The Philosopher's Stone, as in Blood Red Sands, no player is the designated Narrator (i.e. GM) for the whole session -- players trade off acting as the Narrator and they can even "steal" the position of Narrator (just like in Blood Red Sands).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The players cooperate to make the story within a mission/act framework where they define the mission and acts as well as objectives for the group of player characters.  A player can counter an objective and steal the victory points for himself.  Of course, the other players will try to stop him.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The BRS system underneath TPS contains two key mechanisms to limit the power of the current Narrator: challenges and contests.  Any player can challenge the "fiction" that a Narrator composes -- the rationalization that supports a mechanic.  This can't directly prevent a Narrator from using a mechanic, but it can force him to reframe the rationalization and may lead him to try a different tack.  A contest allows a player to attempt to take over the position as Narrator, preempting what the Narrator was doing.  I think these two mechanisms combine well to keep the player who is the Narrator from being "too harsh" on the other players.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One thing that is &lt;i&gt;very&lt;/i&gt; different from other role playing games is that in TPS, players control "story components" in addition to their characters, which are NPCs, monsters, beasts, traps, hazards, etc.  In fact, there are no NPC or other direct "actors" in the story that are not controlled by one of the players. This means that even in a scene without any player characters, the players are still involved, because at least some of the players will have story components present at the scene.  When orcs squabble over who gets to eat a hobbit, it's different players controlling the orcs and one of those players might also have the hobbit in question as their player character (or it could be Neanderthals arguing over a Cro-Magnon captive or aliens planning to torture an earth man).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I don't think that controlling story components in addition to their characters will make it difficult for people to play.  I think there will be scenes with only story components present, scenes with only characters present and scenes with both.  In scenes with both that involve conflict, players will be attacking other players' characters and story components, so I think there's a clear objective.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, that's the idea.  We'll see if it works.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-1664586056838598820?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/1664586056838598820/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/04/philosophers-stone.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/1664586056838598820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/1664586056838598820'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/04/philosophers-stone.html' title='The Philosopher&apos;s Stone'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-724299341525339196</id><published>2010-02-08T22:30:00.000-08:00</published><updated>2010-02-10T01:55:12.175-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='past'/><category scheme='http://www.blogger.com/atom/ns#' term='xus'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='rsync'/><title type='text'>Xus Rsync/Bittorrent/Git approach</title><content type='html'>&lt;div&gt;&lt;b&gt;Approach&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;I started working on my file sharing approach.  Sharing will not involve deltas or packs, just chunks, by Git id.  The idea is to share Git commits, with all of their associated tree and blob objects.  They'll be shared using a manifest for each commit that exhaustively lists all of the chunks in that commit.  A manifest will be a binary XML document (using &lt;a href="http://en.wikipedia.org/wiki/Fast_Infoset"&gt;fastinfoset&lt;/a&gt;, same as Xus uses for its protocol), since that's a pretty efficient binary serialization format (using &lt;a href="http://en.wikipedia.org/wiki/Basic_Encoding_Rules"&gt;BER&lt;/a&gt;encoding for numbers in a lot of places and whatnot) and then using another XML doc to list chunks for the manifest:&lt;div&gt;&lt;ul&gt;&lt;li&gt;A commit manifest contains the serialized commit data, the commit id, and a list of tree object ids/crcs and blob ids with blob chunk ids/crcs&lt;/li&gt;&lt;li&gt;A commit manifest chunk list contains a list of chunks for the commit manifest file, since a commit manifest file could get large&lt;/li&gt;&lt;/ul&gt;I'll probably use an extra branch to store the chunks that a peer currently has for that branch.  When it gets new chunks, it can store them in its chunk-branch for that Git branch (probably named [branch]-chunks).  Git will properly reuse shared chunks because that's what Git does.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A word about chunks.  Git stores its data compressed, but to get good chunks, we have to uncompress the data first and then break it into chunks.  This is so that we can effectively scavenge the Git repository for chunks so that we can avoid downloading the ones we already have, ala rsync.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;How rsync works&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The brilliant idea of rsync is that you can cheaply compute a "rolling crc" as you "slide a window" down a file, byte-by-byte.  An example of this type of crc is the standard shift-xor hash function a lot of people use for strings.  For each byte in the string, shift the crc up one bit and xor the byte in.  Assuming you are using a 32-bit hash, the hash is only "good" for 32 bytes of a string.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's an implementation of the Rsync chunk finder with a very simplistic rolling crc function:&lt;pre&gt;import java.io.FileInputStream&lt;br /&gt;import scala.collection.mutable.ArrayBuffer&lt;br /&gt;import java.security.MessageDigest&lt;br /&gt;&lt;br /&gt;object Rsync {&lt;br /&gt; def use(test: Boolean)(block: =&gt; Any) {&lt;br /&gt;  if (test) {&lt;br /&gt;   block&lt;br /&gt;  } else {&lt;br /&gt;   println("Usage: Findit [-hash string] | [-find file crc sha-1]")&lt;br /&gt;   System.exit(1)&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; def pad(n: BigInt, width: Int) = {&lt;br /&gt;  val s = n.toString(16)&lt;br /&gt;&lt;br /&gt;  if (s.length &gt;= width) {&lt;br /&gt;   s&lt;br /&gt;  } else {&lt;br /&gt;   ("%0"+(width - s.length)+"d").format(0)+s&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; def next(hash: Long, number: Int) = {&lt;br /&gt;  var p = 0&lt;br /&gt;  var n = number&lt;br /&gt;&lt;br /&gt;  for (i &lt;- 1 to 8) {&lt;br /&gt;   p ^= n&lt;br /&gt;   n &gt;&gt;= 1&lt;br /&gt;  }&lt;br /&gt;  (hash &lt;&lt; 1) | (p &amp; 1)&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; def sha(msg: String) = {&lt;br /&gt;  val digest = MessageDigest.getInstance("SHA1")&lt;br /&gt;  val i = BigInt(digest.digest(msg.getBytes))&lt;br /&gt;&lt;br /&gt;  digest.reset&lt;br /&gt;  i&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; def find(file: String, crcIn: Long, shaIn: BigInt, len: Int): Int = {&lt;br /&gt;  val input = new FileInputStream(file)&lt;br /&gt;  var crc = 0L&lt;br /&gt;  val buf = ArrayBuffer[Char]()&lt;br /&gt;  var offset = -1&lt;br /&gt;  var mask = (1 &lt;&lt; len) - 1&lt;br /&gt;&lt;br /&gt;  while (true) {&lt;br /&gt;   val c = input.read()&lt;br /&gt;&lt;br /&gt;   if (c == -1) {&lt;br /&gt;    input.close&lt;br /&gt;    return -1&lt;br /&gt;   } else {&lt;br /&gt;    offset += 1&lt;br /&gt;    crc = next(crc, c)&lt;br /&gt;    buf.append(c.asInstanceOf[Char])&lt;br /&gt;    if (buf.length &gt; len) buf.remove(0)&lt;br /&gt;    if ((crc &amp; mask) == crcIn &amp;&amp; sha(buf.mkString) == shaIn) {&lt;br /&gt;     input.close&lt;br /&gt;     return offset&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  return -1&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; def main(args: Array[String]) {&lt;br /&gt;  use(args.length &gt; 0) {&lt;br /&gt;   args(0) match {&lt;br /&gt;   case "-hash" =&gt; use(args.length == 2)(println("args: -find file "+pad(BigInt(args(1).foldLeft(0L)(next(_, _))), 16)+" "+pad(sha(args(1)), 40)+" "+args(1).length))&lt;br /&gt;   case "-find" =&gt; use(args.length == 5)(println("offset: "+find(args(1), BigInt(args(2), 16).longValue, BigInt(args(3), 16), args(4).toInt)))&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This is more or less what Xus will use.  As you can see, you can efficiently update the crc a byte at a time, so it's quick to locate a chunk.  When you have several chunks, just use a set of CRCs.  As you scan the file, check each crc to see if it's in the set.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So after Xus gets a manifest it has to download all of the chunks it doesn't have.  Here's how it will work:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Check the Git repository for the file id.  If it's in there, no need to download&lt;/li&gt;&lt;li&gt;Check the Git repository for a previous version of that file (we can eventually include extra information in the manifest if the creator's Git detected a rename).  If there is a previous version, scavenge the previous version for chunks using the rsync algorithm&lt;/li&gt;&lt;li&gt;If there are any outstanding chunks we need to download, request them from the DHT&lt;/li&gt;&lt;/ol&gt;&lt;b&gt;Requesting from the DHT&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When a peer needs to download a chunk, we use the topic as a DHT, backed by the master peer's storage:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Use a DHT message to send a chunk request to the peer with ID nearest the chunk's ID&lt;/li&gt;&lt;li&gt;If the peer does not have the chunk, it requests it from a topic master using a mini topic master DHT to distribute the load&lt;/li&gt;&lt;li&gt;Once the peer has the chunk, it connects to the requesting peer and transfers the chunk to it&lt;/li&gt;&lt;/ol&gt;&lt;b&gt;Connecting to a Peer&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some peers may not be able to accept connections.  This interferes with chunk sending requests.  Xus has two ways to deal with this problem:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;The preferred way is the connection service: if one peer can receive connections but the other cannot, the peer which can receive connections can delegate a message to the other peer to connect back to it&lt;/li&gt;&lt;li&gt;If neither peer can receive connections, they can delegate all of their messages through the topic master&lt;/li&gt;&lt;/ol&gt;So, there you have a fairly detailed idea of how I'm implementing the Xus file sharing service.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-724299341525339196?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/724299341525339196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/02/xus-rsyncbittorrentgit-approach.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/724299341525339196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/724299341525339196'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/02/xus-rsyncbittorrentgit-approach.html' title='Xus Rsync/Bittorrent/Git approach'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-7956335621396501723</id><published>2010-01-26T01:36:00.000-08:00</published><updated>2010-01-26T04:50:53.607-08:00</updated><title type='text'>Story telling in role playing games</title><content type='html'>&lt;div&gt;I play a lot of indie RPGs, like &lt;a href="http://www.evilhat.com/home/sotc/"&gt;Spirit of the Century&lt;/a&gt; and &lt;a href="http://www.7skies.net/"&gt;Swashbucklers of the Seven Skies&lt;/a&gt;, but for the past couple months, we've been retrying D&amp;amp;D 4e (and I'll be using "DM" below a lot of times in the generic sense).  I tried it for 5 months in 2008, running a Keep on the Shadowfell adventure.  I have to say that I think that was a mistake for Wizards.  It's a dungeon.  A lot of the monsters aren't intelligent (rats, oozes, skeletons, zombies). Etc.  It ran like a 5 month long miniatures game.  Maybe it was me, I don't know.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Nevertheless, we're giving 4e another go (this time, I even get to be a player!)  D&amp;amp;D 4e has some great ideas and it has great resources for DMs.  Since 2005, I've used techniques described in the "Group Storytelling" in the DMG2.  You can find a lot of helpful hints for DMs out there on the net and I haven't read nearly all of them, but maybe I use some novel techniques.  Some of these techniques were new to the veteran DMs and RPG designers I've spoken with.  I created/independently discovered/borrowed/stole several techniques specifically to prevent wasting the work I do as a DM/story writer.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;A friend of mine ran an adventure for us a while back and after we failed a search check in one room, I noticed him file away a sheet on which he had written a LOT of text.  I asked him later if we were supposed to see that only if we succeeded in that roll, thus wasting all of that work.  He said "yes."  I thought it was a shame that he did all of that work and we never got to see it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;Usually, I have a campaign story arc, with subarcs for sections of the story.  For each subarc (i.e. adventure), I do something kind of like what the DMG2 describes in the "Branching" section.  Rather than make a tree with possibly dead scenes, I write a LINEAR story line which is really just a list of scenes, usually using an outline format in a google spreadsheet (this is great for collaborative DMing, by the way).  This list represents the order in which I THINK the players are going to experience the scenes.  I almost never have any "dead" scenes in my stories -- I work too hard coming up with ideas and fleshing them out to allow them to be skipped :).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Players almost never make the decisions I'm expecting them to make, so the actual order of scenes usually ends up different from the way I wrote it, with from-the-hip scenes inserted in the list as well, along with alterations to the original scenes (I usually change the spreadsheet as I run the adventure).  To prevent the players from skipping over scenes and information that I've worked so hard to produce, I use a few techniques that they didn't mention in the branching section.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First, a few observations to keep in mind:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;The players don't have a lot of information until the DM reveals it; they don't know what's behind every door or around every corner&lt;/li&gt;&lt;li&gt;The DM can ask a player to make a roll without telling them why; "make a perception roll"&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;If the players skip over a scene, there are a few techniques I use to "reclaim" the scene so I can present it to them later on:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;if it is an appointment that they missed, make it a "chance meeting" later&lt;/li&gt;&lt;li&gt;if it was with a particular person who is out of the story now, reassign it to another person or use a messenger to convey the information&lt;/li&gt;&lt;li&gt;make a new scene on-the-fly that accomplishes the same goals&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;Sometimes the story requires a prerequisite before an event can happen, like searching, detecting an ambush, etc.  Prerequisites can be a way to put a certain character in the spotlight, like requiring a certain ritual, a certain skill, a bloodline, a race, etc.  Lock-and-key scenarios that require successful rolling can be a bit dicey (sorry :D).  You don't want the players to blow a roll and fail to see the cool document with the burnt edges that you antiqued by heating up paper soaked with lemon juice!  The "Avoiding Dead Branches" section in the DMG2 presents two alternatives for "fake" branches; i.e. situations that look like a branch, but where there is no actual chance of failure.  The alternatives are setting the DC of the check to 1 and "dropping the pretense" by just telling the players they succeeded (i.e. no roll).  Here are some techniques I use to make sure that the players get the information or have the experience that I put so much work into, but still "keep the pretense"...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Ball and cups&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Ever see that magic trick, where the magician shuffles around 3 cups and you can't tell which cup has the ball under it?  The first two cups you look at never have the ball; it's always in the third cup.  That's because the magician has the ball in his hand.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When the players are searching for something which could be anywhere, sometimes I assign it to "the third place they check".  So after they look in two empty rooms, the third room will have what they're looking for, regardless of what the map looks like.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Suppose the players are looking for clues.  Prepare several clues for them to find and have them gain the clues on successful search rolls in a specific order, &lt;i&gt;regardless of where they are when they actually do the searching&lt;/i&gt;.  So they can search 5 rooms in a house, find two clues and then search the alley to find the third clue.  If they succeed in each of the first 3 rooms in the house, they get the clues then.  If they blow all of the rolls in the house and the alley, they can discover the clues in some other location entirely.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Well, aren't you clever!&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Suppose you want to have the characters spot an ambush in a jungle way before it happens so they can ambush the ambushers.  The D&amp;amp;D game mechanics represent keen senses as a high perception skill value.  Call for a perception roll from the group and if they blow it, give them a "soft ball" random encounter.  Wash-rinse-repeat until they get a successful roll.  When they do succeed, run the "real" encounter where they get to surprise the ambushers as they are preparing the ambush.  Instead of just declaring that the characters have surprised the ambushers, they surprise them "because" they succeeded on a perception roll.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Reality is how you perceive it&lt;/b&gt;&lt;/div&gt;&lt;div&gt;OK, this one is from &lt;a href="http://open.crngames.com/src/donjon.html"&gt;Donjon&lt;/a&gt;.  Sometimes, the players search for traps and none of the chests/doors/cabinets in the whole building actually have traps.  If they ask to check for traps, sometimes you'll want to put a trap there anyway.  If they blow the roll, it can explode, if they make it, they can disarm it.  When the characters use their skills, the player is actually requesting some spot light time for their character.  Give it to them.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-7956335621396501723?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/7956335621396501723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/01/story-telling-in-role-playing-games.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/7956335621396501723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/7956335621396501723'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/01/story-telling-in-role-playing-games.html' title='Story telling in role playing games'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-2602579102315276937</id><published>2010-01-21T00:23:00.000-08:00</published><updated>2010-01-21T00:48:59.233-08:00</updated><title type='text'>Use rsync with Xus file sharing?</title><content type='html'>I'm wondering if it would be a good thing to use a variant of the rsync algorithm with Xus file transfer.  This would help save a lot of bandwidth for large files that only have small changes.  One example is Sauerbraten maps, which can be 2M or more (after compression).  When you move a tree, only a small part of the map file is changed, but without rsync behavior, pushing an update requires transferring the whole file.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At this point, Plexus breaks files into chunks that are 50K (if I remember correctly) and keys them by SHA-1 hashes.  If we include rsync's rolling CRC with the chunk ID, that would be enough (I think) for a peer to determine whether it could reuse a chunk from its current file and avoid downloading a chunk.  I'll have to check on rsync to see its default chunk size.  We chose 50K based on tuning with Pastry and Xus' behavior will probably be very different.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-2602579102315276937?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/2602579102315276937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/01/use-rsync-with-xus-file-sharing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/2602579102315276937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/2602579102315276937'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/01/use-rsync-with-xus-file-sharing.html' title='Use rsync with Xus file sharing?'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-1237056355381336211</id><published>2010-01-18T10:11:00.000-08:00</published><updated>2010-01-18T14:59:49.568-08:00</updated><title type='text'>Xus file sharing</title><content type='html'>It's been a long time since my last post; various RL intrusions encroached on Xus.  Now I'm starting the file sharing piece.  I'm basing it on what I did in Plexus, but starting right away with Git integration instead of putting it off, since that seems to be a better way to actually have Git integration :).&lt;br /&gt;&lt;br /&gt;Xus has kind of a weird profile for a p2p system.  It's made to handle a mass of small clusters, rather than a giant, monolithic cloud.  It's really based on the needs of Plexus, but I suspect other systems out there can benefit from it.  In a monolithic p2p storage system like bittorrent or FreePastry's PAST, the cloud can (theoretically) be so large that the data can "live in the cloud".  In a game like Plexus (or Sauerbraten), however, the clusters are small and may often drop to 0 users (like when the players for a particular world are asleep), so there needs to be a way to restore cluster state (so a world with no players is still up-to-date when a player joins, even if they weren't around recently).&lt;br /&gt;&lt;br /&gt;The most straightforward way I could think of to accomplish this is just to use a Git repository for the Xus file cache and mirror it to a remote Git repository for backup/restore.  When a topic space master boots a topic space, it can pull from a remote git repository to restore the state.  To avoid a single point of failure, the owners can push to more than one designated repository.  The DHT portion of the repository is only useful for peers that are connected, since the DHT expands and contracts, causing chunks to be copied around over time.&lt;br /&gt;&lt;br /&gt;Storage:&lt;div&gt;&lt;ol&gt;&lt;li&gt;each resource is tracked with a tag: an outer directory containing chunk-list file and a subdirectory with standard names&lt;/li&gt;&lt;li&gt;creator sends packed delta to topic owner&lt;/li&gt;&lt;li&gt;owner pushes delta to remote Git repository&lt;/li&gt;&lt;li&gt;owner returns signatures for the chunks, etc. to creator&lt;/li&gt;&lt;li&gt;creator stores chunks, etc. in the DHT.&lt;/li&gt;&lt;li&gt;creator gets an event when storage process is complete&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Retrieval:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;request tag from owner, which responds with ID of chunk-list file&lt;/li&gt;&lt;li&gt;retrieve chunk-list from DHT (which delegates to owner if chunk not in cache)&lt;/li&gt;&lt;li&gt;retrieve chunks from DHT (possibly delegating to owner to fill cache)&lt;/li&gt;&lt;li&gt;requester gets an event when the retrieval process is complete&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;Several owners is a good thing in this model, since they back the DHT cache.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_ff5WPTRrotc/S1ThnylbjFI/AAAAAAAAABY/Gl4941rWY40/s1600-h/file-sharing.png"&gt;&lt;img src="http://1.bp.blogspot.com/_ff5WPTRrotc/S1ThnylbjFI/AAAAAAAAABY/Gl4941rWY40/s320/file-sharing.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5428211524598205522" style="cursor: pointer; width: 320px; height: 182px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, that's the idea.  I decided I'm going to include the source to jgit and its dependencies (jsch and jzlib) with this. Requiring on a properly installed command-line Git is just too much work to make developers do (or force their users to do).  Requiring developers to download, test, and package a compatible version of JGit wouldn't be nice either.  So I have some bloat now.  I really don't see the file sharing part as being quite so optional, anyway.  From my experience, nontrivial p2p apps tend toward bit torrent the same way most apps tend toward email clients (that's someone's law; maybe I'll get a comment with a citation for it).&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-1237056355381336211?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/1237056355381336211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/01/xus-file-sharing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/1237056355381336211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/1237056355381336211'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2010/01/xus-file-sharing.html' title='Xus file sharing'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_ff5WPTRrotc/S1ThnylbjFI/AAAAAAAAABY/Gl4941rWY40/s72-c/file-sharing.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-4698645781056507500</id><published>2009-10-11T11:10:00.000-07:00</published><updated>2010-02-08T22:31:51.775-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xus'/><category scheme='http://www.blogger.com/atom/ns#' term='pastry'/><category scheme='http://www.blogger.com/atom/ns#' term='milestone'/><title type='text'>Xus Milestone 1 complete</title><content type='html'>According to my only somewhat extensive automated tests, Milestone 1 (Basic Xus) is now complete.  That includes layers 1 and 2 and the property service (transient and persistent properties).  Plexus relies heavily on its property service (currently backed by FreePastry) and I think it will be useful to other programs as well.  It's kind of a persistent broadcast; it's really just for relatively small databases, like if you have to track a few hundred things for the topic, like player locations in a game or account credit, for instance.  Plexus uses properties for player presence (nickname, which world they're connected to, etc.) and object information (location, orientation, costume, etc.)  If you need to store large amounts of data, it might be appropriate to use the file storage service (coming soon and featuring optional Git integration) or maybe to add a database service (and contributing it back to the project would be nifty, too).  &lt;a href="http://en.wikipedia.org/wiki/Distributed_hash_table"&gt;DHT&lt;/a&gt; message routing is useful for this sort of thing, so you don't necessarily have to replicate all the data to all of the peers if you are storing  a large amount.&lt;br /&gt;&lt;br /&gt;When a peer successfully joins a topic, the topic owner sends it the current property values.  Peers broadcast property settings or deletions to the topic and the topic owner keeps track of the properties for when new members join.  This creates a very simple (some might even say simplistic) database for each topic.  It's just key-value pairs of strings (like in Java's Properties object).&lt;br /&gt;&lt;br /&gt;When you set a property, you specify whether the setting should be persistent.  If a peer has storage turned on, persistent properties are stored in an XML file so that they are there next time the peer starts up.  It usually only important for topic owners to store persistent properties, because other peers always get the latest properties for a topic when they connect to it (and they may have changed since the peer was last connected anyway).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-4698645781056507500?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/4698645781056507500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/10/xus-milestone-1-complete.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/4698645781056507500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/4698645781056507500'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/10/xus-milestone-1-complete.html' title='Xus Milestone 1 complete'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-55662071690587554</id><published>2009-10-07T01:47:00.000-07:00</published><updated>2010-02-08T22:32:49.963-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='past'/><category scheme='http://www.blogger.com/atom/ns#' term='xus'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='pastry'/><title type='text'>Xus' file storage service and Git</title><content type='html'>Xus has a 2-pronged approach for integrating its file storage with Git:&lt;br /&gt;&lt;ol&gt;&lt;li&gt; the basic file storage will just use ordinary file storage, with an approach similar to Git's, ensuring that Xus' model is "compatable" with Git's&lt;/li&gt;&lt;li&gt; provide a plugin that uses JGit (http://www.eclipse.org/egit/) for people who want to maintain a local Git repository&lt;/li&gt;&lt;/ol&gt;Each peer can be optionally Git-enabled, since the peers will only interact with a local Git repository.  It doesn't use Git's protocol to exchange data, because we want Xus to be able to swarm downloads, but a Git-enabled peer could use Git-clone to seed its cache.  Since the file storage protocol doesn't have to interact with Git, Xus just needs #1 to make sure that a peer can fetch everything it needs over the net.  Since Git uses SHA-1 hashes as keys for almost every type of object, this shouldn't bloat the protocol too much.  Note that when I say "protocol" here, I'm talking about the file storage service protocol, which rides inside of layer 2 messages, not Xus' layer 1 or layer 2 protocols.&lt;br /&gt;&lt;br /&gt;The file storage service will break files into chunks and use the DHT to spread the chunks around.  This is how we do it right now in &lt;a href="http://blog.plubble.com/?p=41"&gt;Plexus&lt;/a&gt;; the directory and chunk models are ours and Plexus uses PAST (Pastry's DHT file storage service) to store and retrieve the objects (chunks, file chunk lists, and directories).  Xus DHT file service will be similar to PAST's but not entirely the same.  The chunk/chunk list/directory model will be similar to Plexus' but it also needs branches, commits, and tags, in order to use Git.&lt;br /&gt;&lt;br /&gt;The Git model has been a milestone on Plexus since last year because I think it's crucial to power an open, collaborative gaming environment.  In a completely open environment where anyone can change anything, version history ensures that people can't destroy data; they can only create new versions without some of the data, and signed commits make spoofing very difficult, allow people to rate authors based on their work, etc.&lt;br /&gt;&lt;br /&gt;This also has the side effect of making a p2p version of Git :).&lt;br /&gt;&lt;br /&gt;I don't think totally reimplementing PAST is a good idea for small clouds, because I believe data copying would kill the network.  If the cloud is small, with peers joining and leaving slowly over time but never getting larger than 5, each time a new peer joins, it gets a copy of all of the data in storage.  PAST does have caching and it works very well for large clouds where storage is built up slowly over time, but I don't think it works well for small rings.  For this reason, I'm planning on only having the topic space masters replicate automatically (hopefully starting with a Git-cloned cache seed), but having "ordinary" peers "fill in the holes" from the topic space master peers on-demand.  This will slow down initial requests, but amortize the impact on the network.&lt;br /&gt;&lt;br /&gt;In practice, I think JGit integration will probably be the default, but I still want to provide it as a plugin as a courtesy to projects so they don't have to link in yet another third party library if they don't require it.  Also, I want non-Git-enabled peers to be able to work with Git-enabled ones seemlessly.  At least this is what seems like a good idea at this time :).&lt;br /&gt;&lt;br /&gt;This implements a form of swarming download, similar in spirit to bittorrent, but not similar in the way it actually functions; you can simultaneously download chunks of files from different peers and several peers will have the chunks, but it's organized quite differently.&lt;br /&gt;&lt;br /&gt;Also :) I'm thinking that it would be a good idea to give each directory (with all of its versions) a separate "view" in Git; i.e. new directories are branched from HEAD in Git (like when you make static web pages for Github: http://pages.github.com/).  This will give each directory an independent set of branches, allowing people to store many different directories in a single Git repository without having to check out a ton of stuff just to get the directory you want, AND it also allows you to reuse the files from other directories because they're all in one Git repository.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-55662071690587554?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/55662071690587554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/10/xus-file-storage-service-and-git.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/55662071690587554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/55662071690587554'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/10/xus-file-storage-service-and-git.html' title='Xus&apos; file storage service and Git'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-6749339114194120242</id><published>2009-10-04T01:59:00.000-07:00</published><updated>2009-10-04T02:35:45.474-07:00</updated><title type='text'>Xus: Layers 1 and 2 work now</title><content type='html'>I have layers 1 and 2 working now, with automated tests (it's on github).  Layer 1 is simple packets and layer 2 is p2p messaging. That covers:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;strong authentication (challenge/response on connect with RSA keys &amp;amp;  signatures)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;direct peer-to-peer messages&lt;/li&gt;&lt;li&gt; broadcast messages&lt;/li&gt;&lt;li&gt;unicast messages&lt;/li&gt;&lt;li&gt;dht messages (delegated to the peer with the peer id closest to the dht key)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;delegated peer-to-peer messages (one peer sending to another peer through a topic)&lt;/li&gt;&lt;/ul&gt;Right now, as long as your peer doesn't spoof its public key, it can connect to any topic (authorization is part of layer 3).  I think one other thing I should add to layer 1 is a heart beat, so you can quickly detect dropped connections (TCP timeouts are notoriously unreliable).&lt;br /&gt;&lt;br /&gt;Layer 3 is the service layer and has these components:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Properties&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Topic authorization and management (including peer "accounts")&lt;br /&gt;&lt;/li&gt;&lt;li&gt;File sharing&lt;/li&gt;&lt;li&gt;Port configuration testing&lt;/li&gt;&lt;li&gt;Connect-back requests (for when only one peer can accept connections)&lt;/li&gt;&lt;/ul&gt;A note about topic management: the idea is to use topic space 0 as a "root" topic space for a cluster of spaces, with topic 1 in space 0 handling administrative concerns for the cluster, like id vending for topic spaces and small id vending for peers (so messages don't have to contain a giant peer ids).  Topic 0,1 would contain a set of properties about accounts and topics which would also allow banning users from clusters and members-only clusters (allowing private and pay services).&lt;br /&gt;&lt;br /&gt;I was thinking back to the very start of my peer-to-peer experiments, so I searched my email archives to see when I started with this.  It was April, 2001 when I first started talking p2p architectures over with my friend Fritz.  A little while later, I made the p2pmud project on source forge; for project paleontologists, here's a link to the old &lt;a href="https://sourceforge.net/search/index.php?words=group_forum_id%3A%2892968+92967+205246+92966%29&amp;amp;sort=score&amp;amp;sortdir=desc&amp;amp;offset=0&amp;amp;group_id=29542&amp;amp;forum_id=1&amp;amp;type_of_search=forums&amp;amp;pmode=0"&gt;p2pmud forums&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The project transitioned through several languages and architectures, eventually adopting FreePastry in Plexus so that we didn't have to write and maintain our own peer-to-peer networking layer.  So now we have to do that and, ironically, the architecture's pretty close to the one I came up with in 2001, except that it's simpler.  In 2001, I had envisioned a set of peers that routed requests to other, natted peers, but now we just have one peer doing the routing for a "topic space" with a bunch of topic spaces clustering to form the entire peer-to-peer grid.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-6749339114194120242?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/6749339114194120242/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/10/xus-layers-1-and-2-work-now.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/6749339114194120242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/6749339114194120242'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/10/xus-layers-1-and-2-work-now.html' title='Xus: Layers 1 and 2 work now'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-2279172273229727705</id><published>2009-09-24T01:05:00.000-07:00</published><updated>2009-09-24T01:55:31.430-07:00</updated><title type='text'>andThen andThen andThen... Scala, where's my car?</title><content type='html'>When I saw Dude Where's My Car?, several years ago with my wife (who is Chinese), she started laughing right as they &lt;a href="http://http://www.youtube.com/watch?v=QrlMK_r01Fw"&gt;pulled into the parking lot of a Chinese restaurant&lt;/a&gt;.  I had no idea why, but she said to wait until the end of the scene.  In the scene, after they order each item, a voice from the speaker says, "and then?" and continues after they run out of things to order until Ashton Kutcher eventually destroys the speaker in frustration.  When the scene was over, I asked her why she started to laugh at the beginning of the scene.  She said she had heard people quoting that at work, but she never realized that the Chinese name of the restaurant, which she saw at the beginning of the scene, was "And Then."&lt;br /&gt;&lt;br /&gt;Appropriately, Scala defines infinite loops in actors using andThen.  Here's how...&lt;br /&gt;&lt;br /&gt;In Scala, one way to compose functions is "f andThen g", which is the same as&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;def newFunc[T](x: T) = g(f(x))&lt;/blockquote&gt;You can think of it as "evaluate f(x) and then evaluate g with that result".  It's an easy way to chain functions and it's good for noncommutative operations, where "order matters," like matrix operations (the same type of idea you would use in implementing a safe navigation operator {quickly ducking for cover}).  For instance, if you want make a function that takes a matrix, transposes it and inverts it and then returns the determinant, you could write that like this:&lt;br /&gt;&lt;blockquote&gt;def transInv = transpose andThen invert andThen determinant&lt;br /&gt;&lt;/blockquote&gt;Those not familiar with functional programming will note the lack of arguments and return type in the definition of transInv.  TransInv gets its arg types from transpose and its return type from determinant, so you can still use transInv(myMatrix).  The definition of Function1[A, R].andThen is (here, Function1 takes an argument of type A and returns a result of type R):&lt;br /&gt;&lt;blockquote&gt;def andThen[A](g: R =&gt; A): T1 =&gt; A = { x =&gt; g(apply(x)) }&lt;/blockquote&gt;Scala defines infinite loops in actors using andThen:&lt;br /&gt;&lt;blockquote&gt;def loop(body: =&gt; Unit): Unit = body andThen loop(body)&lt;/blockquote&gt;So, if want to simulate the scene in Dude, Where's My Car?, using an actor, you can say:&lt;br /&gt;&lt;blockquote&gt;loop {choose}&lt;/blockquote&gt;which translates to:&lt;br /&gt;&lt;blockquote&gt;((_: Unit) =&gt; choose) andThen (_ =&gt; choose) andThen (_ =&gt; choose) andThen...&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-2279172273229727705?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/2279172273229727705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/09/andthen-andthen-andthen-scala-wheres-my.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/2279172273229727705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/2279172273229727705'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/09/andthen-andthen-andthen-scala-wheres-my.html' title='andThen andThen andThen... Scala, where&apos;s my car?'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-6145910889381566287</id><published>2009-09-21T00:26:00.000-07:00</published><updated>2009-09-21T01:58:34.943-07:00</updated><title type='text'>Xus: A Simple Peer-to-Peer Platform</title><content type='html'>A friend of mine wanted to implement peer-to-peer source code repositories with social networking features, like popularity ratings and such and &lt;a href="http://plubble.com/"&gt;Plexus&lt;/a&gt; was already on the way to being able to support something like that, so I decided to break out the back end of Plexus into a separate project, called Xus.  We started talking about what such a thing could do.&lt;br /&gt;&lt;br /&gt;Then the bottom fell out of Plexus.&lt;br /&gt;&lt;br /&gt;Apparently, the &lt;a href="http://www.freepastry.org/"&gt;FreePastry&lt;/a&gt; project is winding down.  It was, in my opinion, the most promising of the major peer-to-peer platforms.  It was straightforward and relatively small.  We chose it over JXTA for our communication in Plexus.  We actually started with JXTA, back in 2002, but JXTA was just too over the top with the excessive design patterns, the large surface area, the lack of a usability layer, and things of this nature.  Why does Sun seem to delight in requiring so much ritual from developers to do the simplest things with their libraries?   So Pastry is way cleaner than JXTA.  Like JXTA, Pastry was made to scale to 1000s of nodes in a cloud and had interesting routing schemes and other mechanisms to promote scalability and reliability.  We liked it a lot.  We did experience a few problems:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;An improperly configured NATted peer could royally screw up the cloud, because all of the peers take part in routing and connect directly to each other&lt;br /&gt;&lt;/li&gt;&lt;li&gt;We had to roll our own presence using our own heartbeats, because Pastry doesn't inform you when a peer disconnects and you couldn't easily enumerate the peers on a broadcast channel (publishing topic)&lt;/li&gt;&lt;/ol&gt;This is all moot now, because FreePastry is not going to be actively developed.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So I'm announcing the Xus project.  Here's the &lt;a href="http://zot.github.com/Xus/"&gt;web page&lt;/a&gt; and here's the &lt;a href="http://github.com/zot/Xus"&gt;source&lt;/a&gt;, so far.  There's a VERY simple, console-based chat to test it.  I don't have unit tests yet.  I've only been working on this for about a week and I'm not in the TDD habit.  Maybe I should be.  Anyway, because of the FreePastry news, Xus is a peer-to-peer platform and the other stuff will be services on top of it.  Here's a snippet from the doc:&lt;br /&gt;&lt;blockquote&gt;Xus is a peer-to-peer protocol with a reference implementation in Scala. The point of Xus is to provide a peer-to-peer platform that is simple, powerful, practical, and easy to use. People can use it for games, social networks, source code repositories, or whatever.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; &lt;strong&gt;Simple&lt;/strong&gt;: able to implemented with a relatively small amount of code so that it's easy to maintain and fix&lt;ul&gt;&lt;li&gt; Layered: there are 3 layers.  Layering separates the concerns of the protocol and makes it easier to understand&lt;/li&gt;&lt;li&gt; Self contained: the reference implementation does not rely on third party libraries, reducing cognitive overhead for future developers&lt;/li&gt;&lt;li&gt; Scala: reference implementation is is Scala, which allows for smaller code that is "less noisy" than Java&lt;/li&gt;&lt;li&gt; Straightforward implementation: simple, direct routing&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt; &lt;strong&gt;Powerful&lt;/strong&gt;: strong enough to support common p2p tropes and some new ones&lt;ul&gt;&lt;li&gt; Messaging: multicast, unicast, dht, and delegated and direct p2p messaging&lt;/li&gt;&lt;li&gt; Delegated messaging allows peers behind NATs to receive messages from other peers&lt;/li&gt;&lt;li&gt; File storage, backed with Git&lt;/li&gt;&lt;li&gt; Replicated properties for simple shared data&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt; &lt;strong&gt;Practical&lt;/strong&gt;&lt;ul&gt;&lt;li&gt; Medium scale allows you to know when peers disconnect&lt;/li&gt;&lt;li&gt; Works through NATs&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt; &lt;strong&gt;Easy to use&lt;/strong&gt;&lt;ul&gt;&lt;li&gt; Built-in port testing &lt;span&gt;—&lt;/span&gt; peers can request other peers to test their port configurations&lt;/li&gt;&lt;li&gt; API is small with a minimum of required setup&lt;/li&gt;&lt;li&gt; Reference implementation will include a UPnP port configuration tool (ported from the Plexus code base)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;Xus is centered around "topic spaces," which are groups of topics.  A topic space is a slice of the total peer-to-peer network, consisting of a medium amount of peers and each peer can connect to many topic spaces.  Probably 100 or fewer peers in a topic space -- depends on the app.  All of the peers in a topic space connect to the active owner, which does all of the message routing for the space.  So, if a peer wants to broadcast a message to a topic, it sends a message to the active owner of the topic's space and the owner then sends a message to each peer in the space.  Any peer can potentially be an active topic space owner if it can accept connections and it is, in fact, an owner of that topic space (Xus uses strong authentication for this kind of thing) .  Peers which can't accept connections can still participate; they just can't be &lt;span style="font-weight: bold;"&gt;active&lt;/span&gt; topic space owners.&lt;br /&gt;&lt;br /&gt;I use NIO in the reference implementation, so this routing isn't computationally intensive, but astute readers will notice that this broadcasting arrangement takes up a relatively lot of bandwidth for the active topic space owner, compared to everyone else.  Hence the "medium amount of peers".  By the way, Xus accomplishes broadcasting in a way that mirrors the most common architecture for first person shooter servers, so it CAN work extremely well (see &lt;a href="http://sauerbraten.org/"&gt;Sauerbraten&lt;/a&gt;).  There are issues and constraints, of course.&lt;br /&gt;&lt;br /&gt;See, this is just the sort of thing that Pastry was trying to avoid by having all of the peers do routing, but it was also the thing that accounted for some of the major complexity in Pastry and all of the problems we had with it.  Thus in Xus, broadcasting is limited to medium-sized groups of peers but this allows Xus to be more reliable and faster -- latency is usually much lower with this architecture.  Xus is for when you want to build a peer-to-peer app quickly and defer scalability issues to when you realize that your project has, in fact, become wildly popular.  At that point, there is nothing preventing you from making levels 1 and 2 of the Xus stack more scalable.  You'll even be able to reuse the Xus protocol, probably adding messages and attributes that are required to support routing.&lt;br /&gt;&lt;br /&gt;The protocol is XML-based and I'm using fastinfoset (which is built-in to Java) to take the fat off the wire.  This allows you to use your favorite XML tools without worrying about how bloated the communication is.  I'm using TCP for connections to simplify things.  Maybe I'll look into SCTP, but for now, it's just TCP.  The protocol is full duplex but does support request-response in cases where messages could fail, like direct p2p messages, for instance.&lt;br /&gt;&lt;br /&gt;I'm not entirely sure whether to have broadcasts return a response with a list of the nodes that failed to accept the broadcast for whatever reason (security or lack of resources, perhaps).  This sounds like it would be useful for some applications.  Right now, Plexus is what's driving the requirements.  If other developers see needs for things like this, they are welcome to jump on board the project and help out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-6145910889381566287?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/6145910889381566287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/09/xus-simple-peer-to-peer-platform.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/6145910889381566287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/6145910889381566287'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/09/xus-simple-peer-to-peer-platform.html' title='Xus: A Simple Peer-to-Peer Platform'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-5041703647596215853</id><published>2009-09-06T11:37:00.000-07:00</published><updated>2009-09-06T12:08:46.493-07:00</updated><title type='text'>Can functional programming really offer something substantial to Java?</title><content type='html'>&lt;a href="http://www.scala-lang.org/node/3069"&gt;This post on Scala-lang&lt;/a&gt; talks about research done on how the style of language affects productivity (the time it takes to understand other peoples' code).  It is specifically comparing Java with Scala.   &lt;a href="http://infoscience.epfl.ch/record/138586/files/dubochet2009coco.pdf"&gt;Here is the paper&lt;/a&gt; that the post refers to.&lt;br /&gt;&lt;br /&gt;Scala allows functional programming, as in Scheme, as opposed to procedural or object-oriented programming, as in Java, but Scala allows a nice blend of the two, which is a unique approach among programming languages.  Yes, there was LOOPS and CLOS, but Scala's approach is quite different and I think it's much a more integrated one.  There seem to be more and more posts out there about the importance of functional languages.  Personally, I agree with the premise: that functional techniques lead to denser code and that can be (if used properly) easier to understand and maintain.  Actually, this is related to one thing that I emphatically agree with the eXtreme Programming camp on: don't use accessors unless absolutely necessary (i.e. use refactoring to insert them when you have need of them).&lt;br /&gt;&lt;br /&gt;There is a controversy here, though.  Every now and then, over the years, I get extreme push-back on my coding style, because some programmers REALLY hate functional style.  They act as if it's offensive -- as if people who use functional techniques are snobs and feel they're too good to use the straightforward, meat-and-potatoes approaches that the gumshoe programmer in the street uses.  That's not it at all for me -- I use procedural techniques too.  Just not all the time; not as a golden hammer.&lt;br /&gt;&lt;br /&gt;It IS possible to use functional techniques in Java (using anonymous inner classes), but they are ugly and verbose.  Nevertheless, I use them in places where I feel they're appropriate.  Some people have complained bitterly about this in the past.  That hasn't had an impact on my code, because of my position and the unique constraints and properties of it but in other circumstances I would be forced to write in what I consider a less effective way.&lt;br /&gt;&lt;br /&gt;Maybe this attitude will change with the attention that functional languages are getting.  I was a Smalltalk programmer in the 80s and 90s, and I remember the Java hype.  A lot of Smalltalkers were saying that it would pass because it was just hype.  After all, they said, look how inferior Java is with its primitive types, substandard collection library, and skeletal GUI support, compared to Smalltalk's!  And anyway, it was just the new new thing.  I figured Java was going to eat Smalltalk's lunch.  I made noises so that people at our company got trained in Java and I made a technology that connected Smalltalk to Java so that Smalltalk could essentially use Java as a display medium, which I thought might slow Java's impact on Java (as of last year, there was still at least one Smalltalk project using that technology).&lt;br /&gt;&lt;br /&gt;Are functional languages just being hyped now as the latest attempt at a silver bullet or do they REALLY have something to offer?  I've always thought they were interesting and powerful and fun to program with.  As I mentioned before, the functional paradigm has been around a long, LONG time: Church introduced Lambda Calculus in 1932 and Turing introduced his machine in 1936.  They were both VERY different approaches to computing and the Turing Machine approach is currently "in vogue."&lt;br /&gt;&lt;br /&gt;That may change.  What if functional languages are shown to scale better in several dimensions, such as code comprehension and multithreaded programming?  I guess we'll see, but it's starting to smell that way to me.  I did a lot of programming in both LISP and Smalltalk, back in the day.  When I switched to Java, the lack of lambda in JDK 1.0.X was a real pain.  When they introduced inner classes in 1.1, things got better, but so far they really don't have the brevity of Smalltalk's blocks.&lt;br /&gt;&lt;br /&gt;Groovy and Scala have nice lambdas and Scala really focuses on functional tools.  My money's on a change that integrates functional tools into the JVM.  Maybe that'll come quickly as more and more deep pocketed groups adopt Scala.  That's how Smalltalk got mainstreamed in the 90s.  Even if Scala doesn't get super broad adoption, if high tech, high finance, and infrastructure orgs continue to adopt Scala, there will be a nice little Scala niche for a lot of people I know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-5041703647596215853?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/5041703647596215853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/09/can-functional-programming-really-offer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/5041703647596215853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/5041703647596215853'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/09/can-functional-programming-really-offer.html' title='Can functional programming really offer something substantial to Java?'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-7534716522462411478</id><published>2009-09-01T01:39:00.000-07:00</published><updated>2009-09-01T03:30:01.066-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Livecoding: connecting the dots from Lambda Calculus to Gibson's cowboys</title><content type='html'>Dot #1: Lambda Calculus...&lt;br /&gt;&lt;br /&gt;My wife and I took a vacation recently and I had a chance to learn some more Lambda Calculus; how the Y-combinator works, in particular.  At Purdue, we focused on Turing Machines and either we didn't really cover LC or I slept during that part.   If you haven't, I HIGHLY recommend learning LC.  Lambda Calculus is the most elegant system I, personally, know of (maybe that's not saying much).  You functional-types out there will already know this next part, but here's some history and stuff.&lt;br /&gt;&lt;br /&gt;It was invented by Alonzo Church, who was Turing's Ph. D. adviser (later they proved that the Lambda Calculus and Universal Turning Machines are equivalent, which was one really impressive feat).  The Y-combinator is a way to define recursive functions using only lambda binding.  Lambda binding is very simple and it's pretty much what Lambda Calculus is.  It more or less just lets you assign values to variables and then use them in an expression, like this (in LISP):&lt;br /&gt;&lt;br /&gt;( (lambda (x) (print x)) 50)&lt;br /&gt;&lt;br /&gt;(lambda (x) (print x)) is a function definition that says to print whatever x is bound to.  Using it like in the above "applies" the function to the argument by first "binding" x to the value 50 and then "evaluating" the expression (print x).  Pretty simple concept.  The trick is how to define recursive functions using this mechanism, since both the set of variables to be bound and the expression to evaluate are separate.  In order to be able to call a function, you either need to pass it in as an argument or have it defined by an "outer" function.&lt;br /&gt;&lt;br /&gt;A recursive function can't take itself as its own argument and it's also not defined in an outer scope, so it essentially has to be given a copy of itself as an argument.  The Y-combinator is a relatively clean way to do this.  I wasn't able to understand it while we were out on our vacation, because I (deliberately) left my computer at home.  Once home though, I was able to type things into LISP and play with them to finally be able to grok the combinator (hmm, "grok the combinator" sounds like some sort of euphemism).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Dot #2: Scala...&lt;br /&gt;&lt;br /&gt;So, that launched me on a journey to rediscover functional programming, since I hadn't messed with it really since the late 80s, when Roy Riggs and I (TEAM CTHULHU) were working on our MUD.  My friend, Serj, reminded me of this functional language for the JVM called Scala and told me that James Strachan wrote in a blog post that if someone had shown him the new Scala book back in 2003, he never would have written Groovy.  Groovy has been my favorite scripting language for quite a few years, because it integrates with Java so well (low barrier to adoption for Java coworkers).  So, I started messing with Scala.  I even made this blog so I could post some musings and info about my Ober project, which I updated from JavaScript to Scala.  I recoded a bunch of Groovy stuff for Dataswarm in Scala and that's worked out really well.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Dot #3: Scheme...&lt;br /&gt;&lt;br /&gt;I met this guy on a plane to Israel a few months ago.  He's in his 50s and he got his masters in education, applying virtual worlds to education.  he's not a programmer (yet), but he's been wanting to essentially "do cyberspace" for education since 1996.  He got a 17 year old Israeli programmer to work with him and make a bunch of interesting mockups.  They tried to commercialize it and whatnot, but never really got anywhere.  When I told him about Plexus (which is currently stalled, by the way), he was sort of shocked into action and really got inspired to work on his project again.  I asked him that since Plexus was open source anyway, why not build on top of it instead of from scratch?&lt;br /&gt;&lt;br /&gt;Eventually, I realized that he really needed a better way to get a feel of what's currently possible, etc. and that would require him to know something of how to program.  I looked for a good intro to pure programming, with little between him and the algorithm and that led me to PLT Scheme (&lt;a href="http://plt-scheme.org/"&gt;http://plt-scheme.org/&lt;/a&gt;).  There's a GREAT book on programming that basically plows through a few semesters of CS very quickly (How to Design Programs here: &lt;a href="http://docs.plt-scheme.org/"&gt;http://docs.plt-scheme.org/&lt;/a&gt;).  The quick intro also does graphics on the command-line, which is pretty slick, letting you define shapes that print out like smileys.  This reminded me of "the good old days" in our LISP MUD when we could type in code and change the game as it was running.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Dot #4: testing and log analysis...&lt;br /&gt;&lt;br /&gt;I've been doing a lot of log analysis with our technology at work.  We're working on making it "bullet proof" now, with the goal of being able to remove the battery from a laptop in a demo, sticking it back in, and starting back up without data loss (after the file system recovers).  This requires some heavy journaling and online backup.  Test runs can be long and produce giant diagnostic logs (0.5 - 2G).  I have to comb through these logs and find errors.  Then I have to trim them and transfer them from Kansas to my machine in Israel so I can inspect them more closely.  This takes a lot of ad-hoc scripting and the needs change after I fix each bug.  This reminds me of what we did with our MUD, because I'm "writing code as I go".  One of my hopes with the Ober project is that I can have a nice tool to do this with.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Dot #5: Gibson's cowboys...&lt;br /&gt;&lt;br /&gt;I started rereading Neuromancer and it's even MORE impressive than it was the first time I read it.  Early in the book, Armitage tells case that he was there when they "invented" Case -- i.e. when they created the software cowboys use for net running.  This reminded me of typing code "in-game" with our MUD and I remembered how cool it was to adapt the game as people were playing it.  So I was thinking that there ought to be some powerful stuff programmers could do that we might not really be doing yet.&lt;br /&gt;&lt;br /&gt;I had told Serj about PLT Scheme.  He's early in college and I'm trying to mentor him to be a guru -- I think he has the potential.  He started messing with Scheme and reading the book and sent me a link to "fluxus" http://www.pawfal.org/fluxus/  This is a "livecoding" system.  People are using this to actually code music and graphics in front of an audience: &lt;a href="http://toplap.org/uk/about/"&gt;http://toplap.org/uk/about/&lt;/a&gt;  The first vid is fairly poor and what you might fear such a performance would be like (sorry guys who made the vid), but the rest are very interesting, I think.  Again, kind of the type of thing that we used to do with our MUD.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Dot #6: livecoding in Scala...&lt;br /&gt;&lt;br /&gt;So people are working on creating systems specifically to accomodate changing programs as they run.  You could say "that's what a shell is" and you'd be right, to an extent.  Shell tools are powerful ways to slice and dice text, but for things like the log analysis I'm doing, I think I need something more like an IDE.  Something that gives programmers an environment they can use to modify code and test it in a tight loop, with access to the code, the data, and intermediate results as the program is running, like in the Haskell Hackery performance here &lt;a href="http://toplap.org/uk/about/"&gt;http://toplap.org/uk/about/&lt;/a&gt; it's well worth watching.  That's more like EMACS or WILY than a shell, I think.&lt;br /&gt;&lt;br /&gt;I'm hoping &lt;a href="http://zot.github.com/Ober-scala/"&gt;Ober&lt;/a&gt; can do something like this for Scala, backed with something like Eclipse, to get syntax highlighting, and whatnot.  One idea might be to make Ober an Eclipse plugin instead (or in addition to) a stand-alone environment.  It might be interesting to "skin" Eclipse and remove the right-button menus, replacing the behavior with &lt;a href="http://www.oberon.ethz.ch/"&gt;Oberon&lt;/a&gt; menus (or 'tags' in &lt;a href="http://www.cse.yorku.ca/%7Eoz/wily/index.html"&gt;Wily&lt;/a&gt; -- a single Oberon menu bar above all of the editors might be sufficient, with some commands to open subpanels or something).  Perhaps running in the debugger will help or ClassGhost (&lt;a href="http://classghost.sourceforge.net/"&gt;http://classghost.sourceforge.net/&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;One sticky issue is that Java can't redefine arbitrary methods in a running VM -- you can't redefine a method using a different signature as you could in Smalltalk and you can't add or remove fields.  A quick check of the new features of JDK7 doesn't show any evidence of change to these limitations.  Coding conventions would help with this (kind of like writing "structured COBOL").  As opposed to hotswapping methods, you can just "reload" a class, which defines a NEW class with the SAME name.  Production servlet hotswappers are familiar with the perils of this.&lt;br /&gt;&lt;br /&gt;Ober's command/namespace registry makes it a system like a shell or Oberon.  Indirecting through the registry instead of using hard pointers allows you to reload a class file without worrying about signatures, provided the fundamental command interface didn't change (i.e. the command itself should be the only thing keeping references to its objects).  A central storage area where commands could place simple data would allow commands to keep state that was protected from redefinition and they could be initialized with this state.&lt;br /&gt;&lt;br /&gt;So here's a simple way to get what I think would be decent support for livecoding with Scala:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;run Ober out of the debugger so you can use hotswapping when possible, using Ober to access intermediate results and as a scratchpad for data munging and Eclipse to change code&lt;br /&gt;&lt;/li&gt;&lt;li&gt;make the class loading namespace check for hints in the class, like annotations for namespaces and such&lt;/li&gt;&lt;li&gt;provide per-command data storage from the Ober object (a trait can make this even easier to access)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;make a Reload command as a fallback for when hotswapping doesn't work&lt;/li&gt;&lt;li&gt;make a log that appends useful Ober commands, such as prefilled Reload commands and access to previous command results and provide easy access to this from the Ober object and a command to show the log&lt;/li&gt;&lt;li&gt;keep commands clean -- don't hold references to other commands' objects; go through the command registery to get them&lt;/li&gt;&lt;li&gt;simplify access to the command registry to make it simple for commands to use it to access each other&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-7534716522462411478?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/7534716522462411478/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/09/livecoding-connecting-dots-from-lambda.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/7534716522462411478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/7534716522462411478'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/09/livecoding-connecting-dots-from-lambda.html' title='Livecoding: connecting the dots from Lambda Calculus to Gibson&apos;s cowboys'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-3142188807801259513</id><published>2009-08-28T01:18:00.000-07:00</published><updated>2009-08-28T01:25:30.436-07:00</updated><title type='text'>Whimsical Jerusalem Pedestrian Crossing Signs</title><content type='html'>I noticed these in walking around in Jerusalem and I haven't seen a lot about them on the web yet, so I thought I'd post them.  The last one's a fake, obviously put up by a concerned citizen who thought that werewolves weren't getting the representation they deserved.  There are several more that I haven't photographed, including at least 2 more fakes: a man dragging a baby, and an angel as well as at least two authentic ones, a man with one hand in a fist and the other with fingers spread and a fat man.  I'll post those eventually.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_ff5WPTRrotc/SpeTrEbTZHI/AAAAAAAAAAk/tusAJuMiFNM/s1600-h/img_0311.jpg"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_ff5WPTRrotc/SpeTrEbTZHI/AAAAAAAAAAk/tusAJuMiFNM/s320/img_0311.jpg" alt="" id="BLOGGER_PHOTO_ID_5374927048421893234" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_ff5WPTRrotc/SpeTq2HIGAI/AAAAAAAAAAc/eBjcRVpWnqo/s1600-h/img_0310.jpg"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_ff5WPTRrotc/SpeTq2HIGAI/AAAAAAAAAAc/eBjcRVpWnqo/s320/img_0310.jpg" alt="" id="BLOGGER_PHOTO_ID_5374927044579170306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_ff5WPTRrotc/SpeTqalALzI/AAAAAAAAAAU/VmJhwc1Kk6o/s1600-h/img_0309.jpg"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_ff5WPTRrotc/SpeTqalALzI/AAAAAAAAAAU/VmJhwc1Kk6o/s320/img_0309.jpg" alt="" id="BLOGGER_PHOTO_ID_5374927037188288306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_ff5WPTRrotc/SpeTp_0UAOI/AAAAAAAAAAM/roduKzhO_4M/s1600-h/img_0308.jpg"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_ff5WPTRrotc/SpeTp_0UAOI/AAAAAAAAAAM/roduKzhO_4M/s320/img_0308.jpg" alt="" id="BLOGGER_PHOTO_ID_5374927030004744418" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-3142188807801259513?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/3142188807801259513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/08/whimsical-jerusalem-pedestrian-crossing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/3142188807801259513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/3142188807801259513'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/08/whimsical-jerusalem-pedestrian-crossing.html' title='Whimsical Jerusalem Pedestrian Crossing Signs'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_ff5WPTRrotc/SpeTrEbTZHI/AAAAAAAAAAk/tusAJuMiFNM/s72-c/img_0311.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-2106188055362004660</id><published>2009-08-20T08:59:00.000-07:00</published><updated>2009-08-20T09:08:34.869-07:00</updated><title type='text'>Streamlining Ober</title><content type='html'>I made some changes to Ober that make it quicker to use.  Now, when you right-click a word, Ober does everything in path-like fashion:&lt;div&gt;&lt;ol&gt;&lt;li&gt;if the word is an Ober built-in, execute it&lt;/li&gt;&lt;li&gt;if the word is a class name, run the main with the args to end of line&lt;/li&gt;&lt;li&gt;if the word is a shell command, run it&lt;/li&gt;&lt;li&gt;if the word is a file, directory, or URL, open it&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;If you middle click, that sets a hint to tell the command that if it is appropriate, open a new viewer instead of replacing the current one.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also, I made a runnable jar for it all, so you don't have to build it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's the new &lt;a href="http://zot.github.com/Ober-scala/"&gt;doc page&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-2106188055362004660?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/2106188055362004660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/08/streamlining-ober.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/2106188055362004660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/2106188055362004660'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/08/streamlining-ober.html' title='Streamlining Ober'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-3075060090478011702</id><published>2009-07-27T00:44:00.000-07:00</published><updated>2009-07-27T01:05:15.782-07:00</updated><title type='text'>The power of text</title><content type='html'>After spending 4 or 5 years working on servers with decent amounts of data going through them, I've had to do a fair bit of forensic work with saved databases, giant log files, etc.  AWK, sed, Groovy, EMACS, and their kin have been my friends.  You can use them to distill unstructured text into a structured form for summaries, trending, etc.&lt;br /&gt;&lt;br /&gt;I am starting to turn Ober into a console for this type of forensic work.  I can see how farsighted Niklaus Wirth was when he made Oberon.  This doesn't look to me like a temporary phase in computing.  If anything, unstructured text is even more prevalent today than it has been in the past.  Google has shown people what you can do with it.  We'll see where Ober goes from here.&lt;br /&gt;&lt;br /&gt;For the future, I'm planning on adding some more Wily-like features to Ober, like preceding commands with |, &lt;, and &gt;.  Here's an update on Ober...&lt;br /&gt;&lt;br /&gt;Ober is becoming usable now.  Here are the items I checked off of the list from the last post:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;execute HOME/.oberrc on startup (if it exists)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Scala expressions embedded in {...}&lt;/li&gt;&lt;li&gt;ctrl-click opens a file.  Actually, it tells the namespaces to "surf", so surfing depends on the namespaces your viewer is using&lt;br /&gt;&lt;/li&gt;&lt;li&gt;fixed redraw bug&lt;/li&gt;&lt;/ul&gt;I also added some cosmetic commands, like TrackPos, Width, ViewerPos, and Height.&lt;br /&gt;&lt;br /&gt;Using the context-sensitive surfing, I made a "data browser" to examine some object databases I use.  It was pretty simple, since I could already dump objects and display the guids of the objects they reference, so when you ctrl-click on a guid, it goes to the viewer for that object (or creates it) where it displays the dump of that object.  If you type things or mess up the text and you want to redisplay, you just ctrl-click on the viewer name and it refreshes.&lt;br /&gt;&lt;br /&gt;Here is the Ober's current &lt;a href="http://github.com/zot/Ober-scala/tree/master"&gt;source code&lt;/a&gt; and here is Ober's current &lt;a href="http://zot.github.com/Ober-scala/"&gt;help page&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-3075060090478011702?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/3075060090478011702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/07/power-of-text.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/3075060090478011702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/3075060090478011702'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/07/power-of-text.html' title='The power of text'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-3222233614150347561</id><published>2009-07-22T05:30:00.000-07:00</published><updated>2009-07-22T06:53:38.529-07:00</updated><title type='text'>A tribute to Niklaus Wirth</title><content type='html'>If you haven't heard of Niklaus Wirth's &lt;a href="http://www.oberon.ethz.ch/"&gt;Oberon&lt;/a&gt; or you haven't seen it, you should check it out.  Messing with it reminded me of when I first learned Smalltalk in 1988.  There's an air of playfulness and potential to it, just like in Smalltalk-80.  The current version of Smalltalk is called &lt;a href="http://squeak.org/"&gt;Squeak&lt;/a&gt; and it's well worth checking out as well.&lt;br /&gt;&lt;br /&gt;Oberon is sort of a Pascal take on Smalltalk.  Like Smalltalk, it's both a language and an environment.  Like Smalltalk, it has built-in programming tools (compiler, editor, etc), and it's interactive; you're programming "in" the language, so the edit-compile-run cycle is VERY tight (like when you're using the scala command and you can evaluate expressions).  Oberon's environment was similar to Smalltalk's, but had some major differences and innovations, the most valuable one being (in my opinion) that you can click on a word anywhere in the environment and it will attempt to execute it as a command.  There are other innovations too, but that's my favorite.&lt;br /&gt;&lt;br /&gt;Harnessing this capability, Rob Pike at AT&amp;amp;T based a text editor/shell on Oberon as part of Plan 9, called &lt;a href="http://en.wikipedia.org/wiki/Acme_%28text_editor%29"&gt;Acme&lt;/a&gt;.  Then, Gary Capell made &lt;a href="http://en.wikipedia.org/wiki/Wily"&gt;Wily&lt;/a&gt; for Unix.  Then, in 2002, I made one based on Wily for Ruby, called &lt;a href="http://sourceforge.net/projects/p2pmud/files/"&gt;Meep&lt;/a&gt;.  And THEN, I rewrote it in Java and renamed it "&lt;a href="http://ober.sourceforge.net/"&gt;Ober&lt;/a&gt;," to point back to Oberon (and because ober means "waiter" in German).  Somewhere along the line, I don't remember whether it was in Meep or just Ober, I added a "namespace" twist, to allow scoped commands, like Oberon has, but identified in the "tag" of the viewer (the text field at the top of the viewer which contains handy commands).&lt;br /&gt;&lt;br /&gt;So.  Time for another rewrite.  Here's &lt;a href="http://github.com/zot/Ober-scala/tree/master"&gt;Ober-scala&lt;/a&gt; now.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://zot.github.com/Ober-scala/ober-scala.jpg"&gt;&lt;img style="cursor: pointer; width: 230px; height: 218px;" src="http://zot.github.com/Ober-scala/ober-scala.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It's two eclipse projects, one Java, and one Scala 2.8 (I'm having trouble with Java and Scala in the same project).  To run it, just use the "Scala Ober" launcher that's in the scala project.   There's a LOT of room for improvement, of course, but it functions, at least.  On Linux.  I haven't tested it on Windows.  Sorry Windows :(.  It's not that I think Windows sucks, it's just that I don't use it and it's pretty inconvenient for me to mess with it on my current setup.&lt;br /&gt;&lt;br /&gt;Why did I do this?  I wanted a "programmer's workbench" that was a combination program runner, simple editor, and shell.  You know, like &lt;a href="http://www.gnu.org/software/emacs/"&gt;EMACS&lt;/a&gt;, but by Scala and for Scala.  And the Oberon environment is very cool.  When I read that Martin Odersky &lt;a href="http://www.artima.com/scalazine/articles/origins_of_scala.html"&gt;studied under Niklaus Wirth&lt;/a&gt;, I figured, hey, maybe some Scala people would be interested in this thing too.  We'll see.&lt;br /&gt;&lt;br /&gt;What can it do?  If you righth-click a word, it will try to execute it as a command.  At this point, there are 3 types of namespaces:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;closure namespaces, which look up named closures&lt;/li&gt;&lt;li&gt;class namespaces, which look up classes&lt;/li&gt;&lt;li&gt;system namespaces, which look up shell commands&lt;/li&gt;&lt;/ol&gt;So, you can test it by right-clicking on some of the words that are already there when you start it (like New, Newcol, Del, Quit, ...).  You can type in the name of a class in your class path and right-click on that (like tc.ober.Test, for instance); it will split the rest of the line by spaces and send the strings to the main method of the class.  You can type in a shell command and right-click that; it will execute the word plus the rest of the line as a system command (using Runtime's exec(String) method).&lt;br /&gt;&lt;br /&gt;What's left?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;execute .oberrc on startup&lt;/li&gt;&lt;li&gt;Scala commands embedded in {...}&lt;/li&gt;&lt;li&gt;file handling (crtl-click on a word and it opens as a file).  See Wily for this behavior.&lt;/li&gt;&lt;li&gt;meta commands for your .oberrc (commands to define commands, etc.)&lt;/li&gt;&lt;li&gt;classpath manipulation&lt;/li&gt;&lt;li&gt;fix bugs (like when you delete the last viewer in a track, it doesn't redraw)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Happy hacking!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-3222233614150347561?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/3222233614150347561/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/07/tribute-to-niklaus-wirth.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/3222233614150347561'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/3222233614150347561'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/07/tribute-to-niklaus-wirth.html' title='A tribute to Niklaus Wirth'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-7045092805786138304</id><published>2009-07-17T16:01:00.001-07:00</published><updated>2009-07-17T16:23:49.363-07:00</updated><title type='text'>Safe navigaion in Scala, the aftermath</title><content type='html'>Wow, I sure stirred up a hornet's nest with my safe navigation experiment.  Some people posted some very useful information and good alternative approaches!&lt;br /&gt;&lt;br /&gt;As for comments about "ugliness", being able to read this in 6 months, etc.; I'm not making a policy decision here, just experimenting.  The fact that people are so put off by experimentation makes me wonder...  Anyway, we'll see if it comes in handy or not.  Things like this can easily be "compiled" by the mind as "programming idioms".&lt;br /&gt;&lt;br /&gt;But as for unreadable, it's only a cascade of lambdas, after all.  Personally, I've been very comfortable with functional style, since I first learned LISP, freshman year in college.  It's amazing to me how emotional some programmers get when they see code using functional style.  Does this mean "imperative -&gt; good, functional -&gt; bad?"&lt;br /&gt;&lt;br /&gt;I guess there's always been a divide between functional and imperative approaches.  I'm glad Church and Turing could see that their different approaches were accomplishing the same thing.  I really think more universities should teach functional languages in their freshman level courses, before people have a chance to ingrain imperative as the one true way.  My university (Purdue) did not; I just happened to learn it from a friend, because I was interested in what LISP was and how to use it.  At the time, I was amazed (and a bit envious) to find out that some universities taught LISP or Scheme to freshmen.&lt;br /&gt;&lt;br /&gt;I think LISP and Scheme are excellent first languages, because they abstract computation away from the machine; they don't encourage you to simulate a computer in your head when you write code.  Simulating a stack machine can be a great barrier to actually understanding recursion and higher order functions.  Freshman and sophomore year, I helped quite a few students learn recursion, but I had to "unteach" the technique of "stack simulation" first, so they actually had a chance of understanding something like A-B recursion or composite recursion.&lt;br /&gt;&lt;br /&gt;It's interesting, because I just started teaching a guy to program last week, and I chose to start with Scheme (although eventually he probably needs to learn Java).  I found good site with some basic tutorials and a free book on programming that actually teaches recursion the way I taught it freshman year, way back in 1984.  It looks like I'm not the only one with those ideas about how to teach recursion.&lt;br /&gt;&lt;br /&gt;For those interested, here's the &lt;a href="http://plt-scheme.org/"&gt;PLaneT Scheme Site&lt;/a&gt; and here's the &lt;a href="http://www.htdp.org/"&gt;book&lt;/a&gt; (linked from their site as well).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-7045092805786138304?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/7045092805786138304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/07/safe-navigaion-in-scala-aftermath.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/7045092805786138304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/7045092805786138304'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/07/safe-navigaion-in-scala-aftermath.html' title='Safe navigaion in Scala, the aftermath'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-5259652112515398125</id><published>2009-07-16T15:30:00.000-07:00</published><updated>2009-07-17T01:21:02.423-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Safe navigaion in Scala, take 2</title><content type='html'>OK, revisiting this topic after a very short time, I have a new implementation, again using that interesting anonymous class technique from James Iry's comment:&lt;pre&gt;implicit def richOption[T](x : T) = new {&lt;br /&gt; def ??[B](f : T =&gt; B):B = if (x != null) f(x) else null.asInstanceOf[B]&lt;br /&gt;}&lt;/pre&gt;I changed the operator from "?!" to "??" because that's a lot easier to type and I chose "??" instead of "?" so people wouldn't confuse it with the questi-colon operator from Java and C. It's stand-alone (doesn't depend on Option or anything) and I had to use a cast to get the types to work out properly, but the test case from my &lt;a href="http://this-statement-is-false.blogspot.com/2009/07/safe-navigation-operators-for-scala.html"&gt;last post&lt;/a&gt; does work&lt;pre&gt;println(p3??(_.bud)??(_.bud)??(_.bud)??(_.name.drop(1)))&lt;/pre&gt;prints null and&lt;pre&gt;println(p3??(_.bud)??(_.bud)??(_.name.drop(1)))&lt;/pre&gt;prints ubba.&lt;br /&gt;&lt;br /&gt;For those new to Scala, the expressions in parentheses are anonymous functions because they use "_" as identifiers.  (_.bud) expands to (x =&gt; x.bud), where Scala chooses an x that is unique in the scope of the expression.  Of course, you can put whatever you want in the final block there, or the other blocks.  You could say this instead&lt;pre&gt;p3??(_.bud)??(_.bud)??(x =&gt; println(x.name.drop(1)))&lt;/pre&gt;You might want to do this if you only want to print provided that the full path exists for instance, which demonstrates that this construct is more powerful than Groovy's, because each step can be more than just another increment along the path.&lt;br /&gt;&lt;br /&gt;This has an advantage over the previous solutions of not requiring the ! operator at the end to extract the value out of the option because the ?? operator returns a raw value instead of an Option.  Not having used Scala for more than a week (I haven't even used LISP since the late 80s), I can't speak as an authority on when it's appropriate to use Options, but this seems to me like an alternative to Option for at least some cases.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-5259652112515398125?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/5259652112515398125/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/07/safe-navigaion-in-scala-take-2.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/5259652112515398125'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/5259652112515398125'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/07/safe-navigaion-in-scala-take-2.html' title='Safe navigaion in Scala, take 2'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5681827487565088993.post-5526262942975811354</id><published>2009-07-16T06:11:00.000-07:00</published><updated>2009-07-16T16:05:39.310-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Safe navigation operators for Scala</title><content type='html'>Welcome to my first blog post.&lt;br /&gt;&lt;br /&gt;I searched the net for a Scala analog to Groovy's safe navigation, but I didn't find anything, so I made my own.  It's like a monad but I haven't thought much about the implications of really making it into a real monad so I haven't monadized it at this point.&lt;br /&gt;&lt;br /&gt;Here is some example data to demonstrate how you use these safe navigation operators in Scala:&lt;pre&gt;case class Person(var name: String, var bud: Person = null)&lt;br /&gt;&lt;br /&gt;val p1 = new Person("bubba")&lt;br /&gt;val p2 = new Person("fred", p1)&lt;br /&gt;val p3 = new Person("mary", p2)&lt;br /&gt;&lt;br /&gt;println(opt(p3)?!(_.bud)?!(_.bud)!(_.name.drop(1)))&lt;/pre&gt;This code prints "ubba".  It uses ?! like Groovy's ?. operator (?. isn't a legal operator in Scala because of the .), but you need the extra parentheses or it doesn't parse like you would want (I think Scala needs the parentheses to disambiguate the scope for the _).  The final ! operator returns the closure value instead of wrapping it with an OptionalRef.&lt;br /&gt;&lt;br /&gt;If you go one more step, you'll get () as the return value:&lt;pre&gt;println(opt(p3)?!(_.bud)?!(_.bud)?!(_.bud)!(_.name.drop(1)))&lt;/pre&gt;That code prints "()". If you don't like the first opt(Any) and you want to do implicit conversions, you can import OptionalRef.Implicit._&lt;br /&gt;&lt;br /&gt;So, it's noisier than Groovy, but a lot less noisy than nested "if" expressions.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here's the code, modified from James Iry's comment:&lt;pre&gt;def notNull[T](x : T) = if (x == null) None else Some(x)&lt;br /&gt;implicit def richOption[T](x : Option[T]) = new {&lt;br /&gt;  def ?![B](f : T =&gt; B) = notNull(f(x get))&lt;br /&gt;  def ![B](f : T =&gt; B) = if (x isDefined) f(x get)&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I like that much better than my old, slightly longer, code :)&lt;pre&gt;object OptionalRef {&lt;br /&gt; object Implicit {&lt;br /&gt;  implicit def obj2OptionalRef[T &lt;: Object](input: T): OptionalRef[T] = {&lt;br /&gt;    if (input == null) NoRef else Ref(input)&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; def opt[T](obj: T) = Ref[T](obj)&lt;br /&gt; abstract class OptionalRef[+T] {&lt;br /&gt;  def isEmpty: Boolean&lt;br /&gt;  def ?![U](st: (T) =&gt; U): OptionalRef[U] = {&lt;br /&gt;   (if (isEmpty) NoRef else st(get)) match {&lt;br /&gt;    case r: OptionalRef[U] =&gt; r&lt;br /&gt;    case null =&gt; NoRef&lt;br /&gt;    case o: U =&gt; Ref(o)&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  def !(block: (T) =&gt; Any): Any = if (!isEmpty) block(get)&lt;br /&gt;  def get: T&lt;br /&gt; }&lt;br /&gt; class Ref[+T](x: T) extends OptionalRef[T] {&lt;br /&gt;  def isEmpty = false&lt;br /&gt;  def get = x&lt;br /&gt;  override def toString = "Ref(" + get + ")"&lt;br /&gt; }&lt;br /&gt; object Ref {&lt;br /&gt;  def apply[T](obj: T) = new Ref(obj)&lt;br /&gt; }&lt;br /&gt; object NoRef extends OptionalRef[Nothing] {&lt;br /&gt;  def isEmpty = true&lt;br /&gt;  def get = throw new NoSuchElementException("NoRef.value")&lt;br /&gt;  override def toString = "NoRef"&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5681827487565088993-5526262942975811354?l=this-statement-is-false.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://this-statement-is-false.blogspot.com/feeds/5526262942975811354/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/07/safe-navigation-operators-for-scala.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/5526262942975811354'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5681827487565088993/posts/default/5526262942975811354'/><link rel='alternate' type='text/html' href='http://this-statement-is-false.blogspot.com/2009/07/safe-navigation-operators-for-scala.html' title='Safe navigation operators for Scala'/><author><name>Bill Burdick</name><uri>http://www.blogger.com/profile/15663826315808273049</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry></feed>
