Author: cbegin Date: Tue Jun 30 04:10:17 2009 New Revision: 789554 URL: http://svn.apache.org/viewvc?rev=789554&view=rev Log: fixed nested map properties.
Removed: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/HybridWrapper.java Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/mapping/BoundSql.java ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaClass.java ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaObject.java ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/BeanWrapper.java ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/ObjectWrapper.java ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/reflection/MetaObjectTest.java ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/dynsql2/DynSqlTest.java ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/dynsql2/MapperConfig.xml ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/nested/MapperConfig.xml ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/nested/NestedForEachTest.java ibatis/trunk/java/ibatis-3/version.properties Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/mapping/BoundSql.java URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/mapping/BoundSql.java?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/mapping/BoundSql.java (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/mapping/BoundSql.java Tue Jun 30 04:10:17 2009 @@ -1,5 +1,7 @@ package org.apache.ibatis.mapping; +import org.apache.ibatis.reflection.MetaObject; + import java.util.List; import java.util.Map; import java.util.HashMap; @@ -10,12 +12,14 @@ private List<ParameterMapping> parameterMappings; private Object parameterObject; private Map<String,Object> additionalParameters; + private MetaObject metaParameters; public BoundSql(String sql, List<ParameterMapping> parameterMappings, Object parameterObject) { this.sql = sql; this.parameterMappings = parameterMappings; this.parameterObject = parameterObject; this.additionalParameters = new HashMap<String,Object>(); + this.metaParameters = MetaObject.forObject(additionalParameters); } public String getSql() { @@ -31,14 +35,14 @@ } public boolean hasAdditionalParameter(String name) { - return additionalParameters.containsKey(name); + return metaParameters.hasGetter(name); } public void setAdditionalParameter(String name, Object value) { - additionalParameters.put(name, value); + metaParameters.setValue(name, value); } public Object getAdditionalParameter(String name) { - return additionalParameters.get(name); + return metaParameters.getValue(name); } } Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaClass.java URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaClass.java?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaClass.java (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaClass.java Tue Jun 30 04:10:17 2009 @@ -64,8 +64,12 @@ public boolean hasSetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { - MetaClass metaProp = metaClassForProperty(prop.getName()); - return metaProp.hasSetter(prop.getChildren()); + if (reflector.hasSetter(prop.getName())) { + MetaClass metaProp = metaClassForProperty(prop.getName()); + return metaProp.hasSetter(prop.getChildren()); + } else { + return false; + } } else { return reflector.hasSetter(prop.getName()); } @@ -74,8 +78,12 @@ public boolean hasGetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { - MetaClass metaProp = metaClassForProperty(prop.getName()); - return metaProp.hasGetter(prop.getChildren()); + if (reflector.hasGetter(prop.getName())) { + MetaClass metaProp = metaClassForProperty(prop.getName()); + return metaProp.hasGetter(prop.getChildren()); + } else { + return false; + } } else { return reflector.hasGetter(prop.getName()); } Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaObject.java URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaObject.java?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaObject.java (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/MetaObject.java Tue Jun 30 04:10:17 2009 @@ -14,17 +14,19 @@ private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory(); public static final MetaObject NULL_META_OBJECT = new MetaObject(NullObject.class, DEFAULT_OBJECT_FACTORY); - private ObjectWrapper dynamicObject; + private Object originalObject; + private ObjectWrapper objectWrapper; private ObjectFactory objectFactory; private MetaObject(Object object, ObjectFactory objectFactory) { + this.originalObject = object; this.objectFactory = objectFactory; if (object instanceof ObjectWrapper) { - this.dynamicObject = (ObjectWrapper) object; + this.objectWrapper = (ObjectWrapper) object; } else if (object instanceof Map) { - this.dynamicObject = new MapWrapper(this, (Map)object); + this.objectWrapper = new MapWrapper(this, (Map)object); } else { - this.dynamicObject = new BeanWrapper(this, object); + this.objectWrapper = new BeanWrapper(this, object); } } @@ -40,32 +42,36 @@ return forObject(object, DEFAULT_OBJECT_FACTORY); } + public Object getOriginalObject() { + return originalObject; + } + public String findProperty(String propName) { - return dynamicObject.findProperty(propName); + return objectWrapper.findProperty(propName); } public String[] getGetterNames() { - return dynamicObject.getGetterNames(); + return objectWrapper.getGetterNames(); } public String[] getSetterNames() { - return dynamicObject.getSetterNames(); + return objectWrapper.getSetterNames(); } public Class getSetterType(String name) { - return dynamicObject.getSetterType(name); + return objectWrapper.getSetterType(name); } public Class getGetterType(String name) { - return dynamicObject.getGetterType(name); + return objectWrapper.getGetterType(name); } public boolean hasSetter(String name) { - return dynamicObject.hasSetter(name); + return objectWrapper.hasSetter(name); } public boolean hasGetter(String name) { - return dynamicObject.hasGetter(name); + return objectWrapper.hasGetter(name); } public Object getValue(String name) { @@ -78,7 +84,7 @@ return metaValue.getValue(prop.getChildren()); } } else { - return dynamicObject.get(prop); + return objectWrapper.get(prop); } } @@ -90,19 +96,12 @@ if (value == null && prop.getChildren() != null) { return; // don't instantiate child path if value is null } else { - Class type = getSetterType(prop.getName()); - try { - Object newObject = objectFactory.create(type); - metaValue = MetaObject.forObject(newObject); - dynamicObject.set(prop, newObject); - } catch (Exception e) { - throw new ReflectionException("Cannot set value of property '" + name + "' because '" + name + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(), e); - } + metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory); } } metaValue.setValue(prop.getChildren(), value); } else { - dynamicObject.set(prop, value); + objectWrapper.set(prop, value); } } @@ -111,8 +110,8 @@ return MetaObject.forObject(value); } - public ObjectWrapper getDynamicObject() { - return dynamicObject; + public ObjectWrapper getObjectWrapper() { + return objectWrapper; } private static class NullObject { Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/BeanWrapper.java URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/BeanWrapper.java?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/BeanWrapper.java (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/BeanWrapper.java Tue Jun 30 04:10:17 2009 @@ -1,6 +1,7 @@ package org.apache.ibatis.reflection.wrapper; import org.apache.ibatis.reflection.*; +import org.apache.ibatis.reflection.factory.ObjectFactory; import org.apache.ibatis.reflection.property.PropertyTokenizer; import org.apache.ibatis.reflection.invoker.Invoker; @@ -76,11 +77,15 @@ public boolean hasSetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { - MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); - if (metaValue == MetaObject.NULL_META_OBJECT) { - return metaClass.hasSetter(name); + if (metaClass.hasSetter(prop.getIndexedName())) { + MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); + if (metaValue == MetaObject.NULL_META_OBJECT) { + return metaClass.hasSetter(name); + } else { + return metaValue.hasSetter(prop.getChildren()); + } } else { - return metaValue.hasSetter(prop.getChildren()); + return false; } } else { return metaClass.hasSetter(name); @@ -90,17 +95,34 @@ public boolean hasGetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { - MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); - if (metaValue == MetaObject.NULL_META_OBJECT) { - return metaClass.hasGetter(name); + if (metaClass.hasGetter(prop.getIndexedName())) { + MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); + if (metaValue == MetaObject.NULL_META_OBJECT) { + return metaClass.hasGetter(name); + } else { + return metaValue.hasGetter(prop.getChildren()); + } } else { - return metaValue.hasGetter(prop.getChildren()); + return false; } } else { return metaClass.hasGetter(name); } } + public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) { + MetaObject metaValue; + Class type = getSetterType(prop.getName()); + try { + Object newObject = objectFactory.create(type); + metaValue = MetaObject.forObject(newObject); + set(prop, newObject); + } catch (Exception e) { + throw new ReflectionException("Cannot set value of property '" + name + "' because '" + name + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(), e); + } + return metaValue; + } + private Object getBeanProperty(PropertyTokenizer prop, Object object) { try { Invoker method = metaClass.getGetInvoker(prop.getName()); Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java Tue Jun 30 04:10:17 2009 @@ -1,9 +1,10 @@ package org.apache.ibatis.reflection.wrapper; -import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.*; +import org.apache.ibatis.reflection.factory.ObjectFactory; import org.apache.ibatis.reflection.property.PropertyTokenizer; -import java.util.Map; +import java.util.*; public class MapWrapper extends BaseWrapper { @@ -37,19 +38,47 @@ } public String[] getGetterNames() { - return (String[]) ((Map) map).keySet().toArray(new String[map.size()]); + return (String[])map.keySet().toArray(new String[map.keySet().size()]); } public String[] getSetterNames() { - return (String[]) ((Map) map).keySet().toArray(new String[map.size()]); + return (String[])map.keySet().toArray(new String[map.keySet().size()]); } public Class getSetterType(String name) { - return map.get(name) == null ? Object.class : map.get(name).getClass(); + PropertyTokenizer prop = new PropertyTokenizer(name); + if (prop.hasNext()) { + MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); + if (metaValue == MetaObject.NULL_META_OBJECT) { + return Object.class; + } else { + return metaValue.getSetterType(prop.getChildren()); + } + } else { + if (map.get(name) != null) { + return map.get(name).getClass(); + } else { + return Object.class; + } + } } public Class getGetterType(String name) { - return map.get(name) == null ? Object.class : map.get(name).getClass(); + PropertyTokenizer prop = new PropertyTokenizer(name); + if (prop.hasNext()) { + MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); + if (metaValue == MetaObject.NULL_META_OBJECT) { + return Object.class; + } else { + return metaValue.getGetterType(prop.getChildren()); + } + } else { + if (map.get(name) != null) { + return map.get(name).getClass(); + } else { + return Object.class; + } + } } public boolean hasSetter(String name) { @@ -57,6 +86,26 @@ } public boolean hasGetter(String name) { - return true; + PropertyTokenizer prop = new PropertyTokenizer(name); + if (prop.hasNext()) { + if (map.containsKey(prop.getIndexedName())) { + MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); + if (metaValue == MetaObject.NULL_META_OBJECT) { + return map.containsKey(name); + } else { + return metaValue.hasGetter(prop.getChildren()); + } + } else { + return false; + } + } else { + return map.containsKey(name); + } + } + + public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) { + HashMap map = new HashMap(); + set(prop, map); + return MetaObject.forObject(map); } } Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/ObjectWrapper.java URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/ObjectWrapper.java?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/ObjectWrapper.java (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/reflection/wrapper/ObjectWrapper.java Tue Jun 30 04:10:17 2009 @@ -1,6 +1,8 @@ package org.apache.ibatis.reflection.wrapper; import org.apache.ibatis.reflection.property.PropertyTokenizer; +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.factory.ObjectFactory; public interface ObjectWrapper { @@ -21,5 +23,7 @@ boolean hasSetter(String name); boolean hasGetter(String name); - + + MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory); + } Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/reflection/MetaObjectTest.java URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/reflection/MetaObjectTest.java?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/reflection/MetaObjectTest.java (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/reflection/MetaObjectTest.java Tue Jun 30 04:10:17 2009 @@ -5,6 +5,8 @@ import static org.junit.Assert.*; import org.junit.Test; +import java.util.*; + public class MetaObjectTest { @Test @@ -179,5 +181,40 @@ } } + @Test + public void shouldDemonstrateDeeplyNestedMapProperties() { + HashMap map = new HashMap(); + MetaObject metaMap = MetaObject.forObject(map); + + assertTrue(metaMap.hasSetter("id")); + assertTrue(metaMap.hasSetter("name.first")); + assertTrue(metaMap.hasSetter("address.street")); + + assertFalse(metaMap.hasGetter("id")); + assertFalse(metaMap.hasGetter("name.first")); + assertFalse(metaMap.hasGetter("address.street")); + + metaMap.setValue("id", "100"); + metaMap.setValue("name.first", "Clinton"); + metaMap.setValue("name.last", "Begin"); + metaMap.setValue("address.street", "1 Some Street"); + metaMap.setValue("address.city", "This City"); + metaMap.setValue("address.province", "A Province"); + metaMap.setValue("address.postal_code", "1A3 4B6"); + + assertTrue(metaMap.hasGetter("id")); + assertTrue(metaMap.hasGetter("name.first")); + assertTrue(metaMap.hasGetter("address.street")); + + assertEquals(3, metaMap.getGetterNames().length); + assertEquals(3, metaMap.getSetterNames().length); + + Map name = (Map)metaMap.getValue("name"); + Map address = (Map)metaMap.getValue("address"); + + assertEquals("Clinton", name.get("first")); + assertEquals("1 Some Street", address.get("street")); + } + } Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/dynsql2/DynSqlTest.java URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/dynsql2/DynSqlTest.java?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/dynsql2/DynSqlTest.java (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/dynsql2/DynSqlTest.java Tue Jun 30 04:10:17 2009 @@ -31,7 +31,7 @@ try { Class.forName("org.hsqldb.jdbcDriver"); - conn = DriverManager.getConnection("jdbc:hsqldb:mem:aname", "sa", + conn = DriverManager.getConnection("jdbc:hsqldb:mem:bname", "sa", ""); Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/dynsql2/CreateDB.sql"); Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/dynsql2/MapperConfig.xml URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/dynsql2/MapperConfig.xml?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/dynsql2/MapperConfig.xml (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/dynsql2/MapperConfig.xml Tue Jun 30 04:10:17 2009 @@ -12,7 +12,7 @@ </transactionManager> <dataSource type="UNPOOLED"> <property name="driver" value="org.hsqldb.jdbcDriver"/> - <property name="url" value="jdbc:hsqldb:mem:aname"/> + <property name="url" value="jdbc:hsqldb:mem:bname"/> <property name="username" value="sa"/> </dataSource> </environment> Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/nested/MapperConfig.xml URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/nested/MapperConfig.xml?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/nested/MapperConfig.xml (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/nested/MapperConfig.xml Tue Jun 30 04:10:17 2009 @@ -16,7 +16,7 @@ </transactionManager> <dataSource type="UNPOOLED"> <property name="driver" value="org.hsqldb.jdbcDriver"/> - <property name="url" value="jdbc:hsqldb:mem:aname"/> + <property name="url" value="jdbc:hsqldb:mem:cname"/> <property name="username" value="sa"/> </dataSource> </environment> Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/nested/NestedForEachTest.java URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/nested/NestedForEachTest.java?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/nested/NestedForEachTest.java (original) +++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/submitted/nested/NestedForEachTest.java Tue Jun 30 04:10:17 2009 @@ -27,7 +27,7 @@ try { Class.forName("org.hsqldb.jdbcDriver"); - conn = DriverManager.getConnection("jdbc:hsqldb:mem:aname", "sa", + conn = DriverManager.getConnection("jdbc:hsqldb:mem:cname", "sa", ""); Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/nested/CreateDB.sql"); Modified: ibatis/trunk/java/ibatis-3/version.properties URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/version.properties?rev=789554&r1=789553&r2=789554&view=diff ============================================================================== --- ibatis/trunk/java/ibatis-3/version.properties (original) +++ ibatis/trunk/java/ibatis-3/version.properties Tue Jun 30 04:10:17 2009 @@ -1,5 +1,5 @@ #Build version info -#Wed Jun 10 13:21:15 MDT 2009 +#Sat Jun 27 06:41:35 MDT 2009 version=3.0.0 -buildDate=2009/06/10 13\:21 -buildNum=179 +buildDate=2009/06/27 06\:41 +buildNum=181