diff --git a/jdb-build-1.6.xml b/jdb-build-1.6.xml
index da3fa52..760c821 100644
--- a/jdb-build-1.6.xml
+++ b/jdb-build-1.6.xml
@@ -59,7 +59,9 @@
     
 
     
-    
+    
+
+    
 
     
 
@@ -96,7 +98,7 @@
     
 
     
-    
+    
         
         
@@ -109,7 +111,7 @@
         
     
 
-    
+    
         
         
diff --git a/libpit/project.properties b/libpit/project.properties
index a85e2f0..8e11113 100755
--- a/libpit/project.properties
+++ b/libpit/project.properties
@@ -1,11 +1,11 @@
-#Tue, 22 Nov 2011 14:32:12 -0600
+#Wed, 07 Dec 2011 17:53:14 -0600
 #Sat Apr 24 17:08:00 CDT 2010
 build.dir=build
 src.dir=src
 lib.shared.dir=../shared-libs
 test.dir=test
-build.number=25
-version=3.0.0
+build.number=8
+version=3.1.0
 name=libpit
 lib.dir=lib
 lib.local=true
diff --git a/libpit/src/main/com/jdbernard/pit/ExtendedPropertyHelp.groovy b/libpit/src/main/com/jdbernard/pit/ExtendedPropertyHelp.groovy
new file mode 100644
index 0000000..5aeb92a
--- /dev/null
+++ b/libpit/src/main/com/jdbernard/pit/ExtendedPropertyHelp.groovy
@@ -0,0 +1,81 @@
+package com.jdbernard.pit
+
+import org.joda.time.DateMidnight
+import org.joda.time.DateTime
+
+import java.text.SimpleDateFormat
+
+public enum ExtendedPropertyHelp {
+
+    // Property types should be ordered here in order of decreasing specificity.
+    // That is, subclasses should come before the more general class so that
+    // objects are converted using the most specific class that
+    // ExtendedPropertyHelp knows how to work with.
+    DATE_MIDNIGHT(/^\d{4}-\d{2}-\d{2}$/, DateMidnight,
+        { v -> DateMidnight.parse(v) },
+        { d -> d.toString("YYYY-MM-dd") }),
+    DATETIME(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/, DateTime,
+        { v -> DateTime.parse(v) },
+        { d -> d.toString("YYYY-MM-dd'T'HH:mm:ss") }),
+    // We never want to parse a value into a java.util.Date or
+    // java.util.Calendar object (we are using Joda Time instead of the
+    // standard Java Date and Calendar objects) but we do want to be able to
+    // handle if someone gives us a Date or Calendar object. 
+    DATE(NEVER_MATCH, Date,
+        { v -> v }, // never called
+        { d -> dateFormat.format(d) }),
+    CALENDAR(NEVER_MATCH, Calendar,
+        { v -> v }, // never called
+        { c ->
+            def df = dateFormat.clone()
+            df.calendar = c
+            df.format(c.time) }),
+
+    INTEGER(NEVER_MATCH, Integer,
+        { v -> v as Integer }, // never called
+        { i -> i as String }),
+    LONG(/^\d+$/, Long,
+        { v -> v as Long },
+        { l -> l as String }),
+    FLOAT(NEVER_MATCH, Float,
+        { v -> v as Float}, // never called
+        { f -> f as String}),
+    DOUBLE(/^\d+\.\d+$/, Double,
+        { v -> v as Double },
+        { d -> d as String });
+
+    String pattern;
+    Class klass;
+    def parseFun, formatFun;
+
+    private static SimpleDateFormat dateFormat =
+        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+
+    // This pattern for can never match (is uses negative lookahead to
+    // contradict itself).
+    private static String NEVER_MATCH = /(?!x)x/;
+
+
+    public ExtendedPropertyHelp(String pattern, Class klass, def parseFun,
+    def formatFun) {
+        this.pattern = pattern
+        this.klass = klass
+        this.parseFun = parseFun
+        this.formatFun = formatFun }
+
+    public boolean matches(String prop) { return prop ==~ pattern }
+
+    public boolean matches(Class klass) { return this.klass == klass }
+
+    public static Object parse(String value) {
+        def propertyType = ExtendedPropertyHelp.values().find { 
+            it.matches(value) }
+
+        return propertyType ? propertyType.parseFun(value) : value }
+
+    public static String format(def object) {
+        def propertyType = ExtendedPropertyHelp.values().find {
+            it.klass.isInstance(object) }
+
+        return propertyType ? propertyType.formatFun(object) : object.toString() }
+}
diff --git a/libpit/src/main/com/jdbernard/pit/Filter.groovy b/libpit/src/main/com/jdbernard/pit/Filter.groovy
index 239bb6f..2bbcfaa 100755
--- a/libpit/src/main/com/jdbernard/pit/Filter.groovy
+++ b/libpit/src/main/com/jdbernard/pit/Filter.groovy
@@ -8,8 +8,8 @@ class Filter {
     List ids = null
     int priority = 9
     boolean acceptProjects = true
-    Closure issueSorter = defaultIssueSorter
-    Closure projectSorter = defaultProjectSorter
+    def issueSorter = defaultIssueSorter
+    def projectSorter = defaultProjectSorter
 
     public static Closure defaultIssueSorter = { it.id.toInteger() }
     public static Closure defaultProjectSorter = { it.name }
diff --git a/libpit/src/main/com/jdbernard/pit/Project.groovy b/libpit/src/main/com/jdbernard/pit/Project.groovy
index 9796e9c..9135f23 100755
--- a/libpit/src/main/com/jdbernard/pit/Project.groovy
+++ b/libpit/src/main/com/jdbernard/pit/Project.groovy
@@ -10,30 +10,32 @@ public abstract class Project {
 
     public void eachIssue(Filter filter = null, Closure c) {
         def sorter = filter?.issueSorter ?: Filter.defaultIssueSorter
-        for (i in issues.values().sort(sorter)) 
+        for (i in sort(issues.values(), sorter)) 
             if (!filter || filter.accept(i))
-                c.call(i)
-    }
+                c.call(i) }
 
     public void eachProject(Filter filter = null, Closure c) {
         def sorter = filter?.projectSorter ?: Filter.defaultProjectSorter
-        for (p in projects.values().sort(sorter))
+        for (p in sort(projects.values(), sorter))
             if (!filter || filter.accept(p))
-                c.call(p)
-    }
+                c.call(p) }
 
     // walk every issue and project in this project recursively and execute the
     // given closure on each issue that meets the filter criteria
     public void walkProject(Filter filter, Closure c) {
         this.eachIssue(filter, c)
-        this.eachProject(filter) { p -> p.walkProject(filter, c) }
-    }
+        this.eachProject(filter) { p -> p.walkProject(filter, c) } }
 
     // This get all issues, including subissues
     public List getAllIssues(Filter filter = null) {
-        List result = this.issues.findAll { filter.accept(it) }
-        this.eachProject(filter) { p -> result += p.getAllIssues(filter) }
-    }
+        def sorter = filter?.issueSorter ?: Filter.defaultIssueSorter
+
+        List allIssues = this.issues.values().findAll {
+            filter ? filter.accept(it) : true }
+
+        this.eachProject(filter) { p -> allIssues += p.getAllIssues(filter) }
+
+        return sort(allIssues, sorter) }
 
     public void setName(String name) { this.name = name }
 
@@ -49,4 +51,10 @@ public abstract class Project {
     public abstract boolean deleteIssue(Issue issue)
 
     public abstract boolean deleteProject(Project project)
+
+    protected List sort(def collection, def sorter) {
+        if (sorter instanceof Closure) {
+            return collection.sort(sorter) }
+        else if (sorter instanceof List) {
+            return sorter.reverse().inject(collection) { c, s -> c.sort(s) }}}
 }
diff --git a/libpit/src/main/com/jdbernard/pit/Status.groovy b/libpit/src/main/com/jdbernard/pit/Status.groovy
index d1a227b..1779370 100755
--- a/libpit/src/main/com/jdbernard/pit/Status.groovy
+++ b/libpit/src/main/com/jdbernard/pit/Status.groovy
@@ -12,25 +12,25 @@ public enum Status {
     protected Status(String s) { symbol = s }
 
     public static Status toStatus(String str) {
-        Status retVal = null
-        for(status in Status.values())  {
-            if (status.symbol.equalsIgnoreCase(str) ||
-                status.name().startsWith(str.toUpperCase())) {
+        // Try to match based on symbol
+        def match = Status.values().find {it.symbol.equalsIgnoreCase(str)}
+        if (match) { return match }
 
-                if (retVal != null)
-                    throw new IllegalArgumentException("Request string is" +
-                        " ambigous, '${str}' could represent ${retVal} or " +
-                        "${status}, possibly others.")
+        // No match on the symbol, look for the status name (or abbreviations)
+        match = Status.values().findAll {
+            it.name().startsWith(str.toUpperCase()) }
 
-                retVal = status
-            }
-        }
+        // No matching status, oops.
+        if (match.size() == 0) {
+            throw new IllegalArgumentException("No status matches '${str}'") }
 
-        if (retVal == null)
-            throw new IllegalArgumentException("No status matches '${str}'")
+        // More than one matching status, oops.
+        else if (match.size() > 1) {
+            throw new IllegalArgumentException("Request string is" +
+                " ambigous, '${str}' could represent any of ${match}.")}
 
-        return retVal
-    }
+        // Only one matching status, yay!
+        else { return match[0] }}
 
     public String toString() {
         def words = name().split("_")
diff --git a/libpit/src/main/com/jdbernard/pit/file/ExtendedPropertyHelp.groovy b/libpit/src/main/com/jdbernard/pit/file/ExtendedPropertyHelp.groovy
deleted file mode 100644
index cd5bf13..0000000
--- a/libpit/src/main/com/jdbernard/pit/file/ExtendedPropertyHelp.groovy
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.jdbernard.pit.file
-
-import org.joda.time.DateMidnight
-import org.joda.time.DateTime
-
-public enum ExtendedPropertyHelp {
-
-    DATE(/^\d{4}-\d{2}-\d{2}$/, DateMidnight,
-        { v -> DateMidnight.parse(v) },
-        { d -> d.toString("YYYY-MM-dd") }),
-    DATETIME(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/, DateTime,
-        { v -> DateTime.parse(v) },
-        { d -> d.toString("YYYY-MM-dd'T'HH:mm:ss") }),
-    INTEGER(/^\d+$/, Integer,
-        { v -> v as Integer },
-        { i -> i as String });
-
-    String pattern;
-    Class klass;
-    def parseFun, formatFun;
-
-    public ExtendedPropertyHelp(String pattern, Class klass, def parseFun,
-    def formatFun) {
-        this.pattern = pattern
-        this.klass = klass
-        this.parseFun = parseFun
-        this.formatFun = formatFun }
-
-    public boolean matches(String prop) { return prop ==~ pattern }
-
-    public static Object parse(String value) {
-        def result = null
-        ExtendedPropertyHelp.values().each { propType ->
-            if (propType.matches(value)) { result = propType.parseFun(value) }}
-
-        return result ?: value }
-
-    public static String format(def object) {
-        def result = null
-        ExtendedPropertyHelp.values().each { propType ->
-            if (!result && propType.klass.isInstance(object)) {
-                result = propType.formatFun(object) }}
-
-        return result ?: object.toString() }
-}