<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -20,7 +20,7 @@ class LedgerHandler(BaseHTTPRequestHandler):
         except Exception:
             print &quot;Saw exception in POST handler&quot;
 
-def cmd_server():
+def main(*args):
     try:
         port   = 9000
         server = HTTPServer(('', port), LedgerHandler)
@@ -31,3 +31,6 @@ def cmd_server():
         print &quot;Shutting down server&quot;
         server.socket.close()
 
+print __name__
+if __name__ == '__main__':
+    main()</diff>
      <filename>python/server.py</filename>
    </modified>
    <modified>
      <diff>@@ -114,6 +114,99 @@ shared_ptr&lt;commodity_pool_t&gt; amount_t::current_pool;
 
 bool amount_t::is_initialized = false;
 
+namespace {
+  void stream_out_mpq(std::ostream&amp;	            out,
+		      mpq_t		            quant,
+		      amount_t::precision_t         prec,
+		      int                           zeros_prec = -1,
+		      const optional&lt;commodity_t&amp;&gt;&amp; comm       = none)
+  {
+    char * buf = NULL;
+    try {
+      IF_DEBUG(&quot;amount.convert&quot;) {
+	char * tbuf = mpq_get_str(NULL, 10, quant);
+	DEBUG(&quot;amount.convert&quot;, &quot;Rational to convert = &quot; &lt;&lt; tbuf);
+	std::free(tbuf);
+      }
+
+      // Convert the rational number to a floating-point, extending the
+      // floating-point to a large enough size to get a precise answer.
+      const std::size_t bits = (mpz_sizeinbase(mpq_numref(quant), 2) +
+				mpz_sizeinbase(mpq_denref(quant), 2));
+      mpfr_set_prec(tempfb, bits + amount_t::extend_by_digits*8);
+      mpfr_set_q(tempfb, quant, GMP_RNDN);
+
+      mpfr_asprintf(&amp;buf, &quot;%.*Rf&quot;, prec, tempfb);
+      DEBUG(&quot;amount.convert&quot;,
+	    &quot;mpfr_print = &quot; &lt;&lt; buf &lt;&lt; &quot; (precision &quot; &lt;&lt; prec &lt;&lt; &quot;)&quot;);
+
+      if (zeros_prec &gt;= 0) {
+	string::size_type index = std::strlen(buf);
+	string::size_type point = 0;
+	for (string::size_type i = 0; i &lt; index; i++) {
+	  if (buf[i] == '.') {
+	    point = i;
+	    break;
+	  }
+	}
+	if (point &gt; 0) {
+	  while (--index &gt;= (point + 1 + zeros_prec) &amp;&amp; buf[index] == '0')
+	    buf[index] = '\0';
+	  if (index &gt;= (point + zeros_prec) &amp;&amp; buf[index] == '.')
+	    buf[index] = '\0';
+	}
+      }
+
+      if (comm) {
+	int integer_digits = 0;
+	if (comm &amp;&amp; comm-&gt;has_flags(COMMODITY_STYLE_THOUSANDS)) {
+	  // Count the number of integer digits
+	  for (const char * p = buf; *p; p++) {
+	    if (*p == '.')
+	      break;
+	    else if (*p != '-')
+	      integer_digits++;
+	  }
+	}
+
+	for (const char * p = buf; *p; p++) {
+	  if (*p == '.') {
+	    if (commodity_t::european_by_default ||
+		(comm &amp;&amp; comm-&gt;has_flags(COMMODITY_STYLE_EUROPEAN)))
+	      out &lt;&lt; ',';
+	    else
+	      out &lt;&lt; *p;
+	    assert(integer_digits &lt;= 3);
+	  }
+	  else if (*p == '-') {
+	    out &lt;&lt; *p;
+	  }
+	  else {
+	    out &lt;&lt; *p;
+
+	    if (integer_digits &gt; 3 &amp;&amp; --integer_digits % 3 == 0) {
+	      if (commodity_t::european_by_default ||
+		  (comm &amp;&amp; comm-&gt;has_flags(COMMODITY_STYLE_EUROPEAN)))
+		out &lt;&lt; '.';
+	      else
+		out &lt;&lt; ',';
+	    }
+	  }
+	}
+      } else {
+	out &lt;&lt; buf;
+      }
+    }
+    catch (...) {
+      if (buf != NULL)
+	mpfr_free_str(buf);
+      throw;
+    }
+    if (buf != NULL)
+      mpfr_free_str(buf);
+  }
+}
+
 void amount_t::initialize(shared_ptr&lt;commodity_pool_t&gt; pool)
 {
   if (! is_initialized) {
@@ -498,6 +591,19 @@ void amount_t::in_place_round()
   set_keep_precision(false);
 }
 
+void amount_t::in_place_floor()
+{
+  if (! quantity)
+    throw_(amount_error, _(&quot;Cannot floor an uninitialized amount&quot;));
+
+  _dup();
+
+  std::ostringstream out;
+  stream_out_mpq(out, MP(quantity), 0);
+
+  mpq_set_str(MP(quantity), out.str().c_str(), 10);
+}
+
 void amount_t::in_place_unround()
 {
   if (! quantity)
@@ -612,99 +718,6 @@ int amount_t::sign() const
   return mpq_sgn(MP(quantity));
 }
 
-namespace {
-  void stream_out_mpq(std::ostream&amp;	            out,
-		      mpq_t		            quant,
-		      amount_t::precision_t         prec,
-		      int                           zeros_prec = -1,
-		      const optional&lt;commodity_t&amp;&gt;&amp; comm       = none)
-  {
-    char * buf = NULL;
-    try {
-      IF_DEBUG(&quot;amount.convert&quot;) {
-	char * tbuf = mpq_get_str(NULL, 10, quant);
-	DEBUG(&quot;amount.convert&quot;, &quot;Rational to convert = &quot; &lt;&lt; tbuf);
-	std::free(tbuf);
-      }
-
-      // Convert the rational number to a floating-point, extending the
-      // floating-point to a large enough size to get a precise answer.
-      const std::size_t bits = (mpz_sizeinbase(mpq_numref(quant), 2) +
-				mpz_sizeinbase(mpq_denref(quant), 2));
-      mpfr_set_prec(tempfb, bits + amount_t::extend_by_digits*8);
-      mpfr_set_q(tempfb, quant, GMP_RNDN);
-
-      mpfr_asprintf(&amp;buf, &quot;%.*Rf&quot;, prec, tempfb);
-      DEBUG(&quot;amount.convert&quot;,
-	    &quot;mpfr_print = &quot; &lt;&lt; buf &lt;&lt; &quot; (precision &quot; &lt;&lt; prec &lt;&lt; &quot;)&quot;);
-
-      if (zeros_prec &gt;= 0) {
-	string::size_type index = std::strlen(buf);
-	string::size_type point = 0;
-	for (string::size_type i = 0; i &lt; index; i++) {
-	  if (buf[i] == '.') {
-	    point = i;
-	    break;
-	  }
-	}
-	if (point &gt; 0) {
-	  while (--index &gt;= (point + 1 + zeros_prec) &amp;&amp; buf[index] == '0')
-	    buf[index] = '\0';
-	  if (index &gt;= (point + zeros_prec) &amp;&amp; buf[index] == '.')
-	    buf[index] = '\0';
-	}
-      }
-
-      if (comm) {
-	int integer_digits = 0;
-	if (comm &amp;&amp; comm-&gt;has_flags(COMMODITY_STYLE_THOUSANDS)) {
-	  // Count the number of integer digits
-	  for (const char * p = buf; *p; p++) {
-	    if (*p == '.')
-	      break;
-	    else if (*p != '-')
-	      integer_digits++;
-	  }
-	}
-
-	for (const char * p = buf; *p; p++) {
-	  if (*p == '.') {
-	    if (commodity_t::european_by_default ||
-		(comm &amp;&amp; comm-&gt;has_flags(COMMODITY_STYLE_EUROPEAN)))
-	      out &lt;&lt; ',';
-	    else
-	      out &lt;&lt; *p;
-	    assert(integer_digits &lt;= 3);
-	  }
-	  else if (*p == '-') {
-	    out &lt;&lt; *p;
-	  }
-	  else {
-	    out &lt;&lt; *p;
-
-	    if (integer_digits &gt; 3 &amp;&amp; --integer_digits % 3 == 0) {
-	      if (commodity_t::european_by_default ||
-		  (comm &amp;&amp; comm-&gt;has_flags(COMMODITY_STYLE_EUROPEAN)))
-		out &lt;&lt; '.';
-	      else
-		out &lt;&lt; ',';
-	    }
-	  }
-	}
-      } else {
-	out &lt;&lt; buf;
-      }
-    }
-    catch (...) {
-      if (buf != NULL)
-	mpfr_free_str(buf);
-      throw;
-    }
-    if (buf != NULL)
-      mpfr_free_str(buf);
-  }
-}
-
 bool amount_t::is_zero() const
 {
   if (! quantity)
@@ -1238,17 +1251,24 @@ void serialize(Archive&amp; ar, long unsigned int&amp; integer,
 
 BOOST_CLASS_EXPORT(ledger::annotated_commodity_t)
 
+template void boost::serialization::serialize(boost::archive::binary_iarchive&amp;,
+					      MP_INT&amp;, const unsigned int);
 template void boost::serialization::serialize(boost::archive::binary_oarchive&amp;,
 					      MP_INT&amp;, const unsigned int);
 template void boost::serialization::serialize(boost::archive::binary_iarchive&amp;,
 					      MP_RAT&amp;, const unsigned int);
+template void boost::serialization::serialize(boost::archive::binary_oarchive&amp;,
+					      MP_RAT&amp;, const unsigned int);
 template void boost::serialization::serialize(boost::archive::binary_iarchive&amp;,
 					      long unsigned int&amp;,
 					      const unsigned int);
+template void boost::serialization::serialize(boost::archive::binary_oarchive&amp;,
+					      long unsigned int&amp;,
+					      const unsigned int);
 
-template void ledger::amount_t::serialize(boost::archive::binary_oarchive&amp;,
-					  const unsigned int);
 template void ledger::amount_t::serialize(boost::archive::binary_iarchive&amp;,
 					  const unsigned int);
+template void ledger::amount_t::serialize(boost::archive::binary_oarchive&amp;,
+					  const unsigned int);
 
 #endif // HAVE_BOOST_SERIALIZATION</diff>
      <filename>src/amount.cc</filename>
    </modified>
    <modified>
      <diff>@@ -354,6 +354,15 @@ public:
     *this = amount_t(to_string());
   }
     
+  /** Yields an amount which has lost all of its extra precision, beyond what
+      the display precision of the commodity would have printed. */
+  amount_t floored() const {
+    amount_t temp(*this);
+    temp.in_place_floor();
+    return temp;
+  }
+  void in_place_floor();
+    
   /** Yields an amount whose display precision is never truncated, even
       though its commodity normally displays only rounded values. */
   amount_t unrounded() const {</diff>
      <filename>src/amount.h</filename>
    </modified>
    <modified>
      <diff>@@ -43,7 +43,7 @@
 #include &quot;xact.h&quot;
 
 #define LEDGER_MAGIC    0x4c454447
-#define ARCHIVE_VERSION 0x03000004
+#define ARCHIVE_VERSION 0x03000005
 
 //BOOST_IS_ABSTRACT(ledger::scope_t)
 BOOST_CLASS_EXPORT(ledger::scope_t)</diff>
      <filename>src/archive.cc</filename>
    </modified>
    <modified>
      <diff>@@ -339,6 +339,18 @@ public:
     *this = temp;
   }
 
+  balance_t floored() const {
+    balance_t temp(*this);
+    temp.in_place_floor();
+    return temp;
+  }
+  void in_place_floor() {
+    balance_t temp;
+    foreach (const amounts_map::value_type&amp; pair, amounts)
+      temp += pair.second.floored();
+    *this = temp;
+  }
+
   balance_t unrounded() const {
     balance_t temp(*this);
     temp.in_place_unround();</diff>
      <filename>src/balance.h</filename>
    </modified>
    <modified>
      <diff>@@ -420,6 +420,7 @@ xact_t * draft_t::insert(journal_t&amp; journal)
 	  }
 	}
       }
+      assert(new_post-&gt;account);
 
       if (new_post.get() &amp;&amp; ! new_post-&gt;amount.is_null()) {
 	found_commodity = &amp;new_post-&gt;amount.commodity();
@@ -475,6 +476,7 @@ xact_t * draft_t::insert(journal_t&amp; journal)
       }
 
       added-&gt;add_post(new_post.release());
+      added-&gt;posts.back()-&gt;account-&gt;add_post(added-&gt;posts.back());
       added-&gt;posts.back()-&gt;set_state(item_t::UNCLEARED);
 
       DEBUG(&quot;derive.xact&quot;, &quot;Added new posting to derived entry&quot;);</diff>
      <filename>src/draft.cc</filename>
    </modified>
    <modified>
      <diff>@@ -33,7 +33,6 @@
 
 #include &quot;format.h&quot;
 #include &quot;scope.h&quot;
-#include &quot;unistring.h&quot;
 #include &quot;pstream.h&quot;
 
 namespace ledger {</diff>
      <filename>src/format.cc</filename>
    </modified>
    <modified>
      <diff>@@ -43,6 +43,7 @@
 #define _FORMAT_H
 
 #include &quot;expr.h&quot;
+#include &quot;unistring.h&quot;
 
 namespace ledger {
 </diff>
      <filename>src/format.h</filename>
    </modified>
    <modified>
      <diff>@@ -70,9 +70,9 @@ public:
     list.remove(func);
   }
 
-  bool run_hooks(Data&amp; item, bool post) {
+  bool run_hooks(Data&amp; item) {
     foreach (T * func, list)
-      if (! (*func)(item, post))
+      if (! (*func)(item))
 	return false;
     return true;
   }</diff>
      <filename>src/hooks.h</filename>
    </modified>
    <modified>
      <diff>@@ -126,9 +126,7 @@ bool journal_t::add_xact(xact_t * xact)
 {
   xact-&gt;journal = this;
 
-  if (! xact_finalize_hooks.run_hooks(*xact, false) ||
-      ! xact-&gt;finalize() ||
-      ! xact_finalize_hooks.run_hooks(*xact, true)) {
+  if (! xact-&gt;finalize() || ! xact_finalize_hooks.run_hooks(*xact)) {
     xact-&gt;journal = NULL;
     return false;
   }</diff>
      <filename>src/journal.cc</filename>
    </modified>
    <modified>
      <diff>@@ -40,9 +40,10 @@
 
 namespace ledger {
 
-format_posts::format_posts(report_t&amp;	 _report,
-			   const string&amp; format,
-			   bool		 _print_raw)
+format_posts::format_posts(report_t&amp;		   _report,
+			   const string&amp;	   format,
+			   bool			   _print_raw,
+			   const optional&lt;string&gt;&amp; _prepend_format)
   : report(_report), last_xact(NULL), last_post(NULL),
     print_raw(_print_raw)
 {
@@ -65,6 +66,9 @@ format_posts::format_posts(report_t&amp;	 _report,
     first_line_format.parse_format(format);
     next_lines_format.parse_format(format);
   }
+
+  if (_prepend_format)
+    prepend_format.parse_format(*_prepend_format);
 }
 
 void format_posts::flush()
@@ -95,6 +99,10 @@ void format_posts::operator()(post_t&amp; post)
   else if (! post.has_xdata() ||
 	   ! post.xdata().has_flags(POST_EXT_DISPLAYED)) {
     bind_scope_t bound_scope(report, post);
+
+    if (prepend_format)
+      out &lt;&lt; prepend_format(bound_scope);
+
     if (last_xact != post.xact) {
       if (last_xact) {
 	bind_scope_t xact_scope(report, *last_xact);
@@ -115,8 +123,9 @@ void format_posts::operator()(post_t&amp; post)
   }
 }
 
-format_accounts::format_accounts(report_t&amp;     _report,
-				 const string&amp; format)
+format_accounts::format_accounts(report_t&amp;		 _report,
+				 const string&amp;		 format,
+				 const optional&lt;string&gt;&amp; _prepend_format)
   : report(_report), disp_pred()
 {
   TRACE_CTOR(format_accounts, &quot;report&amp;, const string&amp;&quot;);
@@ -136,6 +145,9 @@ format_accounts::format_accounts(report_t&amp;     _report,
     account_line_format.parse_format(format);
     total_line_format.parse_format(format, account_line_format);
   }
+
+  if (_prepend_format)
+    prepend_format.parse_format(*_prepend_format);
 }
 
 std::size_t format_accounts::post_account(account_t&amp; account, const bool flat)
@@ -150,6 +162,11 @@ std::size_t format_accounts::post_account(account_t&amp; account, const bool flat)
     account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
 
     bind_scope_t bound_scope(report, account);
+
+    if (prepend_format)
+      static_cast&lt;std::ostream&amp;&gt;(report.output_stream)
+	&lt;&lt; prepend_format(bound_scope);
+
     static_cast&lt;std::ostream&amp;&gt;(report.output_stream)
       &lt;&lt; account_line_format(bound_scope);
 
@@ -217,6 +234,11 @@ void format_accounts::flush()
       ! report.HANDLED(no_total) &amp;&amp; ! report.HANDLED(percent)) {
     bind_scope_t bound_scope(report, *report.session.journal-&gt;master);
     out &lt;&lt; separator_format(bound_scope);
+
+    if (prepend_format)
+      static_cast&lt;std::ostream&amp;&gt;(report.output_stream)
+	&lt;&lt; prepend_format(bound_scope);
+
     out &lt;&lt; total_line_format(bound_scope);
   }
 </diff>
      <filename>src/output.cc</filename>
    </modified>
    <modified>
      <diff>@@ -60,13 +60,15 @@ protected:
   format_t  first_line_format;
   format_t  next_lines_format;
   format_t  between_format;
+  format_t  prepend_format;
   xact_t *  last_xact;
   post_t *  last_post;
   bool      print_raw;
 
 public:
   format_posts(report_t&amp; _report, const string&amp; format,
-	       bool _print_raw = false);
+	       bool _print_raw = false,
+	       const optional&lt;string&gt;&amp; _prepend_format = none);
   virtual ~format_posts() {
     TRACE_DTOR(format_posts);
   }
@@ -82,12 +84,14 @@ protected:
   format_t    account_line_format;
   format_t    total_line_format;
   format_t    separator_format;
+  format_t    prepend_format;
   predicate_t disp_pred;
 
   std::list&lt;account_t *&gt; posted_accounts;
 
 public:
-  format_accounts(report_t&amp; _report, const string&amp; _format);
+  format_accounts(report_t&amp; _report, const string&amp; _format,
+		  const optional&lt;string&gt;&amp; _prepend_format = none);
   virtual ~format_accounts() {
     TRACE_DTOR(format_accounts);
   }</diff>
      <filename>src/output.h</filename>
    </modified>
    <modified>
      <diff>@@ -36,7 +36,6 @@
 #include &quot;account.h&quot;
 #include &quot;journal.h&quot;
 #include &quot;interactive.h&quot;
-#include &quot;unistring.h&quot;
 #include &quot;format.h&quot;
 
 namespace ledger {</diff>
      <filename>src/post.cc</filename>
    </modified>
    <modified>
      <diff>@@ -61,6 +61,7 @@ public:
   account_t *	     account;
 
   amount_t	     amount;	// can be null until finalization
+  optional&lt;expr_t&gt;   amount_expr;
   optional&lt;amount_t&gt; cost;
   optional&lt;amount_t&gt; assigned_amount;
 
@@ -212,6 +213,7 @@ private:
     ar &amp; xact;
     ar &amp; account;
     ar &amp; amount;
+    ar &amp; amount_expr;
     ar &amp; cost;
     ar &amp; assigned_amount;
   }</diff>
      <filename>src/post.h</filename>
    </modified>
    <modified>
      <diff>@@ -220,6 +220,10 @@ internal precision.&quot;))
     .def(&quot;in_place_truncate&quot;, &amp;amount_t::in_place_truncate,
 	 return_internal_reference&lt;&gt;())
 
+    .def(&quot;floored&quot;, &amp;amount_t::floored)
+    .def(&quot;in_place_floor&quot;, &amp;amount_t::in_place_floor,
+	 return_internal_reference&lt;&gt;())
+
     .def(&quot;unrounded&quot;, &amp;amount_t::unrounded)
     .def(&quot;in_place_unround&quot;, &amp;amount_t::in_place_unround,
 	 return_internal_reference&lt;&gt;())</diff>
      <filename>src/py_amount.cc</filename>
    </modified>
    <modified>
      <diff>@@ -176,6 +176,10 @@ void export_balance()
     .def(&quot;in_place_truncate&quot;, &amp;balance_t::in_place_truncate,
 	 return_internal_reference&lt;&gt;())
 
+    .def(&quot;floored&quot;, &amp;balance_t::floored)
+    .def(&quot;in_place_floor&quot;, &amp;balance_t::in_place_floor,
+	 return_internal_reference&lt;&gt;())
+
     .def(&quot;unrounded&quot;, &amp;balance_t::unrounded)
     .def(&quot;in_place_unround&quot;, &amp;balance_t::in_place_unround,
 	 return_internal_reference&lt;&gt;())</diff>
      <filename>src/py_balance.cc</filename>
    </modified>
    <modified>
      <diff>@@ -136,8 +136,8 @@ namespace {
     py_xact_finalizer_t(object obj) : pyobj(obj) {}
     py_xact_finalizer_t(const py_xact_finalizer_t&amp; other)
       : pyobj(other.pyobj) {}
-    virtual bool operator()(xact_t&amp; xact, bool post) {
-      return call&lt;bool&gt;(pyobj.ptr(), xact, post);
+    virtual bool operator()(xact_t&amp; xact) {
+      return call&lt;bool&gt;(pyobj.ptr(), xact);
     }
   };
 
@@ -161,9 +161,9 @@ namespace {
       }
   }
 
-  void py_run_xact_finalizers(journal_t&amp; journal, xact_t&amp; xact, bool post)
+  void py_run_xact_finalizers(journal_t&amp; journal, xact_t&amp; xact)
   {
-    journal.xact_finalize_hooks.run_hooks(xact, post);
+    journal.xact_finalize_hooks.run_hooks(xact);
   }
 
   std::size_t py_read(journal_t&amp; journal, const string&amp; pathname)</diff>
      <filename>src/py_journal.cc</filename>
    </modified>
    <modified>
      <diff>@@ -33,6 +33,7 @@
 
 #include &quot;pyinterp.h&quot;
 #include &quot;pyutils.h&quot;
+#include &quot;times.h&quot;
 
 // jww (2007-05-04): Convert time duration objects to PyDelta
 
@@ -40,8 +41,6 @@ namespace ledger {
 
 using namespace boost::python;
 
-typedef boost::gregorian::date date;
-
 #define MY_PyDateTime_IMPORT				\
   PyDateTimeAPI = (PyDateTime_CAPI*)			\
   PyCObject_Import(const_cast&lt;char *&gt;(&quot;datetime&quot;),	\
@@ -49,7 +48,7 @@ typedef boost::gregorian::date date;
 
 struct date_to_python
 {
-  static PyObject* convert(const date&amp; dte)
+  static PyObject* convert(const date_t&amp; dte)
   {
     MY_PyDateTime_IMPORT;
     return PyDate_FromDate(dte.year(), dte.month(), dte.day());
@@ -77,13 +76,13 @@ struct date_from_python
     date::day_type d =
       static_cast&lt;date::day_type&gt;(PyDateTime_GET_DAY(obj_ptr));
 
-    date * dte = new date(y, m, d);
+    date_t * dte = new date_t(y, m, d);
 
     data-&gt;convertible = (void *) dte;
   }
 };
 
-typedef register_python_conversion&lt;date, date_to_python, date_from_python&gt;
+typedef register_python_conversion&lt;date_t, date_to_python, date_from_python&gt;
   date_python_conversion;
 
 
@@ -93,7 +92,7 @@ struct datetime_to_python
   {
     MY_PyDateTime_IMPORT;
 
-    date dte = moment.date();
+    date_t dte = moment.date();
     datetime_t::time_duration_type tod = moment.time_of_day();
 
     return PyDateTime_FromDateAndTime
@@ -127,28 +126,102 @@ struct datetime_from_python
 
     datetime_t::time_duration_type::hour_type h =
       static_cast&lt;datetime_t::time_duration_type::hour_type&gt;
-        (PyDateTime_DATE_GET_HOUR(obj_ptr));
+      (PyDateTime_DATE_GET_HOUR(obj_ptr));
     datetime_t::time_duration_type::min_type min =
       static_cast&lt;datetime_t::time_duration_type::min_type&gt;
-        (PyDateTime_DATE_GET_MINUTE(obj_ptr));
+      (PyDateTime_DATE_GET_MINUTE(obj_ptr));
     datetime_t::time_duration_type::sec_type s =
       static_cast&lt;datetime_t::time_duration_type::sec_type&gt;
-        (PyDateTime_DATE_GET_SECOND(obj_ptr));
+      (PyDateTime_DATE_GET_SECOND(obj_ptr));
     datetime_t::time_duration_type::fractional_seconds_type ms =
       static_cast&lt;datetime_t::time_duration_type::fractional_seconds_type&gt;
-        (PyDateTime_DATE_GET_MICROSECOND(obj_ptr)) * 1000000;
+      (PyDateTime_DATE_GET_MICROSECOND(obj_ptr)) * 1000000;
 
     datetime_t * moment
-      = new datetime_t(date(y, m, d),
+      = new datetime_t(date_t(y, m, d),
 		       datetime_t::time_duration_type(h, min, s, ms));
 
     data-&gt;convertible = (void *) moment;
   }
 };
 
-typedef register_python_conversion&lt;datetime_t, datetime_to_python, datetime_from_python&gt;
+typedef register_python_conversion&lt;datetime_t,
+				   datetime_to_python, datetime_from_python&gt;
   datetime_python_conversion;
 
+
+/* Convert time_duration to/from python */
+struct duration_to_python
+{
+  static int get_usecs(boost::posix_time::time_duration const&amp; d)
+  {
+    static int64_t resolution =
+      boost::posix_time::time_duration::ticks_per_second();
+    int64_t fracsecs = d.fractional_seconds();
+    if (resolution &gt; 1000000)
+      return static_cast&lt;int&gt;(fracsecs / (resolution / 1000000));
+    else
+      return static_cast&lt;int&gt;(fracsecs * (1000000 / resolution));
+  }
+
+  static PyObject * convert(posix_time::time_duration d)
+  {
+    int days = d.hours() / 24;
+    if (days &lt; 0)
+      days --;
+    int seconds = d.total_seconds() - days*(24*3600);
+    int usecs = get_usecs(d);
+    if (days &lt; 0)
+      usecs = 1000000-1 - usecs;
+    return PyDelta_FromDSU(days, seconds, usecs);
+  }
+};
+
+/* Should support the negative values, but not the special boost time
+   durations */
+struct duration_from_python
+{
+  static void* convertible(PyObject * obj_ptr)
+  {
+    if ( ! PyDelta_Check(obj_ptr))
+      return 0;
+    return obj_ptr;
+  }
+
+  static void construct(PyObject* obj_ptr,
+			python::converter::rvalue_from_python_stage1_data * data)
+  {
+    PyDateTime_Delta const* pydelta
+      = reinterpret_cast&lt;PyDateTime_Delta*&gt;(obj_ptr);
+
+    int days = pydelta-&gt;days;
+    bool is_negative = (days &lt; 0);
+    if (is_negative)
+      days = -days;
+
+    // Create time duration object
+    posix_time::time_duration
+      duration = (posix_time::hours(24) * days +
+		  posix_time::seconds(pydelta-&gt;seconds) +
+		  posix_time::microseconds(pydelta-&gt;microseconds));
+    if (is_negative)
+      duration = duration.invert_sign();
+
+    void * storage =
+      reinterpret_cast&lt;converter::rvalue_from_python_storage
+                       &lt;posix_time::time_duration&gt; *&gt;
+                      (data)-&gt;storage.bytes;
+
+    new (storage) posix_time::time_duration(duration);
+    data-&gt;convertible = storage;
+  }
+};
+
+typedef register_python_conversion&lt;time_duration_t,
+				   duration_to_python, duration_from_python&gt;
+  duration_python_conversion;
+
+
 datetime_t py_parse_datetime(const string&amp; str) {
   return parse_datetime(str);
 }
@@ -161,6 +234,7 @@ void export_times()
 {
   datetime_python_conversion();
   date_python_conversion();
+  duration_python_conversion();
 
   register_optional_to_python&lt;datetime_t&gt;();
   register_optional_to_python&lt;date_t&gt;();</diff>
      <filename>src/py_times.cc</filename>
    </modified>
    <modified>
      <diff>@@ -61,7 +61,8 @@ struct bool_from_python
   static void construct(PyObject* obj_ptr,
 			converter::rvalue_from_python_stage1_data* data)
   {
-    void* storage = ((converter::rvalue_from_python_storage&lt;bool&gt;*) data)-&gt;storage.bytes;
+    void * storage =
+      ((converter::rvalue_from_python_storage&lt;bool&gt;*) data)-&gt;storage.bytes;
     if (obj_ptr == Py_True)
       new (storage) bool(true);
     else
@@ -74,13 +75,19 @@ typedef register_python_conversion&lt;bool, bool_to_python, bool_from_python&gt;
   bool_python_conversion;
 
 
-#if defined(STRING_VERIFY_ON)
-
 struct string_to_python
 {
-  static PyObject* convert(const ledger::string&amp; str)
+  static PyObject* convert(const string&amp; str)
   {
+#if 1
+    // Return a Unicode object
+    PyObject * pstr = PyString_FromString(str.c_str());
+    PyObject * uni  = PyUnicode_FromEncodedObject(pstr, &quot;UTF-8&quot;, NULL);
+    return object(handle&lt;&gt;(borrowed(uni))).ptr();
+#else
+    // Return a 7-bit ASCII string
     return incref(object(static_cast&lt;const std::string&amp;&gt;(str)).ptr());
+#endif
   }
 };
 
@@ -88,26 +95,49 @@ struct string_from_python
 {
   static void* convertible(PyObject* obj_ptr)
   {
-    if (!PyString_Check(obj_ptr)) return 0;
+    if (!PyUnicode_Check(obj_ptr) &amp;&amp;
+	!PyString_Check(obj_ptr)) return 0;
     return obj_ptr;
   }
 
-  static void construct(PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
+  static void construct(PyObject* obj_ptr,
+			converter::rvalue_from_python_stage1_data* data)
   {
-    const char* value = PyString_AsString(obj_ptr);
-    if (value == 0) throw_error_already_set();
-    void* storage =
-      reinterpret_cast&lt;converter::rvalue_from_python_storage&lt;ledger::string&gt; *&gt;(data)-&gt;storage.bytes;
-    new (storage) ledger::string(value);
-    data-&gt;convertible = storage;
+    if (PyString_Check(obj_ptr)) {
+      const char* value = PyString_AsString(obj_ptr);
+      if (value == 0) throw_error_already_set();
+      void* storage =
+	reinterpret_cast&lt;converter::rvalue_from_python_storage&lt;string&gt; *&gt;
+	                (data)-&gt;storage.bytes;
+      new (storage) string(value);
+      data-&gt;convertible = storage;
+    } else {
+      VERIFY(PyUnicode_Check(obj_ptr));
+
+      Py_ssize_t size = PyUnicode_GET_SIZE(obj_ptr);
+      const Py_UNICODE* value = PyUnicode_AS_UNICODE(obj_ptr);
+
+      string str;
+      if (sizeof(Py_UNICODE) == 2) // UTF-16
+	utf8::unchecked::utf16to8(value, value + size, std::back_inserter(str));
+      else if (sizeof(Py_UNICODE) == 4) // UTF-32
+	utf8::unchecked::utf32to8(value, value + size, std::back_inserter(str));
+      else
+	assert(! &quot;Py_UNICODE has an unexpected size&quot;);
+
+      if (value == 0) throw_error_already_set();
+      void* storage =
+	reinterpret_cast&lt;converter::rvalue_from_python_storage&lt;string&gt; *&gt;
+	                (data)-&gt;storage.bytes;
+      new (storage) string(str);
+      data-&gt;convertible = storage;
+    }
   }
 };
 
-typedef register_python_conversion&lt;ledger::string, string_to_python, string_from_python&gt;
+typedef register_python_conversion&lt;string, string_to_python, string_from_python&gt;
   string_python_conversion;
 
-#endif // STRING_VERIFY_ON
-
 
 struct istream_to_python
 {
@@ -125,16 +155,19 @@ struct istream_from_python
     return obj_ptr;
   }
 
-  static void construct(PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
+  static void construct(PyObject* obj_ptr,
+			converter::rvalue_from_python_stage1_data* data)
   {
     void* storage =
-      reinterpret_cast&lt;converter::rvalue_from_python_storage&lt;pyifstream&gt; *&gt;(data)-&gt;storage.bytes;
+      reinterpret_cast&lt;converter::rvalue_from_python_storage&lt;pyifstream&gt; *&gt;
+                      (data)-&gt;storage.bytes;
     new (storage) pyifstream(reinterpret_cast&lt;PyFileObject *&gt;(obj_ptr));
     data-&gt;convertible = storage;
   }
 };
 
-typedef register_python_conversion&lt;std::istream, istream_to_python, istream_from_python&gt;
+typedef register_python_conversion&lt;std::istream,
+				   istream_to_python, istream_from_python&gt;
   istream_python_conversion;
 
 
@@ -154,15 +187,19 @@ struct ostream_from_python
     return obj_ptr;
   }
 
-  static void construct(PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
+  static void construct(PyObject* obj_ptr,
+			converter::rvalue_from_python_stage1_data* data)
   {
-    void* storage = reinterpret_cast&lt;converter::rvalue_from_python_storage&lt;pyofstream&gt; *&gt;(data)-&gt;storage.bytes;
+    void* storage =
+      reinterpret_cast&lt;converter::rvalue_from_python_storage&lt;pyofstream&gt; *&gt;
+                      (data)-&gt;storage.bytes;
     new (storage) pyofstream(reinterpret_cast&lt;PyFileObject *&gt;(obj_ptr));
     data-&gt;convertible = storage;
   }
 };
 
-typedef register_python_conversion&lt;std::ostream, ostream_to_python, ostream_from_python&gt;
+typedef register_python_conversion&lt;std::ostream,
+				   ostream_to_python, ostream_from_python&gt;
   ostream_python_conversion;
 
 
@@ -216,9 +253,7 @@ void export_utils()
     ;
 
   bool_python_conversion();
-#if defined(STRING_VERIFY_ON)
   string_python_conversion();
-#endif
   istream_python_conversion();
   ostream_python_conversion();
 }</diff>
      <filename>src/py_utils.cc</filename>
    </modified>
    <modified>
      <diff>@@ -47,6 +47,22 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_string_overloads, set_string, 0, 2)
 
 namespace {
 
+  PyObject * py_base_type(value_t&amp; value) {
+    if (value.is_boolean()) {
+      return (PyObject *)&amp;PyBool_Type;
+    }
+    else if (value.is_long()) {
+      return (PyObject *)&amp;PyInt_Type;
+    }
+    else if (value.is_string()) {
+      return (PyObject *)&amp;PyUnicode_Type;
+    }
+    else {
+      object typeobj(object(value).attr(&quot;__class__&quot;));
+      return typeobj.ptr();
+    }
+  }
+
   expr_t py_value_getattr(const value_t&amp; value, const string&amp; name)
   {
     if (value.is_scope()) {
@@ -218,6 +234,8 @@ void export_value()
     .def(&quot;in_place_round&quot;, &amp;value_t::in_place_round)
     .def(&quot;truncated&quot;, &amp;value_t::truncated)
     .def(&quot;in_place_truncate&quot;, &amp;value_t::in_place_truncate)
+    .def(&quot;floored&quot;, &amp;value_t::floored)
+    .def(&quot;in_place_floor&quot;, &amp;value_t::in_place_floor)
     .def(&quot;unrounded&quot;, &amp;value_t::unrounded)
     .def(&quot;in_place_unround&quot;, &amp;value_t::in_place_unround)
     .def(&quot;reduced&quot;, &amp;value_t::reduced)
@@ -305,6 +323,12 @@ void export_value()
     .def(&quot;label&quot;, &amp;value_t::label)
 
     .def(&quot;valid&quot;, &amp;value_t::valid)
+
+    .def(&quot;basetype&quot;, py_base_type)
+    ;
+
+  class_&lt; value_t::sequence_t &gt; (&quot;ValueSequence&quot;)
+    .def(vector_indexing_suite&lt; value_t::sequence_t &gt;());
     ;
 
   scope().attr(&quot;NULL_VALUE&quot;)    = NULL_VALUE;</diff>
      <filename>src/py_value.cc</filename>
    </modified>
    <modified>
      <diff>@@ -99,66 +99,75 @@ void python_interpreter_t::initialize()
     Py_Initialize();
     assert(Py_IsInitialized());
 
+    hack_system_paths();
+
     object main_module = python::import(&quot;__main__&quot;);
     if (! main_module)
-      throw_(std::logic_error,
+      throw_(std::runtime_error,
 	     _(&quot;Python failed to initialize (couldn't find __main__)&quot;));
 
     main_nspace = extract&lt;dict&gt;(main_module.attr(&quot;__dict__&quot;));
     if (! main_nspace)
-      throw_(std::logic_error,
+      throw_(std::runtime_error,
 	     _(&quot;Python failed to initialize (couldn't find __dict__)&quot;));
 
     python::detail::init_module(&quot;ledger&quot;, &amp;initialize_for_python);
 
     is_initialized = true;
+  }
+  catch (const error_already_set&amp;) {
+    PyErr_Print();
+    throw_(std::runtime_error, _(&quot;Python failed to initialize&quot;));
+  }
 
-    // Hack ledger.__path__ so it points to a real location
-    python::object module_sys = import(&quot;sys&quot;); 
-    python::object sys_dict   = module_sys.attr(&quot;__dict__&quot;);
-
-    python::list paths(sys_dict[&quot;path&quot;]);
-
-    bool path_initialized = false;
-    int n = python::extract&lt;int&gt;(paths.attr(&quot;__len__&quot;)());
-    for (int i = 0; i &lt; n; i++) {
-      python::extract&lt;std::string&gt; str(paths[i]);
-      path pathname(str);
-      DEBUG(&quot;python.interp&quot;, &quot;sys.path = &quot; &lt;&lt; pathname);
+  TRACE_FINISH(python_init, 1);
+}
 
-      if (exists(pathname / &quot;ledger&quot; / &quot;__init__.py&quot;)) {
-	if (python::object module_ledger = import(&quot;ledger&quot;)) {
-	  DEBUG(&quot;python.interp&quot;,
-		&quot;Setting ledger.__path__ = &quot; &lt;&lt; (pathname / &quot;ledger&quot;));
+void python_interpreter_t::hack_system_paths()
+{
+  // Hack ledger.__path__ so it points to a real location
+  python::object sys_module = python::import(&quot;sys&quot;); 
+  python::object sys_dict   = sys_module.attr(&quot;__dict__&quot;);
 
-	  python::object ledger_dict = module_ledger.attr(&quot;__dict__&quot;);
-	  python::list temp_list;
-	  temp_list.append((pathname / &quot;ledger&quot;).string());
+  python::list paths(sys_dict[&quot;path&quot;]);
 
-	  ledger_dict[&quot;__path__&quot;] = temp_list;
-	} else {
-	  throw_(std::logic_error,
-		 _(&quot;Python failed to initialize (couldn't find ledger)&quot;));
-	}
-	path_initialized = true;
-	break;
+#if defined(DEBUG_ON)
+  bool path_initialized = false;
+#endif
+  int n = python::extract&lt;int&gt;(paths.attr(&quot;__len__&quot;)());
+  for (int i = 0; i &lt; n; i++) {
+    python::extract&lt;std::string&gt; str(paths[i]);
+    path pathname(str);
+    DEBUG(&quot;python.interp&quot;, &quot;sys.path = &quot; &lt;&lt; pathname);
+
+    if (exists(pathname / &quot;ledger&quot; / &quot;__init__.py&quot;)) {
+      if (python::object module_ledger = python::import(&quot;ledger&quot;)) {
+	DEBUG(&quot;python.interp&quot;,
+	      &quot;Setting ledger.__path__ = &quot; &lt;&lt; (pathname / &quot;ledger&quot;));
+
+	python::object ledger_dict = module_ledger.attr(&quot;__dict__&quot;);
+	python::list temp_list;
+	temp_list.append((pathname / &quot;ledger&quot;).string());
+
+	ledger_dict[&quot;__path__&quot;] = temp_list;
+      } else {
+	throw_(std::runtime_error,
+	       _(&quot;Python failed to initialize (couldn't find ledger)&quot;));
       }
-    }
 #if defined(DEBUG_ON)
-    if (! path_initialized)
-      DEBUG(&quot;python.init&quot;,
-	    &quot;Ledger failed to find 'ledger/__init__.py' on the PYTHONPATH&quot;);
+      path_initialized = true;
 #endif
+      break;
+    }
   }
-  catch (const error_already_set&amp;) {
-    PyErr_Print();
-    throw_(std::logic_error, _(&quot;Python failed to initialize&quot;));
-  }
-
-  TRACE_FINISH(python_init, 1);
+#if defined(DEBUG_ON)
+  if (! path_initialized)
+    DEBUG(&quot;python.init&quot;,
+	  &quot;Ledger failed to find 'ledger/__init__.py' on the PYTHONPATH&quot;);
+#endif
 }
 
-object python_interpreter_t::import(const string&amp; str)
+object python_interpreter_t::import_into_main(const string&amp; str)
 {
   if (! is_initialized)
     initialize();
@@ -166,7 +175,8 @@ object python_interpreter_t::import(const string&amp; str)
   try {
     object mod = python::import(str.c_str());
     if (! mod)
-      throw_(std::logic_error, _(&quot;Failed to import Python module %1&quot;) &lt;&lt; str);
+      throw_(std::runtime_error,
+	     _(&quot;Failed to import Python module %1&quot;) &lt;&lt; str);
  
     // Import all top-level entries directly into the main namespace
     main_nspace.update(mod.attr(&quot;__dict__&quot;));
@@ -179,6 +189,32 @@ object python_interpreter_t::import(const string&amp; str)
   return object();
 }
 
+object python_interpreter_t::import_option(const string&amp; str)
+{
+  path file(str);
+
+  python::object sys_module = python::import(&quot;sys&quot;); 
+  python::object sys_dict   = sys_module.attr(&quot;__dict__&quot;);
+
+  python::list paths(sys_dict[&quot;path&quot;]);
+
+#if BOOST_VERSION &gt;= 103700
+  paths.insert(0, file.parent_path().string());
+  sys_dict[&quot;path&quot;] = paths;
+
+  string name = file.filename();
+  if (contains(name, &quot;.py&quot;))
+    name = file.stem();
+#else // BOOST_VERSION &gt;= 103700
+  paths.insert(0, file.branch_path().string());
+  sys_dict[&quot;path&quot;] = paths;
+
+  string name = file.leaf();
+#endif // BOOST_VERSION &gt;= 103700
+
+  return python::import(python::str(name.c_str()));
+}
+
 object python_interpreter_t::eval(std::istream&amp; in, py_eval_mode_t mode)
 {
   bool	 first = true;
@@ -212,7 +248,7 @@ object python_interpreter_t::eval(std::istream&amp; in, py_eval_mode_t mode)
   }
   catch (const error_already_set&amp;) {
     PyErr_Print();
-    throw_(std::logic_error, _(&quot;Failed to evaluate Python code&quot;));
+    throw_(std::runtime_error, _(&quot;Failed to evaluate Python code&quot;));
   }
   return object();
 }
@@ -234,7 +270,7 @@ object python_interpreter_t::eval(const string&amp; str, py_eval_mode_t mode)
   }
   catch (const error_already_set&amp;) {
     PyErr_Print();
-    throw_(std::logic_error, _(&quot;Failed to evaluate Python code&quot;));
+    throw_(std::runtime_error, _(&quot;Failed to evaluate Python code&quot;));
   }
   return object();
 }
@@ -255,7 +291,7 @@ value_t python_interpreter_t::python_command(call_scope_t&amp; args)
     std::strcpy(argv[i + 1], arg.c_str());
   }
 
-  int status;
+  int status = 1;
 
   try {
     status = Py_Main(static_cast&lt;int&gt;(args.size()) + 1, argv);
@@ -277,6 +313,44 @@ value_t python_interpreter_t::python_command(call_scope_t&amp; args)
   return NULL_VALUE;
 }
 
+value_t python_interpreter_t::server_command(call_scope_t&amp; args)
+{
+  if (! is_initialized)
+    initialize();
+
+  python::object server_module;
+
+  try {
+    server_module = python::import(&quot;ledger.server&quot;);
+    if (! server_module)
+      throw_(std::runtime_error,
+	     _(&quot;Could not import ledger.server; please check your PYTHONPATH&quot;));
+  }
+  catch (const error_already_set&amp;) {
+    PyErr_Print();
+    throw_(std::runtime_error,
+	   _(&quot;Could not import ledger.server; please check your PYTHONPATH&quot;));
+  }
+
+  if (python::object main_function = server_module.attr(&quot;main&quot;)) {
+    functor_t func(main_function, &quot;main&quot;);
+    try {
+      func(args);
+    }
+    catch (const error_already_set&amp;) {
+      PyErr_Print();
+      throw_(std::runtime_error,
+	     _(&quot;Error while invoking ledger.server's main() function&quot;));
+    }
+    return true;
+  } else {
+      throw_(std::runtime_error,
+	     _(&quot;The ledger.server module is missing its main() function!&quot;));
+  }
+
+  return false;
+}
+
 option_t&lt;python_interpreter_t&gt; *
 python_interpreter_t::lookup_option(const char * p)
 {
@@ -304,7 +378,7 @@ expr_t::ptr_op_t python_interpreter_t::lookup(const symbol_t::kind_t kind,
       DEBUG(&quot;python.interp&quot;, &quot;Python lookup: &quot; &lt;&lt; name);
 
       if (python::object obj = main_nspace.get(name.c_str()))
-	return WRAP_FUNCTOR(functor_t(name, obj));
+	return WRAP_FUNCTOR(functor_t(obj, name));
     }
     break;
 
@@ -320,6 +394,11 @@ expr_t::ptr_op_t python_interpreter_t::lookup(const symbol_t::kind_t kind,
       if (is_eq(p, &quot;python&quot;))
 	return MAKE_FUNCTOR(python_interpreter_t::python_command);
       break;
+
+    case 's':
+      if (is_eq(p, &quot;server&quot;))
+	return MAKE_FUNCTOR(python_interpreter_t::server_command);
+      break;
     }
   }
 
@@ -349,7 +428,7 @@ namespace {
 	       dynamic_cast&lt;const auto_xact_t *&gt;(scope))
 	lst.append(ptr(auto_xact));
       else
-	throw_(std::runtime_error,
+	throw_(std::logic_error,
 	       _(&quot;Cannot downcast scoped object to specific type&quot;));
     } else {
       lst.append(value);</diff>
      <filename>src/pyinterp.cc</filename>
    </modified>
    <modified>
      <diff>@@ -57,8 +57,10 @@ public:
   }
 
   void initialize();
+  void hack_system_paths();
 
-  python::object import(const string&amp; name);
+  python::object import_into_main(const string&amp; name);
+  python::object import_option(const string&amp; name);
 
   enum py_eval_mode_t {
     PY_EVAL_EXPR,
@@ -67,16 +69,17 @@ public:
   };
 
   python::object eval(std::istream&amp; in,
-			     py_eval_mode_t mode = PY_EVAL_EXPR);
+		      py_eval_mode_t mode = PY_EVAL_EXPR);
   python::object eval(const string&amp; str,
-			     py_eval_mode_t mode = PY_EVAL_EXPR);
+		      py_eval_mode_t mode = PY_EVAL_EXPR);
   python::object eval(const char * c_str,
-			     py_eval_mode_t mode = PY_EVAL_EXPR) {
+		      py_eval_mode_t mode = PY_EVAL_EXPR) {
     string str(c_str);
     return eval(str, mode);
   }
 
   value_t python_command(call_scope_t&amp; scope);
+  value_t server_command(call_scope_t&amp; args);
 
   class functor_t {
     functor_t();
@@ -87,9 +90,9 @@ public:
   public:
     string name;
 
-    functor_t(const string&amp; _name, python::object _func)
+    functor_t(python::object _func, const string&amp; _name)
       : func(_func), name(_name) {
-      TRACE_CTOR(functor_t, &quot;const string&amp;, python::object&quot;);
+      TRACE_CTOR(functor_t, &quot;python::object, const string&amp;&quot;);
     }
     functor_t(const functor_t&amp; other)
       : func(other.func), name(other.name) {
@@ -106,41 +109,10 @@ public:
   virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
 				  const string&amp; name);
 
-#if BOOST_VERSION &gt;= 103700
   OPTION_(python_interpreter_t, import_, DO_(scope) {
-      interactive_t args(scope, &quot;s&quot;);
-
-      path file(args.get&lt;string&gt;(0));
-
-      python::object module_sys = parent-&gt;import(&quot;sys&quot;); 
-      python::object sys_dict	= module_sys.attr(&quot;__dict__&quot;);
-
-      python::list paths(sys_dict[&quot;path&quot;]);
-      paths.insert(0, file.parent_path().string());
-      sys_dict[&quot;path&quot;] = paths;
-
-      string name = file.filename();
-      if (contains(name, &quot;.py&quot;))
-	parent-&gt;import(file.stem());
-      else
-	parent-&gt;import(name);
-    });
-#else // BOOST_VERSION &gt;= 103700
-  OPTION_(python_interpreter_t, import_, DO_(scope) {
-      interactive_t args(scope, &quot;s&quot;);
-
-      path file(args.get&lt;string&gt;(0));
-
-      python::object module_sys = parent-&gt;import(&quot;sys&quot;); 
-      python::object sys_dict	= module_sys.attr(&quot;__dict__&quot;);
-
-      python::list paths(sys_dict[&quot;path&quot;]);
-      paths.insert(0, file.branch_path().string());
-      sys_dict[&quot;path&quot;] = paths;
-
-      parent-&gt;import(file.leaf());
+      interactive_t args(scope, &quot;ss&quot;);
+      parent-&gt;import_option(args.get&lt;string&gt;(1));
     });
-#endif // BOOST_VERSION &gt;= 103700
 };
 
 extern shared_ptr&lt;python_interpreter_t&gt; python_session;</diff>
      <filename>src/pyinterp.h</filename>
    </modified>
    <modified>
      <diff>@@ -36,7 +36,7 @@ template &lt;typename T, typename TfromPy&gt;
 struct object_from_python
 {
   object_from_python() {
-    boost::python::converter::registry::push_back
+    boost::python::converter::registry::insert
       (&amp;TfromPy::convertible, &amp;TfromPy::construct,
        boost::python::type_id&lt;T&gt;());
   }
@@ -106,6 +106,55 @@ struct register_optional_to_python : public boost::noncopyable
   }
 };
 
+namespace boost { namespace python {
+
+// Use expr to create the PyObject corresponding to x
+# define BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(T, expr, pytype)\
+    template &lt;&gt; struct to_python_value&lt;T&amp;&gt;                      \
+        : detail::builtin_to_python                             \
+    {                                                           \
+        inline PyObject* operator()(T const&amp; x) const           \
+        {                                                       \
+            return (expr);                                      \
+        }                                                       \
+        inline PyTypeObject const* get_pytype() const           \
+        {                                                       \
+            return (pytype);                                    \
+        }                                                       \
+    };                                                          \
+    template &lt;&gt; struct to_python_value&lt;T const&amp;&gt;                \
+        : detail::builtin_to_python                             \
+    {                                                           \
+        inline PyObject* operator()(T const&amp; x) const           \
+        {                                                       \
+            return (expr);                                      \
+        }                                                       \
+        inline PyTypeObject const* get_pytype() const           \
+        {                                                       \
+            return (pytype);                                    \
+        }                                                       \
+    };
+
+# define BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE(T, expr)   \
+    namespace converter                                 \
+    {                                                   \
+      template &lt;&gt; struct arg_to_python&lt; T &gt;             \
+        : handle&lt;&gt;                                      \
+      {                                                 \
+          arg_to_python(T const&amp; x)                     \
+            : python::handle&lt;&gt;(expr) {}                 \
+      };                                                \
+    } 
+
+// Specialize argument and return value converters for T using expr
+# define BOOST_PYTHON_TO_PYTHON_BY_VALUE(T, expr, pytype)  \
+        BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(T,expr, pytype)  \
+        BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE(T,expr)
+
+BOOST_PYTHON_TO_PYTHON_BY_VALUE(ledger::string, ::PyUnicode_FromEncodedObject(::PyString_FromString(x.c_str()), &quot;UTF-8&quot;, NULL), &amp;PyUnicode_Type)
+
+} } // namespace boost::python
+
 //boost::python::register_ptr_to_python&lt; boost::shared_ptr&lt;Base&gt; &gt;();
 
 #endif // _PY_UTILS_H</diff>
      <filename>src/pyutils.h</filename>
    </modified>
    <modified>
      <diff>@@ -155,8 +155,6 @@ query_t::lexer_t::token_t query_t::lexer_t::next_token()
       return token_t(token_t::TOK_PAYEE);
     else if (ident == &quot;note&quot;)
       return token_t(token_t::TOK_NOTE);
-    else if (ident == &quot;account&quot;)
-      return token_t(token_t::TOK_ACCOUNT);
     else if (ident == &quot;tag&quot;)
       return token_t(token_t::TOK_META);
     else if (ident == &quot;meta&quot;)</diff>
      <filename>src/query.cc</filename>
    </modified>
    <modified>
      <diff>@@ -33,7 +33,6 @@
 
 #include &quot;report.h&quot;
 #include &quot;session.h&quot;
-#include &quot;unistring.h&quot;
 #include &quot;format.h&quot;
 #include &quot;query.h&quot;
 #include &quot;output.h&quot;
@@ -208,6 +207,12 @@ value_t report_t::fn_quantity(call_scope_t&amp; scope)
   return args.get&lt;amount_t&gt;(0).number();
 }
 
+value_t report_t::fn_floor(call_scope_t&amp; scope)
+{
+  interactive_t args(scope, &quot;v&quot;);
+  return args.value_at(0).floored();
+}
+
 value_t report_t::fn_abs(call_scope_t&amp; scope)
 {
   interactive_t args(scope, &quot;v&quot;);
@@ -453,15 +458,6 @@ value_t report_t::echo_command(call_scope_t&amp; scope)
   return true;
 }
 
-bool report_t::maybe_import(const string&amp; module)
-{
-  if (lookup(symbol_t::OPTION, &quot;import_&quot;)) {
-    expr_t(string(&quot;import_(\&quot;&quot;) + module + &quot;\&quot;)&quot;).calc(*this);
-    return true;
-  }
-  return false;
-}
-
 option_t&lt;report_t&gt; * report_t::lookup_option(const char * p)
 {
   switch (*p) {
@@ -641,6 +637,7 @@ option_t&lt;report_t&gt; * report_t::lookup_option(const char * p)
     else OPT(pricesdb_format_);
     else OPT(print_format_);
     else OPT(payee_width_);
+    else OPT(prepend_format_);
     break;
   case 'q':
     OPT(quantity);
@@ -744,6 +741,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
     case 'f':
       if (is_eq(p, &quot;format_date&quot;))
 	return MAKE_FUNCTOR(report_t::fn_format_date);
+      else if (is_eq(p, &quot;floor&quot;))
+	return MAKE_FUNCTOR(report_t::fn_floor);
       break;
 
     case 'g':
@@ -864,7 +863,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
       if (*(p + 1) == '\0' || is_eq(p, &quot;bal&quot;) || is_eq(p, &quot;balance&quot;)) {
 	return expr_t::op_t::wrap_functor
 	  (reporter&lt;account_t, acct_handler_ptr, &amp;report_t::accounts_report&gt;
-	   (new format_accounts(*this, report_format(HANDLER(balance_format_))),
+	   (new format_accounts(*this, report_format(HANDLER(balance_format_)),
+				maybe_format(HANDLER(prepend_format_))),
 	    *this, &quot;#balance&quot;));
       }
       else if (is_eq(p, &quot;budget&quot;)) {
@@ -876,7 +876,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
 
 	return expr_t::op_t::wrap_functor
 	  (reporter&lt;account_t, acct_handler_ptr, &amp;report_t::accounts_report&gt;
-	   (new format_accounts(*this, report_format(HANDLER(budget_format_))),
+	   (new format_accounts(*this, report_format(HANDLER(budget_format_)),
+				maybe_format(HANDLER(prepend_format_))),
 	    *this, &quot;#budget&quot;));
       }
       break;
@@ -885,7 +886,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
       if (is_eq(p, &quot;csv&quot;)) {
 	return WRAP_FUNCTOR
 	  (reporter&lt;&gt;
-	   (new format_posts(*this, report_format(HANDLER(csv_format_))),
+	   (new format_posts(*this, report_format(HANDLER(csv_format_)),
+			     maybe_format(HANDLER(prepend_format_))),
 	    *this, &quot;#csv&quot;));
       }
       else if (is_eq(p, &quot;cleared&quot;)) {
@@ -894,7 +896,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
 
 	return expr_t::op_t::wrap_functor
 	  (reporter&lt;account_t, acct_handler_ptr, &amp;report_t::accounts_report&gt;
-	   (new format_accounts(*this, report_format(HANDLER(cleared_format_))),
+	   (new format_accounts(*this, report_format(HANDLER(cleared_format_)),
+				maybe_format(HANDLER(prepend_format_))),
 	    *this, &quot;#cleared&quot;));
       }
       break;
@@ -923,22 +926,23 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
       else if (is_eq(p, &quot;prices&quot;))
 	return expr_t::op_t::wrap_functor
 	  (reporter&lt;post_t, post_handler_ptr, &amp;report_t::commodities_report&gt;
-	   (new format_posts(*this, report_format(HANDLER(prices_format_))),
+	   (new format_posts(*this, report_format(HANDLER(prices_format_)),
+			     maybe_format(HANDLER(prepend_format_))),
 	    *this, &quot;#prices&quot;));
       else if (is_eq(p, &quot;pricesdb&quot;))
 	return expr_t::op_t::wrap_functor
 	  (reporter&lt;post_t, post_handler_ptr, &amp;report_t::commodities_report&gt;
-	   (new format_posts(*this, report_format(HANDLER(pricesdb_format_))),
+	   (new format_posts(*this, report_format(HANDLER(pricesdb_format_)),
+			     maybe_format(HANDLER(prepend_format_))),
 	    *this, &quot;#pricesdb&quot;));
-      else if (is_eq(p, &quot;python&quot;) &amp;&amp; maybe_import(&quot;ledger.interp&quot;))
-	return session.lookup(symbol_t::COMMAND, &quot;python&quot;);
       break;
 
     case 'r':
       if (*(p + 1) == '\0' || is_eq(p, &quot;reg&quot;) || is_eq(p, &quot;register&quot;))
 	return WRAP_FUNCTOR
 	  (reporter&lt;&gt;
-	   (new format_posts(*this, report_format(HANDLER(register_format_))),
+	   (new format_posts(*this, report_format(HANDLER(register_format_)),
+			     false, maybe_format(HANDLER(prepend_format_))),
 	    *this, &quot;#register&quot;));
       else if (is_eq(p, &quot;reload&quot;))
 	return MAKE_FUNCTOR(report_t::reload_command);
@@ -947,9 +951,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
     case 's':
       if (is_eq(p, &quot;stats&quot;) || is_eq(p, &quot;stat&quot;))
 	return WRAP_FUNCTOR(report_statistics);
-      else
-	if (is_eq(p, &quot;server&quot;) &amp;&amp; maybe_import(&quot;ledger.server&quot;))
-	  return session.lookup(symbol_t::COMMAND, &quot;server&quot;);
+      else if (is_eq(p, &quot;server&quot;))
+	return session.lookup(symbol_t::COMMAND, &quot;server&quot;);
       break;
 
     case 'x':
@@ -981,10 +984,6 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
 	  (reporter&lt;post_t, post_handler_ptr, &amp;report_t::generate_report&gt;
 	   (new format_posts(*this, report_format(HANDLER(print_format_)),
 			     false), *this, &quot;#generate&quot;));
-    case 'h':
-      if (is_eq(p, &quot;hello&quot;) &amp;&amp; maybe_import(&quot;ledger.hello&quot;))
-	return session.lookup(symbol_t::PRECOMMAND, &quot;hello&quot;);
-      break;
     case 'p':
       if (is_eq(p, &quot;parse&quot;))
 	return WRAP_FUNCTOR(parse_command);</diff>
      <filename>src/report.cc</filename>
    </modified>
    <modified>
      <diff>@@ -143,6 +143,7 @@ public:
   value_t fn_rounded(call_scope_t&amp; scope);
   value_t fn_unrounded(call_scope_t&amp; scope);
   value_t fn_truncated(call_scope_t&amp; scope);
+  value_t fn_floor(call_scope_t&amp; scope);
   value_t fn_abs(call_scope_t&amp; scope);
   value_t fn_justify(call_scope_t&amp; scope);
   value_t fn_quoted(call_scope_t&amp; scope);
@@ -172,6 +173,12 @@ public:
     return option.str();
   }
 
+  optional&lt;string&gt; maybe_format(option_t&lt;report_t&gt;&amp; option) {
+    if (option)
+      return option.str();
+    return none;
+  }
+
   value_t reload_command(call_scope_t&amp;);
   value_t echo_command(call_scope_t&amp; scope);
 
@@ -183,8 +190,6 @@ public:
 			  HANDLED(lots_actual));
   }
 
-  bool maybe_import(const string&amp; module);
-
   void report_options(std::ostream&amp; out)
   {
     HANDLER(abbrev_len_).report(out);
@@ -254,6 +259,7 @@ public:
     HANDLER(period_).report(out);
     HANDLER(plot_amount_format_).report(out);
     HANDLER(plot_total_format_).report(out);
+    HANDLER(prepend_format_).report(out);
     HANDLER(price).report(out);
     HANDLER(prices_format_).report(out);
     HANDLER(pricesdb_format_).report(out);
@@ -695,6 +701,8 @@ public:
 	 &quot;%(format_date(date, \&quot;%Y-%m-%d\&quot;)) %(quantity(scrub(display_total)))\n&quot;);
     });
 
+  OPTION(report_t, prepend_format_);
+
   OPTION_(report_t, price, DO() { // -I
       parent-&gt;HANDLER(display_amount_)
 	.set_expr(string(&quot;--price&quot;), &quot;price(amount_expr)&quot;);</diff>
      <filename>src/report.h</filename>
    </modified>
    <modified>
      <diff>@@ -246,8 +246,10 @@ void serialize(Archive&amp; ar, istream_pos_type&amp; pos, const unsigned int)
 
 #include &lt;boost/python/detail/wrap_python.hpp&gt;
 #include &lt;datetime.h&gt;
+#include &lt;unicodeobject.h&gt;
 
 #include &lt;boost/python/module_init.hpp&gt;
+#include &lt;boost/python/suite/indexing/vector_indexing_suite.hpp&gt;
 
 #endif // HAVE_BOOST_PYTHON
 </diff>
      <filename>src/system.hh.in</filename>
    </modified>
    <modified>
      <diff>@@ -132,10 +132,12 @@ namespace {
 			std::streamsize len,
 			account_t *	account,
 			xact_t *	xact,
-			bool            honor_strict = true);
+			bool            honor_strict = true,
+			bool            defer_expr   = false);
 
-    bool parse_posts(account_t *   account,
-		     xact_base_t&amp; xact);
+    bool parse_posts(account_t *  account,
+		     xact_base_t&amp; xact,
+		     const bool   defer_expr = false);
 
     xact_t * parse_xact(char *	  line,
 			  std::streamsize len,
@@ -145,11 +147,13 @@ namespace {
 				    const string&amp; name);
   };
 
-  void parse_amount_expr(scope_t&amp;             scope,
-			 std::istream&amp;        in,
-			 amount_t&amp;            amount,
-			 post_t *             post,
-			 const parse_flags_t&amp; flags = PARSE_DEFAULT)
+  void parse_amount_expr(scope_t&amp;	      scope,
+			 std::istream&amp;	      in,
+			 amount_t&amp;	      amount,
+			 optional&lt;expr_t&gt; *   amount_expr,
+			 post_t *	      post,
+			 const parse_flags_t&amp; flags	 = PARSE_DEFAULT,
+			 const bool           defer_expr = false)
   {
     expr_t expr(in, flags.plus_flags(PARSE_PARTIAL));
 
@@ -166,17 +170,22 @@ namespace {
 
     if (expr) {
       bind_scope_t bound_scope(scope, *post);
-
-      value_t result(expr.calc(bound_scope));
-      if (result.is_long()) {
-	amount = result.to_amount();
+      if (defer_expr) {
+	assert(amount_expr);
+	*amount_expr = expr;
+	(*amount_expr)-&gt;compile(bound_scope);
       } else {
-	if (! result.is_amount())
-	  throw_(parse_error, _(&quot;Postings may only specify simple amounts&quot;));
-
-	amount = result.as_amount();
+	value_t result(expr.calc(bound_scope));
+	if (result.is_long()) {
+	  amount = result.to_amount();
+	} else {
+	  if (! result.is_amount())
+	    throw_(amount_error,
+		   _(&quot;Amount expressions must result in a simple amount&quot;));
+	  amount = result.as_amount();
+	}
+	DEBUG(&quot;textual.parse&quot;, &quot;The posting amount is &quot; &lt;&lt; amount);
       }
-      DEBUG(&quot;textual.parse&quot;, &quot;The posting amount is &quot; &lt;&lt; amount);
     }
   }
 }
@@ -413,11 +422,28 @@ void instance_t::clock_in_directive(char * line,
 {
   string datetime(line, 2, 19);
 
-  char * p = skip_ws(line + 22);
-  char * n = next_element(p, true);
+  char * p   = skip_ws(line + 22);
+  char * n   = next_element(p, true);
+  char * end = n ? next_element(n, true) : NULL;
+
+  if (end &amp;&amp; *end == ';')
+    end = skip_ws(end + 1);
+  else
+    end = NULL;
+
+  position_t position;
+  position.pathname = pathname;
+  position.beg_pos  = line_beg_pos;
+  position.beg_line = linenum;
+  position.end_pos  = curr_pos;
+  position.end_line = linenum;
 
-  timelog.clock_in(parse_datetime(datetime, current_year),
-		   account_stack.front()-&gt;find_account(p), n ? n : &quot;&quot;);
+  time_xact_t event(position, parse_datetime(datetime, current_year),
+		    p ? account_stack.front()-&gt;find_account(p) : NULL,
+		    n ? n : &quot;&quot;,
+		    end ? end : &quot;&quot;);
+
+  timelog.clock_in(event);
 }
 
 void instance_t::clock_out_directive(char * line,
@@ -427,9 +453,26 @@ void instance_t::clock_out_directive(char * line,
 
   char * p = skip_ws(line + 22);
   char * n = next_element(p, true);
+  char * end = n ? next_element(n, true) : NULL;
+
+  if (end &amp;&amp; *end == ';')
+    end = skip_ws(end + 1);
+  else
+    end = NULL;
+
+  position_t position;
+  position.pathname = pathname;
+  position.beg_pos  = line_beg_pos;
+  position.beg_line = linenum;
+  position.end_pos  = curr_pos;
+  position.end_line = linenum;
+
+  time_xact_t event(position, parse_datetime(datetime, current_year),
+		    p ? account_stack.front()-&gt;find_account(p) : NULL,
+		    n ? n : &quot;&quot;,
+		    end ? end : &quot;&quot;);
 
-  timelog.clock_out(parse_datetime(datetime, current_year),
-		    p ? account_stack.front()-&gt;find_account(p) : NULL, n ? n : &quot;&quot;);
+  timelog.clock_out(event);
   count++;
 }
 
@@ -514,7 +557,7 @@ void instance_t::automated_xact_directive(char * line)
 
   reveal_context = false;
 
-  if (parse_posts(account_stack.front(), *ae.get())) {
+  if (parse_posts(account_stack.front(), *ae.get(), true)) {
     reveal_context = true;
 
     journal.auto_xacts.push_back(ae.get());
@@ -558,7 +601,7 @@ void instance_t::period_xact_directive(char * line)
     pe-&gt;journal = &amp;journal;
 
     if (pe-&gt;finalize()) {
-      extend_xact_base(&amp;journal, *pe.get(), true);
+      extend_xact_base(&amp;journal, *pe.get());
 
       journal.period_xacts.push_back(pe.get());
 
@@ -628,7 +671,7 @@ void instance_t::include_directive(char * line)
 
   if (! exists(filename))
     throw_(std::runtime_error,
-	   _(&quot;File to include was not found: '%1'&quot; &lt;&lt; filename));
+	   _(&quot;File to include was not found: '%1'&quot;) &lt;&lt; filename);
 
   ifstream stream(filename);
 
@@ -783,7 +826,8 @@ post_t * instance_t::parse_post(char *		line,
 				std::streamsize len,
 				account_t *	account,
 				xact_t *	xact,
-				bool            honor_strict)
+				bool            honor_strict,
+				bool            defer_expr)
 {
   TRACE_START(post_details, 1, &quot;Time spent parsing postings:&quot;);
 
@@ -885,8 +929,9 @@ post_t * instance_t::parse_post(char *		line,
     if (*next != '(')		// indicates a value expression
       post-&gt;amount.parse(stream, PARSE_NO_REDUCE);
     else
-      parse_amount_expr(scope, stream, post-&gt;amount, post.get(),
-			PARSE_NO_REDUCE | PARSE_SINGLE | PARSE_NO_ASSIGN);
+      parse_amount_expr(scope, stream, post-&gt;amount, &amp;post-&gt;amount_expr,
+			post.get(), PARSE_NO_REDUCE | PARSE_SINGLE |
+			PARSE_NO_ASSIGN, defer_expr);
 
     if (! post-&gt;amount.is_null() &amp;&amp; honor_strict &amp;&amp; strict &amp;&amp;
 	post-&gt;amount.has_commodity() &amp;&amp;
@@ -931,9 +976,9 @@ post_t * instance_t::parse_post(char *		line,
 	  if (*p != '(')		// indicates a value expression
 	    post-&gt;cost-&gt;parse(cstream, PARSE_NO_MIGRATE);
 	  else
-	    parse_amount_expr(scope, cstream, *post-&gt;cost, post.get(),
-			      PARSE_NO_MIGRATE | PARSE_SINGLE |
-			      PARSE_NO_ASSIGN);
+	    parse_amount_expr(scope, cstream, *post-&gt;cost, NULL, post.get(),
+			      PARSE_NO_MIGRATE | PARSE_SINGLE | PARSE_NO_ASSIGN,
+			      defer_expr);
 
 	  if (post-&gt;cost-&gt;sign() &lt; 0)
 	    throw parse_error(_(&quot;A posting's cost may not be negative&quot;));
@@ -983,8 +1028,9 @@ post_t * instance_t::parse_post(char *		line,
       if (*p != '(')		// indicates a value expression
 	post-&gt;assigned_amount-&gt;parse(stream, PARSE_NO_MIGRATE);
       else
-	parse_amount_expr(scope, stream, *post-&gt;assigned_amount, post.get(),
-			  PARSE_SINGLE | PARSE_NO_MIGRATE);
+	parse_amount_expr(scope, stream, *post-&gt;assigned_amount, NULL,
+			  post.get(), PARSE_SINGLE | PARSE_NO_MIGRATE,
+			  defer_expr);
 
       if (post-&gt;assigned_amount-&gt;is_null()) {
 	if (post-&gt;amount.is_null())
@@ -1084,8 +1130,9 @@ post_t * instance_t::parse_post(char *		line,
   }
 }
 
-bool instance_t::parse_posts(account_t *   account,
-			     xact_base_t&amp; xact)
+bool instance_t::parse_posts(account_t *  account,
+			     xact_base_t&amp; xact,
+			     const bool   defer_expr)
 {
   TRACE_START(xact_posts, 1, &quot;Time spent parsing postings:&quot;);
 
@@ -1096,7 +1143,9 @@ bool instance_t::parse_posts(account_t *   account,
     std::streamsize len = read_line(line);
     assert(len &gt; 0);
 
-    if (post_t * post = parse_post(line, len, account, NULL, false)) {
+    if (post_t * post =
+	parse_post(line, len, account, NULL, /* honor_strict= */ false,
+		   defer_expr)) {
       xact.add_post(post);
       added = true;
     }</diff>
      <filename>src/textual.cc</filename>
    </modified>
    <modified>
      <diff>@@ -41,10 +41,8 @@ namespace ledger {
 
 namespace {
   void clock_out_from_timelog(std::list&lt;time_xact_t&gt;&amp; time_xacts,
-			      const datetime_t&amp;	       when,
-			      account_t *	       account,
-			      const char *	       desc,
-			      journal_t&amp;	       journal)
+			      time_xact_t	      out_event,
+			      journal_t&amp;	      journal)
   {
     time_xact_t event;
 
@@ -55,7 +53,7 @@ namespace {
     else if (time_xacts.empty()) {
       throw parse_error(_(&quot;Timelog check-out event without a check-in&quot;));
     }
-    else if (! account) {
+    else if (! out_event.account) {
       throw parse_error
 	(_(&quot;When multiple check-ins are active, checking out requires an account&quot;));
     }
@@ -65,7 +63,7 @@ namespace {
       for (std::list&lt;time_xact_t&gt;::iterator i = time_xacts.begin();
 	   i != time_xacts.end();
 	   i++)
-	if (account == (*i).account) {
+	if (out_event.account == (*i).account) {
 	  event = *i;
 	  found = true;
 	  time_xacts.erase(i);
@@ -77,29 +75,39 @@ namespace {
 	  (_(&quot;Timelog check-out event does not match any current check-ins&quot;));
     }
 
-    if (desc &amp;&amp; event.desc.empty()) {
-      event.desc = desc;
-      desc = NULL;
+    if (out_event.checkin &lt; event.checkin)
+      throw parse_error
+	(_(&quot;Timelog check-out date less than corresponding check-in&quot;));
+
+    if (! out_event.desc.empty() &amp;&amp; event.desc.empty()) {
+      event.desc = out_event.desc;
+      out_event.desc = empty_string;
     }
 
+    if (! out_event.note.empty() &amp;&amp; event.note.empty())
+      event.note = out_event.note;
+
     std::auto_ptr&lt;xact_t&gt; curr(new xact_t);
-    curr-&gt;_date = when.date();
-    curr-&gt;code  = desc ? desc : &quot;&quot;;
+    curr-&gt;_date = out_event.checkin.date();
+    curr-&gt;code  = out_event.desc; // if it wasn't used above
     curr-&gt;payee = event.desc;
+    curr-&gt;pos   = event.position;
 
-    if (when &lt; event.checkin)
-      throw parse_error
-	(_(&quot;Timelog check-out date less than corresponding check-in&quot;));
+    if (! event.note.empty())
+      curr-&gt;append_note(event.note.c_str());
 
     char buf[32];
-    std::sprintf(buf, &quot;%lds&quot;, long((when - event.checkin).total_seconds()));
+    std::sprintf(buf, &quot;%lds&quot;, long((out_event.checkin - event.checkin)
+				   .total_seconds()));
     amount_t amt;
     amt.parse(buf);
     VERIFY(amt.valid());
 
     post_t * post = new post_t(event.account, amt, POST_VIRTUAL);
     post-&gt;set_state(item_t::CLEARED);
+    post-&gt;pos = event.position;
     curr-&gt;add_post(post);
+    event.account-&gt;add_post(post);
 
     if (! journal.add_xact(curr.get()))
       throw parse_error(_(&quot;Failed to record 'out' timelog transaction&quot;));
@@ -119,19 +127,16 @@ time_log_t::~time_log_t()
       accounts.push_back(time_xact.account);
 
     foreach (account_t * account, accounts)
-      clock_out_from_timelog(time_xacts, CURRENT_TIME(), account, NULL,
+      clock_out_from_timelog(time_xacts,
+			     time_xact_t(none, CURRENT_TIME(), account),
 			     journal);
 
     assert(time_xacts.empty());
   }
 }
 
-void time_log_t::clock_in(const datetime_t&amp; checkin,
-			  account_t *	    account,
-			  const string&amp;     desc)
+void time_log_t::clock_in(time_xact_t event)
 {
-  time_xact_t event(checkin, account, desc);
-
   if (! time_xacts.empty()) {
     foreach (time_xact_t&amp; time_xact, time_xacts) {
       if (event.account == time_xact.account)
@@ -142,15 +147,12 @@ void time_log_t::clock_in(const datetime_t&amp; checkin,
   time_xacts.push_back(event);
 }
 
-void time_log_t::clock_out(const datetime_t&amp; checkin,
-			   account_t *	     account,
-			   const string&amp;     desc)
+void time_log_t::clock_out(time_xact_t event)
 {
   if (time_xacts.empty())
     throw std::logic_error(_(&quot;Timelog check-out event without a check-in&quot;));
 
-  clock_out_from_timelog(time_xacts, checkin, account, desc.c_str(),
-			 journal);
+  clock_out_from_timelog(time_xacts, event, journal);
 }
 
 } // namespace ledger</diff>
      <filename>src/timelog.cc</filename>
    </modified>
    <modified>
      <diff>@@ -44,6 +44,7 @@
 
 #include &quot;utils.h&quot;
 #include &quot;times.h&quot;
+#include &quot;item.h&quot;
 
 namespace ledger {
 
@@ -56,19 +57,25 @@ public:
   datetime_t  checkin;
   account_t * account;
   string      desc;
+  string      note;
+  position_t  position;
 
   time_xact_t() : account(NULL) {
     TRACE_CTOR(time_xact_t, &quot;&quot;);
   }
-  time_xact_t(const datetime_t&amp; _checkin,
-	       account_t *	 _account = NULL,
-	       const string&amp;     _desc	  = &quot;&quot;)
-    : checkin(_checkin), account(_account), desc(_desc) {
-    TRACE_CTOR(time_xact_t, &quot;const datetime_t&amp;, account_t *, const string&amp;&quot;);
+  time_xact_t(const optional&lt;position_t&gt;&amp; _position,
+	      const datetime_t&amp;		  _checkin,
+	      account_t *		  _account = NULL,
+	      const string&amp;		  _desc	   = &quot;&quot;,
+	      const string&amp;               _note    = &quot;&quot;)
+    : checkin(_checkin), account(_account), desc(_desc), note(_note),
+      position(_position ? *_position : position_t()) {
+    TRACE_CTOR(time_xact_t,
+	       &quot;position_t, datetime_t, account_t *, string, string&quot;);
   }
   time_xact_t(const time_xact_t&amp; xact)
     : checkin(xact.checkin), account(xact.account),
-      desc(xact.desc) {
+      desc(xact.desc), note(xact.note), position(xact.position) {
     TRACE_CTOR(time_xact_t, &quot;copy&quot;);
   }
   ~time_xact_t() throw() {
@@ -79,7 +86,7 @@ public:
 class time_log_t
 {
   std::list&lt;time_xact_t&gt; time_xacts;
-  journal_t&amp;		  journal;
+  journal_t&amp;		 journal;
 
 public:
   time_log_t(journal_t&amp; _journal) : journal(_journal) {
@@ -87,13 +94,8 @@ public:
   }
   ~time_log_t();
 
-  void clock_in(const datetime_t&amp; checkin,
-		account_t *	  account = NULL,
-		const string&amp;     desc	  = &quot;&quot;);
-
-  void clock_out(const datetime_t&amp; checkin,
-		 account_t *	   account = NULL,
-		 const string&amp;     desc	  = &quot;&quot;);
+  void clock_in(time_xact_t event);
+  void clock_out(time_xact_t event);
 };
 
 } // namespace ledger</diff>
      <filename>src/timelog.h</filename>
    </modified>
    <modified>
      <diff>@@ -406,8 +406,16 @@ void report_memory(std::ostream&amp; out, bool report_all)
   }
 }
 
+} // namespace ledger
+
+#endif // VERIFY_ON
+
+/**********************************************************************
+ *
+ * String wrapper
+ */
 
-#if defined(STRING_VERIFY_ON)
+namespace ledger {
 
 string::string() : std::string() {
   TRACE_CTOR(string, &quot;&quot;);
@@ -445,18 +453,10 @@ string::~string() throw() {
   TRACE_DTOR(string);
 }
 
-#endif // STRING_VERIFY_ON
+string empty_string(&quot;&quot;);
 
-} // namespace ledger
-
-#endif // VERIFY_ON
-
-ledger::string empty_string(&quot;&quot;);
-
-ledger::strings_list split_arguments(const char * line)
+strings_list split_arguments(const char * line)
 {
-  using namespace ledger;
-
   strings_list args;
 
   char buf[4096];
@@ -506,6 +506,8 @@ ledger::strings_list split_arguments(const char * line)
   return args;
 }
 
+} // namespace ledger
+
 /**********************************************************************
  *
  * Logging</diff>
      <filename>src/utils.cc</filename>
    </modified>
    <modified>
      <diff>@@ -62,10 +62,6 @@
 #define TIMERS_ON   1
 #endif
 
-#if defined(VERIFY_ON)
-//#define STRING_VERIFY_ON 1
-#endif
-
 /*@}*/
 
 /**
@@ -76,11 +72,7 @@
 namespace ledger {
   using namespace boost;
 
-#if defined(STRING_VERIFY_ON)
   class string;
-#else
-  typedef std::string string;
-#endif
 
   typedef std::list&lt;string&gt; strings_list;
 
@@ -162,12 +154,33 @@ void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size);
 
 void report_memory(std::ostream&amp; out, bool report_all = false);
 
-#if defined(STRING_VERIFY_ON)
+} // namespace ledger
+
+#else // ! VERIFY_ON
+
+#define VERIFY(x)
+#define DO_VERIFY() true
+#define TRACE_CTOR(cls, args)
+#define TRACE_DTOR(cls)
+
+#endif // VERIFY_ON
+
+#define IF_VERIFY() if (DO_VERIFY())
+
+/*@}*/
 
 /**
- * This string type is a wrapper around std::string that allows us to
- * trace constructor and destructor calls.
+ * @name String wrapper
+ *
+ * This string type is a wrapper around std::string that allows us to trace
+ * constructor and destructor calls.  It also makes ledger's use of strings a
+ * unique type, that the Boost.Python code can use as the basis for
+ * transparent Unicode conversions.
  */
+/*@{*/
+
+namespace ledger {
+
 class string : public std::string
 {
 public:
@@ -240,24 +253,11 @@ inline bool operator!=(const char* __lhs, const string&amp; __rhs)
 inline bool operator!=(const string&amp; __lhs, const char* __rhs)
 { return __lhs.compare(__rhs) != 0; }
 
-#endif // STRING_VERIFY_ON
+extern string empty_string;
 
-} // namespace ledger
-
-#else // ! VERIFY_ON
+strings_list split_arguments(const char * line);
 
-#define VERIFY(x)
-#define DO_VERIFY() true
-#define TRACE_CTOR(cls, args)
-#define TRACE_DTOR(cls)
-
-#endif // VERIFY_ON
-
-extern ledger::string empty_string;
-
-ledger::strings_list split_arguments(const char * line);
-
-#define IF_VERIFY() if (DO_VERIFY())
+} // namespace ledger
 
 /*@}*/
 </diff>
      <filename>src/utils.h</filename>
    </modified>
    <modified>
      <diff>@@ -35,7 +35,7 @@
 #include &quot;commodity.h&quot;
 #include &quot;annotate.h&quot;
 #include &quot;pool.h&quot;
-#include &quot;unistring.h&quot;
+#include &quot;unistring.h&quot;		// for justify()
 
 namespace ledger {
 
@@ -1439,6 +1439,31 @@ void value_t::in_place_truncate()
   throw_(value_error, _(&quot;Cannot truncate %1&quot;) &lt;&lt; label());
 }
 
+void value_t::in_place_floor()
+{
+  switch (type()) {
+  case INTEGER:
+    return;
+  case AMOUNT:
+    as_amount_lval().in_place_floor();
+    return;
+  case BALANCE:
+    as_balance_lval().in_place_floor();
+    return;
+  case SEQUENCE: {
+    value_t temp;
+    foreach (const value_t&amp; value, as_sequence())
+      temp.push_back(value.floored());
+    *this = temp;
+    return;
+  }
+  default:
+    break;
+  }
+
+  throw_(value_error, _(&quot;Cannot floor %1&quot;) &lt;&lt; label());
+}
+
 void value_t::in_place_unround()
 {
   switch (type()) {</diff>
      <filename>src/value.cc</filename>
    </modified>
    <modified>
      <diff>@@ -440,6 +440,13 @@ public:
   }
   void in_place_truncate();
 
+  value_t floored() const {
+    value_t temp(*this);
+    temp.in_place_floor();
+    return temp;
+  }
+  void in_place_floor();
+
   value_t unrounded() const {
     value_t temp(*this);
     temp.in_place_unround();</diff>
      <filename>src/value.h</filename>
    </modified>
    <modified>
      <diff>@@ -480,7 +480,7 @@ bool xact_t::valid() const
   return true;
 }
 
-void auto_xact_t::extend_xact(xact_base_t&amp; xact, bool post_handler)
+void auto_xact_t::extend_xact(xact_base_t&amp; xact)
 {
   posts_list initial_posts(xact.posts.begin(), xact.posts.end());
 
@@ -490,20 +490,32 @@ void auto_xact_t::extend_xact(xact_base_t&amp; xact, bool post_handler)
     if (! initial_post-&gt;has_flags(ITEM_GENERATED) &amp;&amp;
 	predicate(*initial_post)) {
       foreach (post_t * post, posts) {
-	amount_t amt;
-	assert(post-&gt;amount);
-	if (! post-&gt;amount.commodity()) {
-	  if ((post_handler &amp;&amp;
-	       ! initial_post-&gt;has_flags(POST_CALCULATED)) ||
-	      initial_post-&gt;amount.is_null())
-	    continue;
-	  amt = initial_post-&gt;amount * post-&gt;amount;
+	amount_t post_amount;
+	if (post-&gt;amount.is_null()) {
+	  if (! post-&gt;amount_expr)
+	    throw_(amount_error,
+		   _(&quot;Automated transaction's posting has no amount&quot;));
+
+	  bind_scope_t bound_scope(*scope_t::default_scope, *initial_post);
+	  value_t result(post-&gt;amount_expr-&gt;calc(bound_scope));
+	  if (result.is_long()) {
+	    post_amount = result.to_amount();
+	  } else {
+	    if (! result.is_amount())
+	      throw_(amount_error,
+		     _(&quot;Amount expressions must result in a simple amount&quot;));
+	    post_amount = result.as_amount();
+	  }
 	} else {
-	  if (post_handler)
-	    continue;
-	  amt = post-&gt;amount;
+	  post_amount = post-&gt;amount;
 	}
 
+	amount_t amt;
+	if (! post_amount.commodity())
+	  amt = initial_post-&gt;amount * post_amount;
+	else
+	  amt = post_amount;
+
 	IF_DEBUG(&quot;xact.extend&quot;) {
 	  DEBUG(&quot;xact.extend&quot;,
 		&quot;Initial post on line &quot; &lt;&lt; initial_post-&gt;pos-&gt;beg_line &lt;&lt; &quot;: &quot;
@@ -517,12 +529,12 @@ void auto_xact_t::extend_xact(xact_base_t&amp; xact, bool post_handler)
 
 	  DEBUG(&quot;xact.extend&quot;,
 		&quot;Posting on line &quot; &lt;&lt; post-&gt;pos-&gt;beg_line &lt;&lt; &quot;: &quot;
-		&lt;&lt; &quot;amount &quot; &lt;&lt; post-&gt;amount &lt;&lt; &quot;, amt &quot; &lt;&lt; amt
-		&lt;&lt; &quot; (precision &quot; &lt;&lt; post-&gt;amount.precision()
+		&lt;&lt; &quot;amount &quot; &lt;&lt; post_amount &lt;&lt; &quot;, amt &quot; &lt;&lt; amt
+		&lt;&lt; &quot; (precision &quot; &lt;&lt; post_amount.precision()
 		&lt;&lt; &quot; != &quot; &lt;&lt; amt.precision() &lt;&lt; &quot;)&quot;);
 
 #if defined(DEBUG_ON)
-	  if (post-&gt;amount.keep_precision())
+	  if (post_amount.keep_precision())
 	    DEBUG(&quot;xact.extend&quot;, &quot;  precision is kept&quot;);
 	  if (amt.keep_precision())
 	    DEBUG(&quot;xact.extend&quot;, &quot;  amt precision is kept&quot;);
@@ -542,6 +554,7 @@ void auto_xact_t::extend_xact(xact_base_t&amp; xact, bool post_handler)
 	new_post-&gt;add_flags(ITEM_GENERATED);
 
 	xact.add_post(new_post);
+	new_post-&gt;account-&gt;add_post(new_post);
       }
     }
   }
@@ -555,11 +568,10 @@ void auto_xact_t::extend_xact(xact_base_t&amp; xact, bool post_handler)
 }
 
 void extend_xact_base(journal_t *  journal,
-		      xact_base_t&amp; base,
-		      bool	   post_handler)
+		      xact_base_t&amp; base)
 {
   foreach (auto_xact_t * xact, journal-&gt;auto_xacts)
-    xact-&gt;extend_xact(base, post_handler);
+    xact-&gt;extend_xact(base);
 }
 
 void to_xml(std::ostream&amp; out, const xact_t&amp; xact)</diff>
      <filename>src/xact.cc</filename>
    </modified>
    <modified>
      <diff>@@ -142,7 +142,7 @@ private:
 
 struct xact_finalizer_t {
   virtual ~xact_finalizer_t() {}
-  virtual bool operator()(xact_t&amp; xact, bool post) = 0;
+  virtual bool operator()(xact_t&amp; xact) = 0;
 };
 
 class auto_xact_t : public xact_base_t
@@ -167,7 +167,7 @@ public:
     TRACE_DTOR(auto_xact_t);
   }
 
-  virtual void extend_xact(xact_base_t&amp; xact, bool post);
+  virtual void extend_xact(xact_base_t&amp; xact);
 
 #if defined(HAVE_BOOST_SERIALIZATION)
 private:
@@ -201,7 +201,7 @@ struct auto_xact_finalizer_t : public xact_finalizer_t
     TRACE_DTOR(auto_xact_finalizer_t);
   }
 
-  virtual bool operator()(xact_t&amp; xact, bool post);
+  virtual bool operator()(xact_t&amp; xact);
 
 #if defined(HAVE_BOOST_SERIALIZATION)
 private:
@@ -258,7 +258,7 @@ class func_finalizer_t : public xact_finalizer_t
   func_finalizer_t();
 
 public:
-  typedef function&lt;bool (xact_t&amp; xact, bool post)&gt; func_t;
+  typedef function&lt;bool (xact_t&amp; xact)&gt; func_t;
 
   func_t func;
 
@@ -273,15 +273,15 @@ public:
     TRACE_DTOR(func_finalizer_t);
   }
 
-  virtual bool operator()(xact_t&amp; xact, bool post) {
-    return func(xact, post);
+  virtual bool operator()(xact_t&amp; xact) {
+    return func(xact);
   }
 };
 
-void extend_xact_base(journal_t * journal, xact_base_t&amp; xact, bool post);
+void extend_xact_base(journal_t * journal, xact_base_t&amp; xact);
 
-inline bool auto_xact_finalizer_t::operator()(xact_t&amp; xact, bool post) {
-  extend_xact_base(journal, xact, post);
+inline bool auto_xact_finalizer_t::operator()(xact_t&amp; xact) {
+  extend_xact_base(journal, xact);
   return true;
 }
 </diff>
      <filename>src/xact.h</filename>
    </modified>
    <modified>
      <diff>@@ -150,6 +150,7 @@ for line in fd.readlines():
     line = re.sub('set_session_context\(\)',
                   'set_session_context()\n        self.testSession = None', line)
     line = re.sub('([a-z_]+?)_t\b', '\\1', line)
+    line = re.sub('(&quot;[^&quot;]+&quot;)', 'u\\1', line)
     line = re.sub('std::string\(([^)]+?)\)', '\\1', line)
     line = re.sub('string\(([^)]+?)\)', '\\1', line)
     line = re.sub('\.print\(([^)]+?)\)', '.print_(\\1)', line)</diff>
      <filename>test/convert.py</filename>
    </modified>
    <modified>
      <diff>@@ -4,16 +4,16 @@
 &gt;&gt;&gt;2
 While parsing file &quot;$sourcepath/src/amount.h&quot;, line 67: 
 Error: No quantity specified for amount
-While parsing file &quot;$sourcepath/src/amount.h&quot;, line 712: 
+While parsing file &quot;$sourcepath/src/amount.h&quot;, line 721: 
 Error: Invalid date/time: line amount_t amoun
-While parsing file &quot;$sourcepath/src/amount.h&quot;, line 718: 
+While parsing file &quot;$sourcepath/src/amount.h&quot;, line 727: 
 Error: Invalid date/time: line string amount_
-While parsing file &quot;$sourcepath/src/amount.h&quot;, line 724: 
+While parsing file &quot;$sourcepath/src/amount.h&quot;, line 733: 
 Error: Invalid date/time: line string amount_
-While parsing file &quot;$sourcepath/src/amount.h&quot;, line 730: 
+While parsing file &quot;$sourcepath/src/amount.h&quot;, line 739: 
 Error: Invalid date/time: line string amount_
-While parsing file &quot;$sourcepath/src/amount.h&quot;, line 736: 
+While parsing file &quot;$sourcepath/src/amount.h&quot;, line 745: 
 Error: Invalid date/time: line std::ostream&amp; 
-While parsing file &quot;$sourcepath/src/amount.h&quot;, line 743: 
+While parsing file &quot;$sourcepath/src/amount.h&quot;, line 752: 
 Error: Invalid date/time: line std::istream&amp; 
 === 7</diff>
      <filename>test/regress/25A099C9.test</filename>
    </modified>
    <modified>
      <diff>@@ -235,9 +235,7 @@ ledger_la_DEPENDENCIES = $(lib_LTLIBRARIES)
 ledger_la_LDFLAGS      = -avoid-version -module
 ledger_la_LIBADD       = $(LIBOBJS) $(lib_LTLIBRARIES) $(INTLLIBS)
 
-pkgpython_PYTHON = python/__init__.py		\
-	python/hello.py				\
-	python/server.py
+pkgpython_PYTHON = python/__init__.py python/server.py
 
 endif
 </diff>
      <filename>tools/Makefile.am</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>python/hello.py</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>5ffa987daf4d97c52066e4c28733d826d3726297</id>
    </parent>
    <parent>
      <id>f0f1b0cdfa3a0a73695eda52b25de71bd40adc5a</id>
    </parent>
  </parents>
  <author>
    <name>John Wiegley</name>
    <email>johnw@newartisans.com</email>
  </author>
  <url>http://github.com/jwiegley/ledger/commit/a034435c4287aba7fd32ed63a745e560350c924a</url>
  <id>a034435c4287aba7fd32ed63a745e560350c924a</id>
  <committed-date>2009-11-11T11:45:14-08:00</committed-date>
  <authored-date>2009-11-11T11:45:14-08:00</authored-date>
  <message>Merge branch 'next'</message>
  <tree>f0acb080410a32c215c2c1938811cc14d512b580</tree>
  <committer>
    <name>John Wiegley</name>
    <email>johnw@newartisans.com</email>
  </committer>
</commit>
