packages feed

UMM 0.2.2 → 0.3.0

raw patch · 10 files changed

+526/−55 lines, 10 files

Files

UMM.cabal view
@@ -1,5 +1,5 @@ Name:             UMM-Version:          0.2.2+Version:          0.3.0 Homepage:         http://www.korgwal.com/umm/ Author:           Uwe Hollerbach <uh@alumni.caltech.edu> Maintainer:       Uwe Hollerbach <uh@alumni.caltech.edu>
UMM.hs view
@@ -16,7 +16,7 @@ along with umm; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -$Id: UMM.hs,v 1.67 2010/06/10 06:44:20 uwe Exp $ -}+$Id: UMM.hs,v 1.69 2010/07/06 03:12:06 uwe Exp $ -}  module Main where import Prelude hiding (putStr,putStrLn,print,readFile,getContents)@@ -183,22 +183,30 @@   where chk w1 w2 = w1 == w2 || w1 == COLAll         sh = mapM_ print +-- Generate the sum of a list of amounts, translating them+-- into the default ccs to the extent possible++genSum :: Name -> [Record] -> [Record] -> Date -> [CCSAmt] -> [CCSAmt]+genSum dc ccs prices date vs =+  let fp = map (\e -> reprice e dc ccs date prices) vs+      gp = groupBy eqCCSAmtName (sortBy cmpCCSAmtName fp)+  in filter (\e -> ccsA e /= 0) (map sumCCS gp)+  where sumCCS cs =+           CCSAmt (ccsN (head cs)) (Amount (roundP 2 (sum (map ccsA cs))))+        ccsN (CCSAmt n _) = n+        ccsA (CCSAmt _ (Amount a)) = a+ doBalance :: Bool -> Date -> [Name] -> Name -> [Record] ->              [Record] -> [Record] -> [Record] -> IO () doBalance ke date names dc ccs accts trans prices =   do final <- getBalances startTime date Nothing False accts trans      let fsel = selAccts ke names final-         fp = map (\e -> reprice e dc ccs date prices) (concatMap tr3 fsel)-         gp = groupBy eqCCSAmtName (sortBy cmpCCSAmtName fp)-         sp = filter (\e -> ccsA e /= 0) (map sumCCS gp)-     putStrLn ("Account balances as of " ++ show date)+         sp = genSum dc ccs prices date (concatMap tr3 fsel)+     putStrLn ("Account balances as of " ++ (gregorianDateToWDay date)+              ++ " " ++ show date)      mapM_ putStrLn (ppAccts (showPos dc ccs date prices fsel) 8)      putStrLn ("Grand total: ~" ++ show sp)-  where sumCCS cs =-           CCSAmt (ccsN (head cs)) (Amount (roundP 2 (sum (map ccsA cs))))-        ccsN (CCSAmt n _) = n-        ccsA (CCSAmt _ (Amount a)) = a-        tr3 (_,_,v) = v+  where tr3 (_,_,v) = v  doRegister :: Date -> Date -> [Name] -> Name -> [Record] ->               [Record] -> [Record] -> [Record] -> Bool -> IO ()@@ -263,12 +271,13 @@          doList w dc ccs accts grps incs exps        PlotCmd name date1 date2 (Name output) ->          let crec = find (\r -> getRecName r == name) cd+             gs = genSum1 dc ccs prices          in if elem name (map getRecName cb)                then putStrLn (show name ++ " is a base CCS!")                else if isNothing crec                        then if elem name (map getRecName accts)                                then plotBalances date1 date2 name-                                                 accts trans output+                                                 accts trans output gs                                else putStrLn (show name ++ " is unknown!")                        else plotPrices name (getNB (fromJust crec))                                        date1 date2 prices output@@ -288,3 +297,7 @@          getBalances startTime date Nothing False accts trans >> return ()   where getNB (CCSRec _ _ _ nb) = nb         getNB r = error ("internal error at main! got " ++ show r)+        genSum1 dc ccs prices (r,bs) =+          let date = getRecDate r+          in (date, map ccsA (genSum dc ccs prices date bs))+        ccsA (CCSAmt _ a) = a
UMMData.hs view
@@ -16,7 +16,7 @@ along with umm; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -$Id: UMMData.hs,v 1.56 2010/05/17 05:24:09 uwe Exp $ -}+$Id: UMMData.hs,v 1.57 2010/07/06 03:12:08 uwe Exp $ -}  module UMMData (Name(..), Date(..), Amount(..), startTime,                 Command(..), CmdOpt(..), Record(..), genDate,@@ -26,8 +26,9 @@                 SN(..), Period(..), CCSAmt(..), cmpCCSAmtName,                 eqCCSAmtName, AccountData, noName, todoName, joinDrop,                 roundP, isLeap, validDate, julianDate, gregorianDate,-                offsetDate, previousDate, nextDate,-                trimspace, mylines, mergelines, uniqAdjBy, uniqAdj) where+                offsetDate, previousDate, nextDate, julianDateToWDay,+                gregorianDateToWDay, trimspace, mylines, mergelines,+                uniqAdjBy, uniqAdj) where import Prelude import Data.Char import Data.List@@ -465,6 +466,25 @@ previousDate, nextDate :: Date -> Date previousDate d = offsetDate d (-1) nextDate d = offsetDate d 1++-- Utility functions to get the day of the week+-- from either a Julian or a Gregorian date++julianDateToWDay :: Int -> String+julianDateToWDay jd =+  let jm = mod (jd + 1) 7+  in case jm of+       0 -> "Sun"+       1 -> "Mon"+       2 -> "Tue"+       3 -> "Wed"+       4 -> "Thu"+       5 -> "Fri"+       6 -> "Sat"+       _ -> error ("internal error at julianDateToWDay! got " ++ show jm)++gregorianDateToWDay :: Date -> String+gregorianDateToWDay = julianDateToWDay . julianDate  -- Remove leading and trailing whitespace from a string. 
UMMEval.hs view
@@ -16,7 +16,7 @@ along with umm; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -$Id: UMMEval.hs,v 1.48 2010/06/10 06:44:20 uwe Exp $ -}+$Id: UMMEval.hs,v 1.50 2010/07/12 00:03:27 uwe Exp $ -}  module UMMEval (validateRecs, validateCCS, validateAccts, classifyRecs,                 validateTransPrices, generateImplicitPrices, getBalances,@@ -361,14 +361,15 @@      unless (null i) (putStrLn "Notes:" >> mapM_ ss i >> putStrLn "")      return r -plotBalances :: Date -> Date -> Name -> [Record] -> [Record] -> String -> IO ()-plotBalances date1 date2 reg accts trans output =+plotBalances :: Date -> Date -> Name -> [Record] -> [Record] ->+                String -> ((Record, [CCSAmt]) -> (Date, [Amount])) -> IO ()+plotBalances date1 date2 reg accts trans output gs =   do let (_,i1,e) =            runLedger (mkInit accts >>= appTr date2 (Just [reg]) False trans)          i = dropWhile (\t -> getRecDate (fst t) < date1) i1      unless (null e) (showErrs "processing errors" e)-     unless (null i) (putStrLn "Notes:" >> mapM_ showTB i >> putStrLn "")-     putStrLn ("gonna plot: " ++ output)+     if null i then putStrLn ("No balances known for " ++ show reg)+               else genPlot output reg date1 date2 (map gs i)  -- For now, we don't generate "swap prices" internally, so unless the user -- enters some, we won't see any; see also generateImplicitPrices above.@@ -402,10 +403,9 @@   do let p1 = dropWhile (\t -> date2 < getRecDate t) prices          p2 = takeWhile (\t -> date1 < getRecDate t) p1          (_,i,e) = runLedger (getP nm dc p2)-         pdata = map gp (reverse i)      unless (null e) (putStrLn "There were swap \"prices\" which are ignored")      if null i then putStrLn ("No prices known for " ++ show nm)-               else genPlot output nm pdata+               else genPlot output nm date1 date2 (map gp (reverse i))   where gp (PriceRec d _ (CCSAmt _ (Amount a1)) (CCSAmt _ (Amount a2))) =           (d, [Amount (a2/a1)])         gp r = intErr "plotPrices" r
UMMHelp.hs view
@@ -16,13 +16,13 @@ along with umm; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -$Id: help-head.txt,v 1.4 2010/06/13 23:46:16 uwe Exp $ -}+$Id: help-head.txt,v 1.6 2010/07/12 00:26:27 uwe Exp $ -}  module UMMHelp (writeHdr, usageMsg) where import Prelude  version :: String-version = "0.2.2"+version = "0.3.0"  writeHdr :: String writeHdr =@@ -77,8 +77,6 @@   "* 'plot' generates a plot of the price history of the specified\n" ++   "  currency, commodity, or security, or of the value of the specified\n" ++   "  account, in the given date range.\n" ++-  "\n" ++-  "  This is in progress, and only partially implemented.\n" ++   "\n" ++   "* 'price' shows the price history of the specified currency,\n" ++   "  commodity, or security, in the given date range\n" ++
UMMPlot.hs view
@@ -16,57 +16,124 @@ along with umm; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -$Id: UMMPlot.hs,v 1.3 2010/06/13 23:46:16 uwe Exp $ -}+$Id: UMMPlot.hs,v 1.7 2010/07/12 00:26:26 uwe Exp $ -}  module UMMPlot (genPlot) where import Prelude hiding (putStr, putStrLn, print) import Data.List-import System.IO(openFile, IOMode(..), hClose)+import System.IO(withFile, IOMode(..)) import System.IO.UTF8-import System.Process+-- Just one of these is needed to build this; pick the appropriate one+-- import System.Cmd	-- for ghc 6.8+import System.Process	-- for ghc 6.10 (and newer? untested) import Control.Monad  import UMMData  -- TODO: a lot more work!+-- Do we need the niceBounds stuff at all? Or can gnuplot handle it? +-- Given a pair of numbers, return a set of nice bounds plus a number of+-- sub-intervals into which those nice bounds should be divided:+--+--	niceBounds 23 65 -> (20.0,65.0,9)+--+-- meaning that the nice lower and upper bounds are 20 and 65, and that+-- interval should be sub-divided into 9 sub-intervals which will thus+-- each have length 5, and therefore tic-marks will be placed at nice+-- round numbers: [20, 25, ..., 60, 65]+--+-- The original algorithm is not mine, but I don't now remember+-- where it came from... I got it a long time ago.++-- TODO: make this polymorphic, accepting Fractional or even Num?++niceBounds :: Double -> Double -> (Double, Double, Int)+niceBounds l h | l == h      = (l - 1, h + 1, 8)+               | l > h       = nbw h l+               | otherwise   = nbw l h+  where nbw lo hi =+          let sc = fsc (hi - lo) 1.0+              los = lo*sc+              his = hi*sc+              tries = map (fn los his sc) [1.0, 0.5, 0.25, 0.2, 0.1, 0.05]+          in head (dropWhile (\(_,_,n) -> n <= 6) tries)+        fsc d s | d < 1       = fsc (10*d) (10*s)+                | d > 10      = fsc (d/10) (s/10)+                | otherwise   = s+        fn lo hi sc e =+          let fl = fromInteger (floor (lo/e))+              ch = fromInteger (ceiling (hi/e))+              n = ceiling (hi/e) - floor (lo/e)+              es = e/sc+          in (fl*es, ch*es, n)++-- Various steps to take in subdividing a date range, used below++data DateStep = Day | Month | YearM | YearQ | Year | DY Int deriving (Show)++-- Given a pair of dates, return another pair of dates which are nice bounds+-- plus a subdivision indicator: analogous to niceBounds, above, but+-- specialized for dates, for which what's "nice" is slightly different+-- than for generic numbers.++niceDateBounds :: Date -> Date -> (Date, Date, DateStep)+niceDateBounds l h = if l <= h then njbw l h else njbw h l+  where njbw (Date yl ml _) (Date yh mh _) =+          let dy = yh - yl+              lo1 = nd yl ml 1+              hi1 = nd yh (mh + 1) 0+              lo2 = nd yl (ml - rem (ml - 1) 3) 1+              hi2 = nd yh (mh + 3 - rem (mh - 1) 3) 0+              lo3 = nd yl 1 1+              hi3 = nd yh 12 31+              (l4, h4, n4) =+                niceBounds (fromIntegral yl) (fromIntegral (yh + 1))+              lo4 = nd (fromInteger (round l4)) 1 1+              hi4 = nd (fromInteger (round h4)) 1 0+          in if dy <= 0+                then (lo1, hi1, if ml == mh then Day else Month)+                else if dy <= 2+                        then (lo1, hi1, YearM)+                        else if dy <= 5+                                then (lo2, hi2, YearQ)+                                else if dy <= 15+                                        then (lo3, hi3, Year)+                                        else (lo4, hi4, DY n4)+-- The round-tripping of Date to Julian day back to Date may seem stupid,+-- but it normalizes the date: for example, 2009-13-0 becomes 2009-12-31+-- without having to worry about how many days there are in a given month+        nd y m d = gregorianDate (julianDate (Date y m d))+ -- Adjust as needed: for example, for pgm output, use --  "set terminal pbm gray medium size 800,600\n" ++ -termo :: String -> String -> String-termo output name =+plot_cmds :: String -> String -> Date -> Date -> String+plot_cmds output name lo hi =   "set terminal postscript 'Times-Roman' 16\n" ++   "set output '" ++ output ++ ".ps'\n" ++   "set title 'Value of " ++ name ++ " over time'\n" ++   "unset key\n" +++  "set xdata time\n" +++  "set timefmt \"%Y-%m-%d\"\n" +++  "set format x \"%Y-%m-%d\"\n" +++  "set xrange [\"" ++ show lo ++ "\":\"" ++ show hi ++ "\"]\n" ++   "plot '" ++ output ++ ".dat' using 1:2 with lines\n" -genPlot :: String -> Name -> [(Date, [Amount])] -> IO ()-genPlot output name pts =-  do fp <- openFile (output ++ ".plot") WriteMode-     hPutStr fp (termo output (show name))-     -- TODO: analyze input, generate nice xtics-     hClose fp-     fd <- openFile (output ++ ".dat") WriteMode-     mapM_ (dP fd) pts-     hClose fd-     doit ("gnuplot " ++ output ++ ".plot")+genPlot :: String -> Name -> Date -> Date -> [(Date, [Amount])] -> IO ()+genPlot output name date1 date2 pts =+  let pts1 = filter (not . null . snd) pts+  in if null pts1+        then putStrLn ("Nothing to show while trying to plot " ++ show name)+        else do let (nlo, nhi, _) = niceDateBounds date1 date2+                withFile (output ++ ".plot") WriteMode+                  (\h -> hPutStr h (plot_cmds output (show name) nlo nhi))+                withFile (output ++ ".dat") WriteMode+                  (\h -> mapM_ (dP h) pts1)+                doit ("gnuplot " ++ output ++ ".plot")   where dP fp (d,vs) =-          hPutStr fp (show (julianDate d)) >>-            mapM_ (dY fp) vs >> hPutStrLn fp ""+          hPutStr fp (show d) >> mapM_ (dY fp) vs >> hPutStrLn fp ""         dY fp r = hPutStr fp (' ' : show r) --- If you use the stupid version, you'll get a warning that nothing from--- System.Process is used... that's ok.- doit :: String -> IO ()---- Stupid version that just says what the user needs to do next:--- use this if you're using ghc 6.8.---- doit cmd = putStrLn ("now you must run '" ++ cmd ++ "'")---- Smart version that actually runs the command:--- use this if you're using 6.10 or later.- doit cmd = putStrLn ("running '" ++ cmd ++ "'") >> system cmd >> return ()
+ test/test1.dat view
@@ -0,0 +1,179 @@+todo 2009-1-1 Test 1: counting in different ways+todo 2009-1-1 Run "umm test1.dat bal 2009-m-d" for different values of m and d+todo 2009-1-1 This exercises "xfer" transactions++todo 2009-1-1 You should see N dollars in accounts 1 & 3 on the Nth day of the+todo 2009-1-1 year, and H_n dollars in account 2 on the Nth day of the year,+todo 2009-1-1 where H_n is the nth harmonic number: H_19 = 275295799/77597520,+todo 2009-1-1 H_20 = 55835135/15519504. Account 1 counts up to 60 on 2009-3-1,+todo 2009-1-1 account 2 counts up to H_30 on 2009-1-30, and account 3 counts+todo 2009-1-1 up to 365 on 2009-12-31. In account 4, start with 1/3 dollar,+todo 2009-1-1 then add powers of 10 for a while, then subtract them again;+todo 2009-1-1 should again end up with 1/3++ccs $+income in+expense out++account count1 "manually count $"+account count2 "harmonic numbers"+account count3 "automatically count $"+account count4 "check bignums"++xfer 2009-1-1 in count1 1+xfer 2009-1-2 in count1 1+xfer 2009-1-3 in count1 1+xfer 2009-1-4 in count1 1+xfer 2009-1-5 in count1 1+xfer 2009-1-6 in count1 1+xfer 2009-1-7 in count1 1+xfer 2009-1-8 in count1 1+xfer 2009-1-9 in count1 1+xfer 2009-1-10 in count1 1+xfer 2009-1-11 in count1 1+xfer 2009-1-12 in count1 1+xfer 2009-1-13 in count1 1+xfer 2009-1-14 in count1 1+xfer 2009-1-15 in count1 1+xfer 2009-1-16 in count1 1+xfer 2009-1-17 in count1 1+xfer 2009-1-18 in count1 1+xfer 2009-1-19 in count1 1+xfer 2009-1-20 in count1 1+xfer 2009-1-21 in count1 1+xfer 2009-1-22 in count1 1+xfer 2009-1-23 in count1 1+xfer 2009-1-24 in count1 1+xfer 2009-1-25 in count1 1+xfer 2009-1-26 in count1 1+xfer 2009-1-27 in count1 1+xfer 2009-1-28 in count1 1+xfer 2009-1-29 in count1 1+xfer 2009-1-30 in count1 1+xfer 2009-1-31 in count1 1+xfer 2009-2-1 in count1 1+xfer 2009-2-2 in count1 1+xfer 2009-2-3 in count1 1+xfer 2009-2-4 in count1 1+xfer 2009-2-5 in count1 1+xfer 2009-2-6 in count1 1+xfer 2009-2-7 in count1 1+xfer 2009-2-8 in count1 1+xfer 2009-2-9 in count1 1+xfer 2009-2-10 in count1 1+xfer 2009-2-11 in count1 1+xfer 2009-2-12 in count1 1+xfer 2009-2-13 in count1 1+xfer 2009-2-14 in count1 1+xfer 2009-2-15 in count1 1+xfer 2009-2-16 in count1 1+xfer 2009-2-17 in count1 1+xfer 2009-2-18 in count1 1+xfer 2009-2-19 in count1 1+xfer 2009-2-20 in count1 1+xfer 2009-2-21 in count1 1+xfer 2009-2-22 in count1 1+xfer 2009-2-23 in count1 1+xfer 2009-2-24 in count1 1+xfer 2009-2-25 in count1 1+xfer 2009-2-26 in count1 1+xfer 2009-2-27 in count1 1+xfer 2009-2-28 in count1 1+xfer 2009-3-1 in count1 1++xfer 2009-1-1 in count2 1/1+xfer 2009-1-2 in count2 1/2+xfer 2009-1-3 in count2 1/3+xfer 2009-1-4 in count2 1/4+xfer 2009-1-5 in count2 1/5+xfer 2009-1-6 in count2 1/6+xfer 2009-1-7 in count2 1/7+xfer 2009-1-8 in count2 1/8+xfer 2009-1-9 in count2 1/9+xfer 2009-1-10 in count2 1/10+xfer 2009-1-11 in count2 1/11+xfer 2009-1-12 in count2 1/12+xfer 2009-1-13 in count2 1/13+xfer 2009-1-14 in count2 1/14+xfer 2009-1-15 in count2 1/15+xfer 2009-1-16 in count2 1/16+xfer 2009-1-17 in count2 1/17+xfer 2009-1-18 in count2 1/18+xfer 2009-1-19 in count2 1/19+xfer 2009-1-20 in count2 1/20+xfer 2009-1-21 in count2 1/21+xfer 2009-1-22 in count2 1/22+xfer 2009-1-23 in count2 1/23+xfer 2009-1-24 in count2 1/24+xfer 2009-1-25 in count2 1/25+xfer 2009-1-26 in count2 1/26+xfer 2009-1-27 in count2 1/27+xfer 2009-1-28 in count2 1/28+xfer 2009-1-29 in count2 1/29+xfer 2009-1-30 in count2 1/30++recurring daily until 2009-12-31 xfer 2009-1-1 in count3 1++xfer 2009-1-1 in count4  1/3+xfer 2009-1-1 in count4  1+xfer 2009-1-2 in count4  10+xfer 2009-1-3 in count4  100+xfer 2009-1-4 in count4  1000+xfer 2009-1-5 in count4  10000+xfer 2009-1-6 in count4  100000+xfer 2009-1-7 in count4  1000000+xfer 2009-1-8 in count4  10000000+xfer 2009-1-9 in count4  100000000+xfer 2009-1-10 in count4 1000000000+xfer 2009-1-11 in count4 10000000000+xfer 2009-1-12 in count4 100000000000+xfer 2009-1-13 in count4 1000000000000+xfer 2009-1-14 in count4 10000000000000+xfer 2009-1-15 in count4 100000000000000+xfer 2009-1-16 in count4 1000000000000000+xfer 2009-1-17 in count4 10000000000000000+xfer 2009-1-18 in count4 100000000000000000+xfer 2009-1-19 in count4 1000000000000000000+xfer 2009-1-20 in count4 10000000000000000000+xfer 2009-1-21 in count4 100000000000000000000+xfer 2009-1-22 in count4 1000000000000000000000+xfer 2009-1-23 in count4 10000000000000000000000+xfer 2009-1-24 in count4 100000000000000000000000+xfer 2009-1-25 in count4 1000000000000000000000000+xfer 2009-1-26 in count4 10000000000000000000000000+xfer 2009-1-27 in count4 100000000000000000000000000+xfer 2009-1-28 in count4 1000000000000000000000000000+xfer 2009-1-29 in count4 10000000000000000000000000000+xfer 2009-1-30 in count4 100000000000000000000000000000+xfer 2009-1-31 in count4 1000000000000000000000000000000+xfer 2009-2-1 count4 out  1+xfer 2009-2-2 count4 out  100+xfer 2009-2-3 count4 out  10000+xfer 2009-2-4 count4 out  1000000+xfer 2009-2-5 count4 out  100000000+xfer 2009-2-6 count4 out  10000000000+xfer 2009-2-7 count4 out  1000000000000+xfer 2009-2-8 count4 out  100000000000000+xfer 2009-2-9 count4 out  10000000000000000+xfer 2009-2-10 count4 out 1000000000000000000+xfer 2009-2-11 count4 out 100000000000000000000+xfer 2009-2-12 count4 out 10000000000000000000000+xfer 2009-2-13 count4 out 1000000000000000000000000+xfer 2009-2-14 count4 out 100000000000000000000000000+xfer 2009-2-15 count4 out 10000000000000000000000000000+xfer 2009-2-16 count4 out 1000000000000000000000000000000+xfer 2009-2-17 count4 out 100000000000000000000000000000+xfer 2009-2-18 count4 out 1000000000000000000000000000+xfer 2009-2-19 count4 out 10000000000000000000000000+xfer 2009-2-20 count4 out 100000000000000000000000+xfer 2009-2-21 count4 out 1000000000000000000000+xfer 2009-2-22 count4 out 10000000000000000000+xfer 2009-2-23 count4 out 100000000000000000+xfer 2009-2-24 count4 out 1000000000000000+xfer 2009-2-25 count4 out 10000000000000+xfer 2009-2-26 count4 out 100000000000+xfer 2009-2-27 count4 out 1000000000+xfer 2009-2-28 count4 out 10000000+xfer 2009-3-1 count4 out  100000+xfer 2009-3-2 count4 out  1000+xfer 2009-3-3 count4 out  10
+ test/test2.dat view
@@ -0,0 +1,100 @@+todo 2009-1-1 Test 2: more counting in different ways+todo 2009-1-1 This exercises "buy", "sell", and "exch" transactions.+todo 2009-1-1 Run "umm test1.dat bal 2009-m-d" for different values of m and d.++todo 2009-1-1 You should see N units of J in account 1, balanced by -N $,+todo 2009-1-1 for each day of January 2009; then in February and the first+todo 2009-1-1 couple of days of March, the J get exchanged for $ again,+todo 2009-1-1 and the positive balance of J and negative balance of $ should+todo 2009-1-1 decrease again, until the account is empty.+todo 2009-1-1 In account 2, units of J are bought in exchange for $, but+todo 2009-1-1 automatically throughout the year: on the Nth day of the year,+todo 2009-1-1 there should be N units of J balanced by -N $.+todo 2009-1-1 Account 3 is the same as account 2, except that each J is+todo 2009-1-1 exchanged for an S on the same day it is bought; thus+todo 2009-1-1 there should be N units of S balanced by -N $. In account 3+todo 2009-1-1 there will be two transactions each day, one showing the+todo 2009-1-1 purchase of 1 unit of J and one showing the exchange of that+todo 2009-1-1 unit of J for 1 unit of S.++ccs $+ccs J "junk"+ccs S "s...tuff"++account count1 "manually count $ & J"+account count2 "automatically count $ & J"+account count3 "automatically count $ & S"++# manually accumulate junk++buy 2009-1-1 count1 1 J 1+buy 2009-1-2 count1 1 J 1+buy 2009-1-3 count1 1 J 1+buy 2009-1-4 count1 1 J 1+buy 2009-1-5 count1 1 J 1+buy 2009-1-6 count1 1 J 1+buy 2009-1-7 count1 1 J 1+buy 2009-1-8 count1 1 J 1+buy 2009-1-9 count1 1 J 1+buy 2009-1-10 count1 1 J 1+buy 2009-1-11 count1 1 J 1+buy 2009-1-12 count1 1 J 1+buy 2009-1-13 count1 1 J 1+buy 2009-1-14 count1 1 J 1+buy 2009-1-15 count1 1 J 1+buy 2009-1-16 count1 1 J 1+buy 2009-1-17 count1 1 J 1+buy 2009-1-18 count1 1 J 1+buy 2009-1-19 count1 1 J 1+buy 2009-1-20 count1 1 J 1+buy 2009-1-21 count1 1 J 1+buy 2009-1-22 count1 1 J 1+buy 2009-1-23 count1 1 J 1+buy 2009-1-24 count1 1 J 1+buy 2009-1-25 count1 1 J 1+buy 2009-1-26 count1 1 J 1+buy 2009-1-27 count1 1 J 1+buy 2009-1-28 count1 1 J 1+buy 2009-1-29 count1 1 J 1+buy 2009-1-30 count1 1 J 1+buy 2009-1-31 count1 1 J 1+sell 2009-2-1 count1 1 J 1+sell 2009-2-2 count1 1 J 1+sell 2009-2-3 count1 1 J 1+sell 2009-2-4 count1 1 J 1+sell 2009-2-5 count1 1 J 1+sell 2009-2-6 count1 1 J 1+sell 2009-2-7 count1 1 J 1+sell 2009-2-8 count1 1 J 1+sell 2009-2-9 count1 1 J 1+sell 2009-2-10 count1 1 J 1+sell 2009-2-11 count1 1 J 1+sell 2009-2-12 count1 1 J 1+sell 2009-2-13 count1 1 J 1+sell 2009-2-14 count1 1 J 1+sell 2009-2-15 count1 1 J 1+sell 2009-2-16 count1 1 J 1+sell 2009-2-17 count1 1 J 1+sell 2009-2-18 count1 1 J 1+sell 2009-2-19 count1 1 J 1+sell 2009-2-20 count1 1 J 1+sell 2009-2-21 count1 1 J 1+sell 2009-2-22 count1 1 J 1+sell 2009-2-23 count1 1 J 1+sell 2009-2-24 count1 1 J 1+sell 2009-2-25 count1 1 J 1+sell 2009-2-26 count1 1 J 1+sell 2009-2-27 count1 1 J 1+sell 2009-2-28 count1 1 J 1+sell 2009-3-1 count1 1 J 1+sell 2009-3-2 count1 1 J 1+sell 2009-3-3 count1 1 J 1++# automatically accumulate junk++recurring daily until 2009-12-31 buy 2009-1-1 count2 1 J 1++# automatically accumulate junk, but exchange it for s...tuff++recurring daily until 2009-12-31 buy 2009-1-1 count3 1 J 1+recurring daily until 2009-12-31 exch 2009-1-1 count3 1 S 1 J
+ test/test3a.dat view
@@ -0,0 +1,47 @@+todo 2009-1-1 Test 3a: this exercises "split" transactions.+todo 2009-1-1 Run "umm test3a.dat bal 2009-1-d" for different values of d.+todo 2009-1-1 You should see 10^(N-1) dollars in the account on the Nth day+todo 2009-1-1 of January 2009, from 1 up to 10^30.++ccs J "junk"++income in++account count "generate powers of 10"++# generate an initial amount in the account++xfer 2009-1-1 in count 1 J++# start splitting++split 2009-1-2 J 10 1+split 2009-1-3 J 10 1+split 2009-1-4 J 10 1+split 2009-1-5 J 10 1+split 2009-1-6 J 10 1+split 2009-1-7 J 10 1+split 2009-1-8 J 10 1+split 2009-1-9 J 10 1+split 2009-1-10 J 10 1+split 2009-1-11 J 10 1+split 2009-1-12 J 10 1+split 2009-1-13 J 10 1+split 2009-1-14 J 10 1+split 2009-1-15 J 10 1+split 2009-1-16 J 10 1+split 2009-1-17 J 10 1+split 2009-1-18 J 10 1+split 2009-1-19 J 10 1+split 2009-1-20 J 10 1+split 2009-1-21 J 10 1+split 2009-1-22 J 10 1+split 2009-1-23 J 10 1+split 2009-1-24 J 10 1+split 2009-1-25 J 10 1+split 2009-1-26 J 10 1+split 2009-1-27 J 10 1+split 2009-1-28 J 10 1+split 2009-1-29 J 10 1+split 2009-1-30 J 10 1+split 2009-1-31 J 10 1
+ test/test3b.dat view
@@ -0,0 +1,47 @@+todo 2009-1-1 Test 3b: this exercises "split" transactions.+todo 2009-1-1 Run "umm test3b.dat bal 2009-1-d" for different values of d.+todo 2009-1-1 You should see N dollars in the account on the Nth day+todo 2009-1-1 of January 2009, from 1 up to 31.++ccs J "junk"++income in++account count "again, count"++# generate an initial amount in the accounts++xfer 2009-1-1 in count 1 J++# start splitting++split 2009-1-2 J 2 1+split 2009-1-3 J 3 2+split 2009-1-4 J 4 3+split 2009-1-5 J 5 4+split 2009-1-6 J 6 5+split 2009-1-7 J 7 6+split 2009-1-8 J 8 7+split 2009-1-9 J 9 8+split 2009-1-10 J 10 9+split 2009-1-11 J 11 10+split 2009-1-12 J 12 11+split 2009-1-13 J 13 12+split 2009-1-14 J 14 13+split 2009-1-15 J 15 14+split 2009-1-16 J 16 15+split 2009-1-17 J 17 16+split 2009-1-18 J 18 17+split 2009-1-19 J 19 18+split 2009-1-20 J 20 19+split 2009-1-21 J 21 20+split 2009-1-22 J 22 21+split 2009-1-23 J 23 22+split 2009-1-24 J 24 23+split 2009-1-25 J 25 24+split 2009-1-26 J 26 25+split 2009-1-27 J 27 26+split 2009-1-28 J 28 27+split 2009-1-29 J 29 28+split 2009-1-30 J 30 29+split 2009-1-31 J 31 30