<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>pydisco/disco/error.py</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -35,7 +35,7 @@ init(_Args) -&gt;
         % disco_worker processes.
         ets:new(active_workers, [named_table, public]),
 
-        % node_laod records how many disco_workers there are
+        % node_load records how many disco_workers are
         % running on a node (could be found in active_workers
         % as well). This table exists mainly for convenience and
         % possibly for performance reasons.</diff>
      <filename>master/src/disco_server.erl</filename>
    </modified>
    <modified>
      <diff>@@ -3,8 +3,7 @@ import re, traceback, tempfile, struct, random
 from disco.util import\
     parse_dir, load_conf, err, data_err, msg, resultfs_enabled, load_oob
 from disco.func import re_reader, netstr_reader
-from disco.netstring import *
-from disconode.util import *
+from disconode.util import ensure_path, safe_append, write_files
 from disconode import external
 from disco import comm
 
@@ -160,7 +159,7 @@ def connect_input(input):
         else:
                 return open_remote(input, ext_host, ext_file)
 
-class MapOutput:
+class MapOutput(object):
         def __init__(self, part, params, combiner = None):
                 self.combiner = combiner
                 self.params = params
@@ -193,7 +192,7 @@ class MapOutput:
                 os.rename(self.fname + &quot;.partial&quot;, self.fname)
         
 
-class ReduceOutput:
+class ReduceOutput(object):
         def __init__(self, params):
                 self.fname = REDUCE_OUTPUT % this_partition()
                 self.params = params
@@ -216,7 +215,7 @@ def num_cmp(x, y):
                 pass
         return cmp(x, y)
 
-class ReduceReader:
+class ReduceReader(object):
         def __init__(self, input_files, do_sort, mem_sort_limit):
                 self.inputs = []
                 part = PART_SUFFIX % this_partition()</diff>
      <filename>node/disconode/disco_worker.py</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,9 @@
 import os, os.path, time, struct, marshal
-from subprocess import *
+from subprocess import Popen, PIPE
 from disco.netstring import decode_netstring_str
-from disconode.util import *
+from disconode.util import write_files
 from disco.util import msg
+from disco.error import DiscoError
 
 MAX_ITEM_SIZE = 1024**3
 MAX_NUM_OUTPUT = 1000000
@@ -16,11 +17,11 @@ def pack_kv(k, v):
 def unpack_kv():
         le = struct.unpack(&quot;I&quot;, out_fd.read(4))[0]
         if le &gt; MAX_ITEM_SIZE:
-                raise &quot;External key size exceeded: %d bytes&quot; % le
+                raise DiscoError(&quot;External key size exceeded: %d bytes&quot; % le)
         k = out_fd.read(le)
         le = struct.unpack(&quot;I&quot;, out_fd.read(4))[0]
         if le &gt; MAX_ITEM_SIZE:
-                raise &quot;External key size exceeded: %d bytes&quot; % le
+                raise DiscoError(&quot;External key size exceeded: %d bytes&quot; % le)
         v = out_fd.read(le)
         return k, v
 
@@ -48,14 +49,14 @@ def ext_reduce(red_in, red_out, params):
         while True:
                 for fd, event in p.poll():
                         if event &amp; (select.POLLNVAL | select.POLLERR):
-                                raise &quot;Pipe to the external process failed&quot;
+                                raise DiscoError(&quot;Pipe to the external process failed&quot;)
                         elif event &amp; select.POLLIN:
                                 num = struct.unpack(&quot;I&quot;,
                                         external.out_fd.read(4))[0]
                                 if num &gt; MAX_NUM_OUTPUT:
-                                        raise &quot;External output limit &quot;\
+                                        raise DiscoError(&quot;External output limit &quot;\
                                                 &quot;exceeded: %d &gt; %d&quot; %\
-                                                (num, MAX_NUM_OUTPUT)
+                                                (num, MAX_NUM_OUTPUT))
                                 for i in range(num):
                                         red_out.add(*external.unpack_kv())
                                         tt += 1</diff>
      <filename>node/disconode/external.py</filename>
    </modified>
    <modified>
      <diff>@@ -6,9 +6,9 @@ def ensure_path(path, check_exists = True):
                 err(&quot;File exists: %s&quot; % path)
         if os.path.isfile(path):
                 os.remove(path)
-        dir, fname = os.path.split(path)
+        dirpath, fname = os.path.split(path)
         try:
-                os.makedirs(dir)
+                os.makedirs(dirpath)
         except OSError, x:
                 if x.errno == 17:
                         # File exists is ok, it may happen</diff>
      <filename>node/disconode/util.py</filename>
    </modified>
    <modified>
      <diff>@@ -1,24 +0,0 @@
-import sys
-from types import FunctionType
-from core import Disco, Params, result_iterator
-import func
-
-class DeprecatedFunc:
-        def __init__(self, fun, name):
-                self.fun = fun
-                self.name = name
-
-        def __getattr__(self, name):
-                if name == &quot;func_code&quot;:
-                        print &gt;&gt; sys.stderr, &quot;WARNING! disco.%s is &quot;\
-                                &quot;deprecated. Use disco.func.%s instead.&quot;\
-                                        % (self.name, self.name)
-                        return self.fun.func_code
-                raise AttributeException(&quot;%s not found&quot; % name)
-
-chain_reader = DeprecatedFunc(func.chain_reader, &quot;chain_reader&quot;)
-
-def job(master, name, input, fun_map = None, **kw):
-        kw.update({&quot;name&quot;: name, &quot;input&quot;: input})
-        kw[&quot;map&quot;] = kw.get(&quot;map&quot;, fun_map)
-        return Disco(master).new_job(**kw).wait(clean = kw.get(&quot;clean&quot;, True))</diff>
      <filename>pydisco/disco/__init__.py</filename>
    </modified>
    <modified>
      <diff>@@ -4,11 +4,24 @@ nocurl = &quot;nocurl&quot; in os.environ.get(&quot;DISCO_FLAGS&quot;, &quot;&quot;).lower().split()
 
 try:
         import pycurl
-except:
+except ImportError:
         nocurl = True
 
 if nocurl:
-        from comm_httplib import *
+        from disco.comm_httplib import *
 else:
-        from comm_curl import *
+        from disco.comm_curl import *
 
+# get rid of this for python2.6+
+try:
+        import json
+except ImportError:
+        try:
+                import simplejson as json
+        except ImportError:
+                import cjson
+                class Dummy(object):
+                        pass
+                json = Dummy()
+                json.loads = cjson.decode
+                json.dumps = cjson.encode</diff>
      <filename>pydisco/disco/comm.py</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-import httplib, urllib2, cStringIO, struct
+import httplib, urllib
 
 http_pool = {}
 </diff>
      <filename>pydisco/disco/comm_httplib.py</filename>
    </modified>
    <modified>
      <diff>@@ -1,19 +1,10 @@
-import sys, re, os, marshal, cjson, time, cPickle, types, cStringIO
-from disco import func, util, comm, modutil, eventmonitor
-from netstring import *
-
-class JobException(Exception):
-        def __init__(self, msg, master, name):
-                self.msg = msg
-                self.name = name
-                self.master = master
-
-        def __str__(self):
-                return &quot;Job %s/%s failed: %s&quot; %\
-                        (self.master, self.name, self.msg)
-
+import sys, re, os, marshal, time, cPickle
+from disco import func, util, comm
+from disco.comm import json
+from disco.error import DiscoError, JobException
+from disco.netstring import encode_netstring_fd, decode_netstring_fd
 
-class Params:
+class Params(object):
         def __init__(self, **kwargs):
                 self._state = {}
                 for k, v in kwargs.iteritems():
@@ -56,22 +47,24 @@ class Disco(object):
         def __init__(self, host):
                 self.host = &quot;http://&quot; + util.disco_host(host)[7:]
 
-        def request(self, url, data = None, redir = False, offset = 0):
-                return comm.download(self.host + url,\
-                        data = data, redir = redir, offset = offset)
-        
+        def request(self, url, data = None, redir = False):
+                try:
+                        return comm.download(self.host + url, data = data, redir = redir)
+                except comm.CommException, msg:
+                        raise DiscoError(&quot;Failed to fetch %r, data of len %r, redir=%r. Error was %s&quot; % (self.host + url, len(data), redir, msg))
+
         def nodeinfo(self):
-                return cjson.decode(self.request(&quot;/disco/ctrl/nodeinfo&quot;))
+                return json.loads(self.request(&quot;/disco/ctrl/nodeinfo&quot;))
 
         def joblist(self):
-                return cjson.decode(self.request(&quot;/disco/ctrl/joblist&quot;))
+                return json.loads(self.request(&quot;/disco/ctrl/joblist&quot;))
         
         def oob_get(self, name, key):
                 try:
                         return util.load_oob(self.host, name, key)
                 except comm.CommException, x:
                         if x.http_code == 404:
-                                raise KeyError(&quot;Unknown key or job name&quot;)
+                                raise DiscoError(&quot;Unknown key or job name&quot;)
                         raise
         
         def oob_list(self, name):
@@ -80,9 +73,9 @@ class Disco(object):
                                 redir = True)
                 except comm.CommException, x:
                         if x.http_code == 404:
-                                raise KeyError(&quot;Unknown key or job name&quot;)
+                                raise DiscoError(&quot;Unknown key or job name&quot;)
                         raise
-                return cjson.decode(r)
+                return json.loads(r)
 
         def profile_stats(self, name, mode = &quot;&quot;):
                 import pstats
@@ -125,8 +118,8 @@ class Disco(object):
                                 if not len(l):
                                         continue
                                 try:
-                                        ent = tuple(cjson.decode(l))
-                                except cjson.DecodeError:
+                                        ent = tuple(json.loads(l))
+                                except ValueError:
                                         break
                                 # HTTP range request doesn't like empty ranges:
                                 # Let's ensure that at least the last newline
@@ -158,10 +151,10 @@ class Disco(object):
                                 nam.append(n.name)
                
                 r = self.request(&quot;/disco/ctrl/get_results&quot;,
-                        cjson.encode([timeout, nam]))
+                        json.dumps([timeout, nam]))
                 if not r:
                         return None
-                r = cjson.decode(r)
+                r = json.loads(r)
                 if single:
                         return r[0][1]
                 else:
@@ -177,7 +170,7 @@ class Disco(object):
         def jobinfo(self, name):
                 r = self.request(&quot;/disco/ctrl/jobinfo?name=&quot; + name)
                 if r:
-                        return cjson.decode(r)
+                        return json.loads(r)
                 else:
                         return r
 
@@ -244,9 +237,9 @@ class Job(object):
         def __init__(self, master, **kwargs):
                 self.master = master
                 if &quot;name&quot; not in kwargs:
-                        raise Exception(&quot;Argument name is required&quot;)
+                        raise DiscoError(&quot;Argument name is required&quot;)
                 if re.search(&quot;\W&quot;, kwargs[&quot;name&quot;]):
-                        raise Exception(&quot;Only characters in [a-zA-Z0-9_] &quot;\
+                        raise DiscoError(&quot;Only characters in [a-zA-Z0-9_] &quot;\
                               &quot;are allowed in the job name&quot;)
                 self.name = &quot;%s@%d&quot; % (kwargs[&quot;name&quot;], int(time.time()))
                 self._run(**kwargs)
@@ -276,17 +269,17 @@ class Job(object):
                         kw[&quot;input&quot;] = kw[&quot;input_files&quot;]
 
                 if &quot;chunked&quot; in kw:
-                        raise Exception(&quot;Argument 'chunked' is deprecated&quot;)
+                        raise DiscoError(&quot;Argument 'chunked' is deprecated&quot;)
                 
                 if not &quot;input&quot; in kw:
-                        raise Exception(&quot;input is required&quot;)
+                        raise DiscoError(&quot;input is required&quot;)
                 
                 if not (&quot;map&quot; in kw or &quot;reduce&quot; in kw):
-                        raise Exception(&quot;Specify map and/or reduce&quot;)
+                        raise DiscoError(&quot;Specify map and/or reduce&quot;)
                 
                 for p in kw:
                         if p not in Job.defaults:
-                                raise Exception(&quot;Unknown argument: %s&quot; % p)
+                                raise DiscoError(&quot;Unknown argument: %s&quot; % p)
 
                 inputs = kw[&quot;input&quot;]
 
@@ -382,7 +375,7 @@ class Job(object):
                         red_inputs = []
                         for inp in inputs:
                                 if type(inp) == list:
-                                        raise Exception(&quot;Reduce doesn't &quot;\
+                                        raise DiscoError(&quot;Reduce doesn't &quot;\
                                                 &quot;accept redundant inputs&quot;)
                                 elif inp.startswith(&quot;dir://&quot;):
                                         if inp.endswith(&quot;.txt&quot;):
@@ -393,26 +386,26 @@ class Job(object):
                                         ext_inputs.append(inp)
 
                         if ext_inputs and red_inputs:
-                                raise Exception(&quot;Can't mix partitioned &quot;\
+                                raise DiscoError(&quot;Can't mix partitioned &quot;\
                                         &quot;inputs with other inputs&quot;)
                         elif red_inputs:
                                 q = lambda x: int(x.split(&quot;:&quot;)[-1]) + 1
                                 nr_red = q(red_inputs[0])
                                 for x in red_inputs:
                                         if q(x) != nr_red:
-                                                raise Exception(\
+                                                raise DiscoError(\
                                                 &quot;Number of partitions must &quot;\
                                                 &quot;match in all inputs&quot;)
                                 n = d(&quot;nr_reduces&quot;) or nr_red
                                 if n != nr_red:
-                                        raise Exception(
+                                        raise DiscoError(
                                         &quot;Specified nr_reduces = %d but &quot;\
                                         &quot;number of partitions in the input &quot;\
                                         &quot;is %d&quot; % (n, nr_red))
                                 kw[&quot;nr_reduces&quot;] = nr_red
                                 inputs = red_inputs
                         elif d(&quot;nr_reduces&quot;) != 1:
-                                raise Exception(&quot;nr_reduces must be 1 when &quot;\
+                                raise DiscoError(&quot;nr_reduces must be 1 when &quot;\
                                         &quot;using non-partitioned inputs &quot;\
                                         &quot;without the map phase&quot;)
                         else:
@@ -459,7 +452,7 @@ class Job(object):
                 reply = self.master.request(&quot;/disco/job/new&quot;, self.msg)
                         
                 if reply != &quot;job started&quot;:
-                        raise Exception(&quot;Failed to start a job. Server replied: &quot; + reply)
+                        raise DiscoError(&quot;Failed to start a job. Server replied: &quot; + reply)
 
 
 </diff>
      <filename>pydisco/disco/core.py</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,7 @@
-import sys, cjson
+import sys
 from os import environ
+from disco.comm import json
+from disco.error import DiscoError
 
 # Following from Python cookbook, #475186
 def has_colors(stream):
@@ -27,7 +29,7 @@ class EventMonitor(object):
                         self.name = name
 
                 if not disco:
-                        raise Exception(&quot;Specify either job or disco and name&quot;)
+                        raise DiscoError(&quot;Specify either job or disco and name&quot;)
 
                 self.offset = 0
                 self.output = None
@@ -101,7 +103,7 @@ class EventMonitor(object):
 
         def json_output(self, status, tstamp, host, msg):
                 if tstamp:
-                        print cjson.encode([tstamp, host, msg])
+                        print json.dumps([tstamp, host, msg])
         
         def ansi_output(self, status, tstamp, host, msg):
                 if status:</diff>
      <filename>pydisco/disco/eventmonitor.py</filename>
    </modified>
    <modified>
      <diff>@@ -2,6 +2,7 @@ import re, cPickle
 from disco.util import err, data_err, msg
 
 def netstr_reader(fd, content_len, fname):
+
         if content_len == None:
                 err(&quot;Content-length must be defined for netstr_reader&quot;)
         def read_netstr(idx, data, tot):</diff>
      <filename>pydisco/disco/func.py</filename>
    </modified>
    <modified>
      <diff>@@ -24,11 +24,14 @@ import StringIO
 MAX_LEN_STRING = 10
 MAX_PACKET_LEN = 1024**3
 
+class NetStringError(Exception):
+        pass
+
 def _read_string(msg, i):
         j = msg.index(&quot; &quot;, i)
-        len = int(msg[i: j])
+        length = int(msg[i: j])
         j += 1
-        return (j + len + 1, msg[j: j + len])
+        return (j + length + 1, msg[j: j + length])
 
 
 def encode_netstring_str(d):
@@ -66,13 +69,13 @@ def decode_netstring_fd(fd):
                 lenstr += c
                 i += 1
                 if i &gt; MAX_LEN_STRING:
-                        raise &quot;Length string too long&quot;
+                        raise NetStringError(&quot;Length string too long&quot;)
        
         if not lenstr:
                 raise EOFError()
        
-        llen = int(lenstr)
-        if llen &gt; MAX_PACKET_LEN:
-                raise &quot;Will not receive %d bytes&quot; % llen
+        length = int(lenstr)
+        if length &gt; MAX_PACKET_LEN:
+                raise NetStringError(&quot;Will not receive %d bytes&quot; % length)
         
-        return decode_netstring_str(fd.read(llen))
+        return decode_netstring_str(fd.read(length))</diff>
      <filename>pydisco/disco/netstring.py</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
-
-import re, os
-import sys, time, os, traceback
-from disco import comm
+import os
+import sys, time, traceback
+from disco.comm import CommException, download, open_remote
+from disco.error import DiscoError
 
 job_name = &quot;none&quot;
 resultfs_enabled =\
@@ -14,12 +14,12 @@ def msg(m, c = 'MSG', job_input = &quot;&quot;):
 
 def err(m):
         msg(m, 'MSG')
-        raise Exception(m)
+        raise DiscoError(m)
 
 def data_err(m, job_input):
         msg(m, 'DAT', job_input)
         if sys.exc_info() == (None, None, None):
-                raise Exception(m)
+                raise DiscoError(m)
         else:
                 print traceback.print_exc()
                 raise
@@ -42,7 +42,7 @@ def jobname(addr):
         elif addr.startswith(&quot;dir:&quot;):
                 return addr.strip(&quot;/&quot;).split(&quot;/&quot;)[-2]
         else:
-                raise &quot;Unknown address: %s&quot; % addr
+                raise DiscoError(&quot;Unknown address: %s&quot; % addr)
 
 def pack_files(files):
         msg = {}
@@ -68,7 +68,7 @@ def disco_host(addr):
         elif addr.startswith(&quot;http:&quot;):
                 return addr
         else:
-                raise &quot;Unknown host specifier: %s&quot; % addr
+                raise DiscoError(&quot;Unknown host specifier: %s&quot; % addr)
 
 def proxy_url(proxy, path, node = &quot;x&quot;):
         if not proxy:
@@ -80,7 +80,7 @@ def proxy_url(proxy, path, node = &quot;x&quot;):
         elif proxy.startswith(&quot;http://&quot;):
                 host = proxy[7:]
         else:
-                raise Exception(&quot;Unknown proxy protocol: %s&quot; % proxy)
+                raise DiscoError(&quot;Unknown proxy protocol: %s&quot; % proxy)
         return &quot;http://%s/disco/node/%s/%s&quot; % (host, node, path)
 
 def parse_dir(dir_url, proxy = None, part_id = None):
@@ -92,14 +92,14 @@ def parse_dir(dir_url, proxy = None, part_id = None):
                 else:
                         r = comm.download(url).splitlines()
         else:
-                b, max = name.split(&quot;/&quot;)[-1].split(&quot;:&quot;)
-                fl = len(max)
+                b, mmax = name.split(&quot;/&quot;)[-1].split(&quot;:&quot;)
+                fl = len(mmax)
                 base = b[:len(b) - fl]
                 t = &quot;%s%%.%dd&quot; % (base, fl)
                 if part_id != None:
                         r = [t % part_id]
                 else:
-                        r = [t % i for i in range(int(max) + 1)]
+                        r = [t % i for i in range(int(mmax) + 1)]
 
         p = &quot;/&quot;.join(name.split(&quot;/&quot;)[:-1])
         return [&quot;disco://%s/%s/%s&quot; % (host, p, x.strip()) for x in r]
@@ -114,7 +114,7 @@ def load_oob(host, name, key):
                 fname = &quot;%s/data/%s&quot; % (ROOT, &quot;/&quot;.join(loc.split(&quot;/&quot;)[3:]))
                 try:
                         return file(fname).read()
-                except Exception, x:
+                except DiscoError:
                         raise comm.CommException(404, 
                                 &quot;OOB key (%s) not found at %s&quot; %\
                                 (key, fname))</diff>
      <filename>pydisco/disco/util.py</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,6 @@
-import sys, cjson
+import sys
 import tserver
+from disco.comm import json
 from disco.core import Disco, result_iterator
 
 def data_gen(path):
@@ -12,12 +13,12 @@ def fun_map(e, params):
         return [(int(e), &quot;&quot;)]
 
 def add_node():
-        orig_config = cjson.decode(
+        orig_config = json.loads(
                 disco.request(&quot;/disco/ctrl/load_config_table&quot;))
         config = orig_config[:]
         config.append([&quot;missingnode&quot;, &quot;2&quot;])
         r = disco.request(&quot;/disco/ctrl/save_config_table&quot;,
-                cjson.encode(config))
+                json.dumps(config))
         if r != &quot;\&quot;table saved!\&quot;&quot;:
                 raise Exception(&quot;Couldn't add a dummy node: %s&quot; % r)
         return orig_config
@@ -48,7 +49,7 @@ except:
         raise
 finally:
         disco.request(&quot;/disco/ctrl/save_config_table&quot;,
-                cjson.encode(orig_config))
+                json.dumps(orig_config))
 
 print &quot;ok&quot;
 </diff>
      <filename>test/test_missingnode.py</filename>
    </modified>
    <modified>
      <diff>@@ -22,7 +22,15 @@ where
 - config_dir: where to store config files on the master node
 
 &quot;&quot;&quot;
-import sys, cjson, md5, cStringIO, os
+import sys, cStringIO, os
+
+try:
+        import hashlib as md5
+except ImportError:
+        # Hashlib is not available in Python2.4
+        import md5
+
+from disco.comm import json
 
 DEFAULT_REPL_PORT = 9900
 DEFAULT_NUFA_PORT = 9800
@@ -193,24 +201,26 @@ def create_master_config(name, config, path, client_conf):
         print &quot;ok&quot;
 
 if len(sys.argv) &lt; 3 or sys.argv[1] not in [&quot;inputfs&quot;, &quot;resultfs&quot;]:
-        print &quot;\nUsage: python gluster_config.py [inputfs|resultfs] config.json&quot;
-        print 
-        print &quot;This script generates Disco-compatible config files for Gluster,&quot;
-        print &quot;a distributed filesystem.&quot;
-        print 
-        print &quot;Two modes are available:&quot;
-        print &quot;- inputfs, which produces a Gluster volfile that is suitable for&quot;
-        print &quot;  storing input data for Disco so that data is k-way replicated&quot;
-        print &quot;  over nodes.&quot;
-        print &quot;- resultfs, which produces a Gluster volfile for communication&quot;
-        print &quot;  between Disco nodes, in place of the default HTTP-based&quot;
-        print &quot;  solution.&quot;
-        print 
-        print &quot;See gluster_example.json for an example config gile. For more&quot;
-        print &quot;information, see http://discoproject.org/doc/start/dfs.html.\n&quot;
+        print &quot;&quot;&quot;
+        Usage: python gluster_config.py [inputfs|resultfs] config.json
+
+        This script generates Disco-compatible config files for Gluster,
+        a distributed filesystem.
+
+        Two modes are available:
+        - inputfs, which produces a Gluster volfile that is suitable for
+          storing input data for Disco so that data is k-way replicated
+          over nodes.
+        - resultfs, which produces a Gluster volfile for communication
+          between Disco nodes, in place of the default HTTP-based
+          solution.
+
+        See gluster_example.json for an example config gile. For more
+        information, see http://discoproject.org/doc/start/dfs.html.
+        &quot;&quot;&quot;
         sys.exit(1)
 
-config = cjson.decode(file(sys.argv[2]).read())
+config = json.loads(file(sys.argv[2]).read())
 path = os.path.abspath(config[&quot;config_dir&quot;])
 
 if sys.argv[1] == &quot;inputfs&quot;:</diff>
      <filename>util/gluster_config.py</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>eb347eadc2ec65f868df35480be50edb7003b91c</id>
    </parent>
  </parents>
  <author>
    <name>Mistobaan &lt;&gt;</name>
    <email nil="true"></email>
  </author>
  <url>http://github.com/tuulos/disco/commit/e05ed88f1fbca696c47fda80cc45504a33707e23</url>
  <id>e05ed88f1fbca696c47fda80cc45504a33707e23</id>
  <committed-date>2009-09-05T01:21:03-07:00</committed-date>
  <authored-date>2009-08-25T10:29:54-07:00</authored-date>
  <message>mistobaans changes + some DiscoError - some import *</message>
  <tree>e2c10087cda34fc5d5ad5e688ed73ccd7f54371c</tree>
  <committer>
    <name>Ville Tuulos</name>
    <email>tuulos@dxfront.(none)</email>
  </committer>
</commit>
