# Using jodliterate

The JODSOURCE addon, (a part of the JOD system), contains a handy literate programming tool that enables the generation of beautiful J source code documents.

The Bible, Koran, and Bhagavad Gita of Literate Programming is Donald Knuth’s masterful tome of the same name.

Knuth applied Literate Programming to his $\TeX$ systems and produced what many consider enduring masterpieces of program documentation.

jodliterate is certainly not worthy of $\TeX$ level accolades but with a little work it’s possible to produce fine documents. This J kernel notebook outlines how you can install and use jodliterate. Jupyter notebooks are typically executed but to accommodate J users that do hot have Jupyter this notebook is also available on GitHub as a static PDF document.

#### Notebook Preliminaries

In [1]:
NB. show J kernel version
9!:14 ''

j901/j64avx/windows/release-e/commercial/www.jsoftware.com/2020-01-29T11:15:50

In [2]:
NB. load JOD in a clear base locale
load 'general/jod' [ clear ''

NB. The distributed JOD profile automatically RESETME's.
NB. To safely use dictionaries with many J tasks they must
NB. be READONLY. To prevent opening the same put dictionary
NB. READWRITE comment out (dpset) and restart this notebook.
dpset 'RESETME'

NB. Converting Jupyter notebooks to LaTeX is
NB. simplified by ASCII box characters.
portchars ''

NB. Verb to show large boxed displays in
NB. the notebook without ugly wrapping.
sbx_ijod_=: ' ... ' ,"1~ 75&{."1@":


#### Installing jodliterate

To use jodliterate you need to:

1. Install a current version of J.
2. Install the J addons JOD, JODSOURCE, and JODDOCUMENT.
3. Build the JOD development dictionaries from JODSOURCE.
4. Install a current version of pandoc.
5. Install a current version of $\TeX$ and $\LaTeX$.
6. Make the jodliterate J script.
7. Run jodliterate on a JOD group with pandoc compatible document fragments.
8. Compile the files of the previous step to produce a PDF

When presented with long lists of program prerequisites my impulse is to run! Life is too short for configuration wars. Everything should be easy. Installing jodliterate requires more work than phone apps but compared to enterprise installations setting up jodliterate is trivial. We’ll go through it step by step.

#### Step 1: Install a current version of J

J is freely available at jsoftware.com. J installation instructions can be found on the J Wiki on this page.

Follow the appropriate instructions for your OS.

Note: JOD runs on Windows, Linux, and MacOS versions of J, hence these are the only platforms that currently support jodliterate.

#### Step 2: Install the J addons JOD, JODSOURCE and JODDOCUMENT

After installing J install the J addons. J addons are installed with the J package manager pacman. Pacman has three IDE flavors: a command-line flavor and two GUI flavors. The GUI flavors depend on JQT or JHS. The GUI flavors of pacman are only available on some versions of J whereas the command line version is part of the base J install and is available on all platforms.

I install all the addons. I recommend that you do the same.

JOD depends on some J modules like jfiles, regex, and task that are sometimes distributed as addons. If you install all addons JOD’s modules and dependents are both installed.

#### Installing addons with command line pacman

Start J and do:

In [3]:
NB. install J addons with command-line pacman

load 'pacman'    NB. load pacman jpkg services

In [4]:
'help' jpkg ''   NB. what can you do for me?

Valid options are:
history, install, manifest, remove, reinstall, search,
show, showinstalled, shownotinstalled, showupgrade,
status, update, upgrade

https://code.jsoftware.com/wiki/JAL/Package_Manager/jpkg


In [5]:
NB. install all addons
NB. see https://code.jsoftware.com/wiki/Pacman

NB. uncomment next line if addons not installed
NB. 'install' jpkg '*'  NB.

In [6]:
3 {. 'showinstalled' jpkg '' NB. first few installed addons

+---------+------+------+-----------------------------+
|api/expat|1.0.11|1.0.11|libexpat                     |
+---------+------+------+-----------------------------+
|api/gles |1.0.31|1.0.31|Modern OpenGL API            |
+---------+------+------+-----------------------------+
|api/java |1.0.2 |1.0.2 |api: Java to J shared library|
+---------+------+------+-----------------------------+

In [7]:
'showupgrade' jpkg ''  NB. list addon updates


#### Installing addons with JQT GUI pacman

I mostly use the Windows JQT version of pacman to install and maintain J addons. You can find pacman on the tools menu.

pacman shows all available addons and provides tools for installing, updating, and removing them.

The GUI version is easy to use. Press the Select All button and then press the Install button to install all the addons. To update addons select the Upgrades menu and select the addons you want to update.

#### Step 3: Build the JOD development dictionaries from JODSOURCE

JOD source code is distributed in the form of JOD dictionary dumps. Dictionary dumps are large J scripts that serialize JOD dictionaries. Dumps contain everything stored in dictionaries. You will find source code, binary data, test scripts, documentation, build macros, and more in typical JOD dictionaries.

jodliterate is stored as a JOD dictionary group. A dictionary group is simply a collection of J words with optional header and post-processor scripts. JOD generates J scripts from groups. Before we can make jodliterate we must load the JOD development dictionaries. The JODSOURCE addon includes a J script that loads development dictionaries.

Again, start J and do:

In [8]:
require 'general/jod'

In [9]:
NB. set a JODroot user folder
NB. if not set /jod/ is the default

NB. use paths for your OS
UserFolders_j_=: UserFolders_j_ , 'JODroot';'c:/temp'

NB. show added folder
UserFolders_j_ {~ (0 {"1 UserFolders_j_) i. <'JODroot'

+-------+-------+
|JODroot|c:/temp|
+-------+-------+

In [10]:
NB. load JOD developement dictionaries
load_dev_tmp=: 3 : 0
if. +./ (;:'joddev jod utils') e. od '' do.
'dev dictionaries exist'
else.
0!:0<jpath'~addons/general/jodsource/jodsourcesetup.ijs'
end.
)

load_dev_tmp 0

dev dictionaries exist

In [11]:
NB. joddev, jod, utils should exist

erase 'load_dev_tmp'
(;:'joddev jod utils') e. od ''

1 1 1


#### Step 4: Install a current version of pandoc

pandoc is easily one of the most useful markup utilities on the intertubes. If you routinely deal with markup formats like markdown, XML, $\LaTeX$, json and you aren’t using pandoc you are working too hard.

Be lazy! Install pandoc.

jodliterate uses the task addon to shell out to pandoc. Versions of pandoc after 2.9.1.1 support J syntax high-lighting.

In [12]:
NB. show pandoc version from J - make sure you are running
NB. a recent version of pandoc. There may be different
NB. versions in many locations on various systems.

ppath=: '"C:\Program Files\Pandoc\pandoc"'
THISPANDOC_ajodliterate_=: ppath
shell THISPANDOC_ajodliterate_,' --version'

pandoc 2.9.1.1
Compiled with pandoc-types 1.20, texmath 0.12, skylighting 0.8.3
Default user data directory: C:\Users\john\AppData\Roaming\pandoc
Copyright (C) 2006-2019 John MacFarlane
Web:  https://pandoc.org
This is free software; see the source for copying conditions.
There is no warranty, not even for merchantability or fitness
for a particular purpose.


In [13]:
NB. make sure your version of pandoc
NB. supports J syntax-highlighting

NB. appends line feed character if necessary
tlf=:] , ((10{a.)"_ = {:) }. (10{a.)"_

NB. J is on the supported languages list
pcmd=: THISPANDOC_ajodliterate_,' --list-highlight-languages'
(<;._2 tlf (shell pcmd) -. CR) e.~ <,'j'

1


#### Step 5: Install a current version of LaTeX

jodliterate uses $\LaTeX$ to compile PDF documents. When setjodliterate runs it sets an output directory and writes a $\LaTeX$ preamble file JODLiteratePreamble.tex to it. It’s a good idea to review this file to get an idea of the $\LaTeX$ packages jodliterate uses. It’s possible that some of these packages are not in your $\LaTeX$ distribution and will have to be installed.

To ease the burden of $\LaTeX$ package maintenance I use freely available $\TeX$ versions that automatically install missing packages.

1. On Windows I use MiKTeX
2. On other platforms I use TeXLive

If your system automatically installs packages the first time you compile jodliterate output it may fetch missing packages from The Comprehensive $\TeX$ Archive Network (CTAN). If new packages are installed reprocess your files a few times to insure all the required packages are downloaded and installed.

#### Step: 6 Make the jodliterate J script

Once the JOD development dictionaries are built (Step 3) making jodliterate is easy. Start J and do:

In [14]:
require 'general/jod'

NB. open dictionaries
od ;:'joddev jod utils' [ 3 od ''

+-+--------------------+------+---+-----+
|1|opened (rw/ro/ro) ->|joddev|jod|utils|
+-+--------------------+------+---+-----+

In [15]:
NB. generate jodliterate
sbx mls 'jodliterate'

+-+--------------------+------------------------------------+               ...
|1|load script saved ->|c:/jod/joddev/script/jodliterate.ijs|               ...
+-+--------------------+------------------------------------+               ...


mls creates a standard J load script. Once generated this script can be loaded with the standard J load utility. You can test this by restarting J without JOD and loading jodliterate.

In [16]:
NB. load generated script
load 'jodliterate'

NB. (jodliterate) interface word(s):
NB. --------------------------------
NB. THISPANDOC      NB. full pandoc path - use (pandoc) if on shell path
NB. grplit          NB. make latex for group (y)
NB. ifacesection    NB. interface section summary string
NB. ifc             NB. format interface comment text
NB. setjodliterate  NB. prepare LaTeX processing - sets out directory writes preamble

NOTE: adjust pandoc path if version (pandoc 2.9.1.1) is not >= 2.9.1.1


#### Step 7: Run jodliterate on a JOD group with pandoc compatible document fragments

This sounds a lot worse than it is. There is a group in utils called sunmoon that has an interesting pandoc compatible document fragment.

Start J and do:

In [17]:
require 'general/jod'

od 'utils' [ 3 od ''

+-+--------------+-----+
|1|opened (ro) ->|utils|
+-+--------------+-----+

In [18]:
NB. display short explanations for (sunmoon) words
sbx hlpnl }. grp 'sunmoon'

+-----------------+-------------------------------------------------------- ...
|IFACEWORDSsunmoon|interface words (IFACEWORDSsunmoon) group                ...
|NORISESET        |indicates sun never rises or sets in (sunriseset0) and ( ...
|ROOTWORDSsunmoon |root words (ROOTWORDSsunmoon) group                      ...
|arctan           |arc tangent                                              ...
|calmoons         |calendar dates of new and full moons                     ...
|cos              |cosine radians                                           ...
|fromjulian       |converts Julian day numbers to dates, converse (tojulian ...
|moons            |times of new and full moons for n calendar years         ...
|round            |round (y) to nearest (x) (e.g. 1000 round 12345)         ...
|sin              |sine radians                                             ...
|sunriseset0      |computes sun rise and set times - see group documentatio ...
|sunriseset1      |computes sun rise and set times - see group documentatio ...
|tabit            |promotes only atoms and lists to tables                  ...
|tan              |tan radians                                              ...
|today            |returns todays date                                      ...
|yeardates        |returns all valid dates for n calendar years             ...
+-----------------+-------------------------------------------------------- ...

In [19]:
NB. display part of the (sunmoon) group document header
NB. this is pandoc compatible markdown - note the LaTeX
NB. commands - pandoc allows markdown/LaTeX mixtures
900 {. 2 9 disp 'sunmoon'

ï»¿sunmoon is a collection of basic astronomical algorithms
The key verbs are moons, sunriseset0 and sunriseset1.
All of these verbs were derived from BASIC programs published
in *Sky & Telescope* magazine in the 1990's. The rest of
the verbs in sunmoon are mostly date and trigonometric
utilities.

\subsection{\texttt{sunmoon} Interface}

~~~~ { .j }
calmoons      NB. calendar dates of new and full moons
moons         NB. times of new and full moons for n calendar years
sunriseset0   NB. computes sun rise and set times - see group documentation
sunriseset1   NB. computes sun rise and set times - see group documentation
~~~~

\subsection{\textbf\texttt{sunriseset0} \textsl{v--} sunrise and sunset times}

This  verb has been adapted from a BASIC program submitted by
Robin  G.  Stuart  *Sky & Telescope's*  shortest  sunrise/set
program  cont

In [20]:
NB. run jodliterate on (sunmoon)
require 'jodliterate'

NB. set the output directory - when
NB. running in Jupyter use a subdirectory
NB. of your notebook directory.

ltxpath=: 'C:\Users\john\AnacondaProjects\testfolder\grplit\'
setjodliterate ltxpath

+-+-------------------------------------------------+
|1|C:\Users\john\AnacondaProjects\testfolder\grplit\|
+-+-------------------------------------------------+

In [21]:
NB. (grplit) returns a list of generated
NB. LaTeX and command files. The *.bat
NB. file compiles the generated LaTeX

,. grplit 'sunmoon'

+-----------------------------------------------------------------+
|1                                                                |
+-----------------------------------------------------------------+
|C:\Users\john\AnacondaProjects\testfolder\grplit\sunmoon.tex     |
+-----------------------------------------------------------------+
|C:\Users\john\AnacondaProjects\testfolder\grplit\sunmoontitle.tex|
+-----------------------------------------------------------------+
|C:\Users\john\AnacondaProjects\testfolder\grplit\sunmoonoview.tex|
+-----------------------------------------------------------------+
|C:\Users\john\AnacondaProjects\testfolder\grplit\sunmooncode.tex |
+-----------------------------------------------------------------+
|C:\Users\john\AnacondaProjects\testfolder\grplit\sunmoon.bat     |
+-----------------------------------------------------------------+


#### Step 8: Compile the files of the previous step to produce a PDF

In [22]:
_250 {. shell ltxpath,'sunmoon.bat'

gular.otf><c:/program files/miktex 2.9/fonts/ope
ntype/public/lm/lmmono12-regular.otf>
Output written on sunmoon.pdf (22 pages, 107711 bytes).
Transcript written on sunmoon.log.

(base) C:\Users\john\AnacondaProjects\testfolder\grplit>endlocal


In [23]:
NB. uncomment to display generated PDF
NB. shell ltxpath,'sunmoon.pdf'


#### Storing jodliterate pandoc compatible document fragments in JOD

Effective use of jodliterate requires a melange of Markdown, $\LaTeX$, JOD, and J skills combined with a healthy attitude about experimentation. You have to try things and see if they work!

However, before you can try jodliterate document fragments you have put them in JOD dictionaries.

jodliterate uses two types of document fragments:

1. markdown overview group documents.
2. $\LaTeX$ overview macros.

Markdown group documents are transformed by pandoc into $\LaTeX$ but the overview macros are not altered in any way. This enables the use of arbitrarily complex $\LaTeX$. The following examples show how to insert document fragments.

#### Create a jodliterate Demo Dictionary

In [24]:
NB. create a demo dictionary - (didnum) insures new name
require 'general/jod'

NB. new dictionary in default JOD directory
sbx newd itslit_ijod_=: 'aaa',":didnum_ajod_ ''

+-+---------------------+------------------------------------------+------- ...
|1|dictionary created ->|aaa327403631806685638405507439206657280913|c:/user ...
+-+---------------------+------------------------------------------+------- ...

In [25]:
NB. 1 if new dictionary created
(<itslit) e. od ''

1

In [26]:
od itslit [ 3 od '' NB. open only new dictionary

+-+--------------+------------------------------------------+
|1|opened (rw) ->|aaa327403631806685638405507439206657280913|
+-+--------------+------------------------------------------+

In [27]:
NB. define some words
freq=:~. ; #/.~
movmean=:-@[ (+/ % #)\ ]
geomean=:# %: */
bmi=: 704.5"_ * ] % [: *: [
polyprod=:+//.@(*/)

wlst=: ;:'freq movmean geomean bmi polyprod'

NB. put in dictionary
put wlst

NB. short word explanations
t=: ,:  'freq';'frequency distribution'
t=: t , 'movmean';'moving mean'
t=: t , 'geomean';'geometric mean of a list'
t=: t , 'bmi';'body mass index - (x) inches (y) lbs'
t=: t , 'polyprod';'polynomial product'

0 8 put t

+-+-------------------------------+------------------------------------------+
|1|5 word explanation(s) put in ->|aaa327403631806685638405507439206657280913|
+-+-------------------------------+------------------------------------------+

In [28]:
NB. make header and macro groups
grp 'litheader' ; wlst
grp 'litmacro'  ; wlst

+-+--------------------------+------------------------------------------+
|1|group <litmacro> put in ->|aaa327403631806685638405507439206657280913|
+-+--------------------------+------------------------------------------+

In [29]:
IFACEWORDSlitheader=: wlst
put 'IFACEWORDSlitheader'

+-+-------------------+------------------------------------------+
|1|1 word(s) put in ->|aaa327403631806685638405507439206657280913|
+-+-------------------+------------------------------------------+


#### Use Group Document Overview Markdown

In [30]:
NB. add group header markdown
litheader=: (0 : 0)
litheader is a markdown demo group.

This markdown text will be
[transmogrified](https://calvinandhobbes.fandom.com)
by pandoc to \LaTeX. A group interface will be
generated from the IFACEWORDSlitheader
list. Interface lists are usually, but
not always, associated with a *class group*.

\subsection{\texttt{litheader} Interface}

{~{insert_interface_md_}~}
)

NB. store markdown as a JOD group document
2 9 put 'litheader';litheader

+-+-----------------------------+------------------------------------------+
|1|1 group document(s) put in ->|aaa327403631806685638405507439206657280913|
+-+-----------------------------+------------------------------------------+

In [31]:
NB. run jodliterate on group
ltxpath=: 'C:\Users\john\AnacondaProjects\testfolder\grplit\'
setjodliterate ltxpath
{: grplit 'litheader'

+--------------------------------------------------------------+
|C:\Users\john\AnacondaProjects\testfolder\grplit\litheader.bat|
+--------------------------------------------------------------+

In [32]:
NB. compile latex
_250 {. shell ltxpath,'litheader.bat'

lar.otf><c:/program files/miktex 2.9/fonts/o
pentype/public/lm/lmmono12-regular.otf>
Output written on litheader.pdf (4 pages, 47726 bytes).
Transcript written on litheader.log.

(base) C:\Users\john\AnacondaProjects\testfolder\grplit>endlocal


In [33]:
NB. uncomment to show PDF
NB. shell ltxpath,'litheader.pdf'


#### Use Macro Overview LaTeX

In [34]:
NB. add a LaTeX overview - this code will not
NB. be altered by jodliterate the suffix
NB. '_oview_tex' is required to associate
NB. the overview with the group 'litmacro'

litmacro_oview_tex=: (0 : 0)

This \LaTeX\ code will not be
touched by \texttt{jodliterate}.

\subsection{Business Babel}

Truth management is enabled.''

\emph{Excerpt from an actual business document!}
Obviously composed in an irony free zone.

\subsection{Some Complicated \LaTeX}

\medskip

$\frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\ldots} } } }$

)

NB. store LaTeX as JOD text macro
4 put 'litmacro_oview_tex';LATEX_ajod_;litmacro_oview_tex

+-+--------------------+------------------------------------------+
|1|1 macro(s) put in ->|aaa327403631806685638405507439206657280913|
+-+--------------------+------------------------------------------+

In [35]:
NB. run jodliterate on group
{: grplit 'litmacro'

+-------------------------------------------------------------+
|C:\Users\john\AnacondaProjects\testfolder\grplit\litmacro.bat|
+-------------------------------------------------------------+

In [36]:
NB. compile latex
_250 {. shell ltxpath,'litmacro.bat'

e1/public/lm/lmsy6.pfb><C:/Program Files/MiKTeX 2.9/fonts/type1/public/lm/lms
y8.pfb>
Output written on litmacro.pdf (4 pages, 138976 bytes).
Transcript written on litmacro.log.

(base) C:\Users\john\AnacondaProjects\testfolder\grplit>endlocal


In [37]:
NB. display PDF
NB. shell ltxpath,'litmacro.pdf'


#### Using jodliterate with larger J systems

The main jodliterate verb grplit works with single JOD groups. Larger systems are typically made from many groups. JOD macro and test scripts are one way to work around this limitation. The JOD development dictionaries contain several macros that illustrate this approach.

In [38]:
od ;:'joddev jod utils' [ 3 od ''

NB. list macros with substring 'latex'
4 2 dnl 'latex'

+-+-------------+---------------------+
|1|buildjodlatex|buildjodliteratelatex|
+-+-------------+---------------------+

In [39]:
NB. display start of macro that
NB. applies jodliterate to JOD code
250 {. 4 disp 'buildjodlatex'

NB.*buildjodlatex s--  generates syntax highlighted JOD source LaTeX.
NB.
NB. Files are written to the put dictionary's document directory.
NB.
NB. assumes: current versions of pandoc (pandoc 2.9.1.1 or later)
NB.          check noun (THISPANDOC


#### Final Remarks

jodliterate is an idiosyncratic anal-retentive software utility; it’s mainly for people that consider source code an art form. Nobody likes ugly undocumented art!

If you have any questions, suggestions, or complaints please leave a comment on this post. To include others join one of J discussion forums and post your queries there.

May the source be with you!

WordPress conversion from UsingJodliterate.ipynb by nb2wp v0.3.1

# More J Pandoc Syntax HighLighting

Syntax highlighting is essential for blogging program code. Many blog hosts recognize this and provide tools for highlighting programming languages. WordPress.com (this host) has a nifty highlighting tool that handles dozens of mainstream programming languages. Unfortunately, one of my favorite programming languages, J, (yes it’s a single letter name), is way out of the mainstream and is not supported.

There are a few ways to deal with this problem.

1. Eschew J highlighting.
2. Upgrade1 your WordPress.com subscription and install custom syntax highlighters that can handle arbitrary language definitions.
3. Find another blog host that freely supports custom highlighters.
4. Roll your own or customize an existing highlighter.

A few years ago I went with the fourth option and hacked the superb open-source tool pandoc. The grim details are described in this blog post. My hack produced a customized version of pandoc with J highlighting. I still use my hacked version and I’d probably stick with it if current pandoc versions had not introduced must-have features like converting Jupyter notebooks to Markdown, PDF, LaTeX and HTML. Jupyter is my default thinking-things-through programming environment. I’ve even taken to blogging with Jupyter notebooks. If you write and explain code you owe it to yourself to give Jupyter a try.

Unwilling to eschew J highlighting or forgo Jupyter I was on the verge of re-hacking pandoc when I read the current pandoc (version 2.9.1.1) documentation and saw that J is now officially supported by pandoc. You can verify this with the shell commands.

pandoc --version
pandoc --list-highlight-languages

The pandoc developers made my day! I felt like Wayne meeting a rock star.

Highlighting J is now a simple matter of placing J code in markdown blocks like:

  ~~~~ { .j }
... code code code ...
~~~~

and issuing shell commands like:

pandoc --highlight-style tango --metadata title="J test" -s jpdh.md -o jpdh.html

The previous command generated the HTML of this post which I pasted into the WordPress.com Classic Editor. Not only do I get J code highlighting on the cheap I also get footnotes which, for god freaking sakes,2 are not supported by the new WordPress block editor for low budget blogs.

The source markdown used for this post is available here – enjoy!


NB. Some J code I am currently using to test TAB
NB. delimited text files before loading them with SSIS.

NB. read TAB delimited table files as symbols - see long document
readtd2s=:[: s:@<;._2&> (9{a.) ,&.>~ [: <;._2 [: (] , ((10{a.)"_ = {:) }. (10{a.)"_) (13{a.) -.~ 1!:1&(]<@.(32&>@(3!:0)))

tdkeytest=:4 : 0

NB.*tdkeytest v-- test natural key columns  of TAB delimited text
NB. files.
NB.
NB. Many of the raw tables of the ETL process depend on  compound
NB. primary keys. This verb applies a basic  test of primary  key
NB. columns. Passing this test  makes it very  likely  the  table
NB. will load  without key constraint  violations.  Failures  are
NB. still possible depending  on how  text  data is converted  to
NB. other  datatypes. Failure of this test indicates  a very high
NB. chance of key constraint violations.
NB.
NB. dyad:  il =. blclColnames tdkeytest clFile
NB.
NB.   f0=. 'C:\temp\dailytsv\raw_ST_BU.txt'
NB.   k0=. ;:'BuId XMLFileDate'
NB.   k0 tdkeytest f0
NB.
NB.   f1=. 'C:\temp\dailytsv\raw_ST_Item.txt'
NB.   k1=. ;:'BuId ItemId XMLFileDate'
NB.   k1 tdkeytest f1

NB. first row is header
h=. 0{d=. readtd2s y

NB. key column positions
'header key column(s) missing' assert -.(#h) e. p=. h i. s: x

c=. #d=. }. d
b=. ~:p {"1 d

NB. columns unique, rowcnt, nonunique rowcnt
if. r=. c = +/b do.
r , c , 0
else.
NB. there are duplicates show some sorted duplicate keys
k=. p {"1 d
d=. d {~ I. k e. k #~ -.b
d=. (/: p {"1 d) { d
b=. ~:p {"1 d
m=. +/b
smoutput (":m),' duplicate key blocks'
n=. DUPSHOW <. m
smoutput 'first ',(":n),' duplicate row key blocks'
smoutput (<p { h) ,&.> n {. ,. b <;.1 p {"1 d
r , c , #d
end.
)

1. The pay more option is always available.
2. WordPress.com is beginning to remind me of Adobe. Stop taking away longstanding features when upgrading!

# SWAG a J/EXCEL/GIT Personal Cash Flow Forecasting Mob

While browsing in a favorite bookstore with my son, I spotted a display of horoscope themed Christmas tree ornaments. The ornaments were glass balls embossed with golden birth signs like Aquarius, Gemini, Cancer, et cetera, and a descriptive phrase that “summed up” the character of people born under a sign. Below my birth sign golden text declared, “Imaginative and Suspicious.”

I said to my son, “I hate it when astrological rubbish is right.”

I am imaginative and suspicious; it’s a curse. When it comes to money my “suspicious dial” is permanently set on eleven. I assume everyone is out to cheat and defraud me until there is overwhelming evidence to the contrary. Paranoia is generally crippling but when it comes to cold hard cash it’s a sound retention strategy.

Prompted by an eminent life move, I found myself in need of a cash flow forecasting tool. Normal people deal with forecasting problems by buying standard finance programs or cranking up spreadsheets; imaginative and suspicious people roll their own.

## SWAG

SWAG, (Silly Wild Ass Guess), is a hybrid J/EXCEL/GIT mob1 that meets my eccentric needs. I wanted a tool that:

1. Abstracted away accounting noise.
2. Was general and flexible.
3. Used highly portable, durable, and version control friendly inputs and outputs.
4. Reflected what ordinary people, not tax accountants, actually do with money.
5. Is open source and unencumbered by parasitic software patents.

Amazingly, my short list of no-brainer requirements eliminates most standard finance programs. Time to code!

## SWAG Inputs

The bulk of SWAG is a JOD generated self-contained J script. You can peruse the script here. SWAG inputs and outputs are brain-dead simple TAB delimited text tables. Inputs consist of monthly, null-free, numeric time series tables, scenario tables, and name cross-reference tables. Outputs are simple, null-free, numeric time series tables. Input and output time series tables have identical formats.

A few examples will make this clear. The following is a typical SWAG input and output time series table.

 Date        E0      E1       E2      E3  E4     E5  E6  E7  E8  EC  EF  Etotal   I0       I1  I2  I3  I4  I5  IC  Itotal   R0         R1        R2  R3  Rtotal     D0  D1  D2  D3  D4  Dtotal  BB       NW         U0         U1  U2  U3
2015-09-01  912.00  1650.00  100.00  0   50.00  0   0   0   0   0   0   2712.00  4800.00  0   0   0   0   0   0   4800.00  130000.00  25000.00  0   0   155000.00  0   0   0   0   0   0       2088.00  157088.00  155000.00  0   0   0
2015-10-01  912.00  1656.88  100.00  0   50.00  0   0   0   0   0   0   2718.88  4806.00  0   0   0   0   0   0   4806.00  130054.17  25062.50  0   0   155116.67  0   0   0   0   0   0       2087.13  159291.79  0          0   0   0
2015-11-01  912.00  1663.78  100.00  0   50.00  0   0   0   0   0   0   2725.78  4812.01  0   0   0   0   0   0   4812.01  130054.17  25062.50  0   0   155116.67  0   0   0   0   0   0       2086.23  161378.02  0          0   0   0
2015-12-01  912.00  1670.71  100.00  0   50.00  0   0   0   0   0   0   2732.71  4818.02  0   0   0   0   0   0   4818.02  130054.17  25062.50  0   0   155116.67  0   0   0   0   0   0       2085.31  163463.33  0          0   0   0
2016-01-01  912.00  1677.67  100.00  0   50.00  0   0   0   0   0   0   2739.67  4824.05  0   0   0   0   0   0   4824.05  130054.17  25062.50  0   0   155116.67  0   0   0   0   0   0       2084.37  165547.70  0          0   0   0
2016-02-01  912.00  1684.66  100.00  0   50.00  0   0   0   0   0   0   2746.66  4830.08  0   0   0   0   0   0   4830.08  130054.17  25062.50  0   0   155116.67  0   0   0   0   0   0       2083.41  167631.12  0          0   0   0
2016-03-01  912.00  1691.68  100.00  0   50.00  0   0   0   0   0   0   2753.68  4836.11  0   0   0   0   0   0   4836.11  130054.17  25062.50  0   0   155116.67  0   0   0   0   0   0       2082.43  169713.55  0          0   0   0 

The first header line is a simple list of names. The first name “Date” heads a column of first of month dates in YYYY-MM-DD format. The SWAG clock has month resolution and dates are the only nonnumeric items. Names beginning with “E” like E0, E1, …, are aggregated expenses. Names beginning with “I” like I0, I1, I2 … are income totals. “R” names are reserves: basically savings, investments, equity and so forth. “D” names are various debts. BB is basic period balance, NW is period net worth and “U” names are utility series. Utility series facilitate calculations. Remaining names are self-explanatory totals. Be aware that this table has been formatted for this blog. Examples of raw input and output tables can be found here.

The next ingredient in the SWAG stew is what many call a scenario. A scenario is a collection of prospective assumptions and actions. In one scenario you buy a Mercedes and assume interest rates remain low. In another, you take the bus and rates explode. When forecasting I evaluate five basic scenarios, grim, pessimistic, expected, optimistic, and exuberant. Being a negative Debbie Downer type I rarely invest time in exuberant scenarios. I concentrate on grim and pessimistic scenarios because once you are mentally prepared for the worst anything better feels like a lottery win.

The following is a typical SWAG scenario table. Scenario tables, like time series tables, are simple TAB delimited text files.

 Name         Scenario On Group       Value  OnDate     OffDate    Method   MethodArguments                                                Description
reservetotal s0          assumptions 0      2015-09-01 2015-10-01 assume   RSavings=. 0.5 [ RInvest=. 3 [ REquity=. 3 [ ROther=. 1        annual nominal percent reserve growth or decline during period
car          s0                      50     2015-09-01 2035-08-01 history                                                                 annualized car maintenance until first death
house        s0                      912    2015-09-01 2016-08-01 history  BackPeriods=.1                                                 current rent until move
insurance    s0                      100    2015-09-01 2035-08-01 history                                                                 car insurance
living       s0                      1650   2015-09-01 2044-01-01 history  YearInflate=.5                                                 normal monthly living expenses
salary       s0                      4800   2015-09-01 2016-08-01 history  BackPeriods=.4 [ YearInflate=.1.5                              maintain net monthly income until move
reservetotal s0                      25000  2015-09-01 2015-10-01 reserve  Initial=.1 [ RInvest=. 1                                       stock value at model start
reservetotal s0                      130000 2015-09-01 2015-10-01 reserve  Initial=.1                                                     savings at model start
salary       s0                      4200   2016-08-01 2023-07-01 history  BackPeriods=.4 [ YearInflate=.1.5                              reduced net income after move until retirement
house        s0          move        2000   2016-08-01 2016-09-01 history                                                                 moving expenses
house        s0                      100    2016-08-01 2044-01-01 history                                                                 incidental housing expenses after move
house        s0                      100    2016-08-01 2044-01-01 history                                                                 home owners association payments
house        s0                      150    2016-08-01 2044-01-01 history                                                                 property taxes
reservetotal s0          buy house   110000 2016-08-01 2016-09-01 reserve  Initial=.1 [ REquity=. 1                                       down payment added to house equity initial setting prevents double spend
loan         s0          buy house   150000 2016-08-01 2023-02-01 borrow   Interest=. 4.5 [ YearTerm=. 30 [ DHouse=.1  [ LoanEquity=.1    30 year mortgage rate on house until inheritance
reservetotal s0          buy house   110000 2016-08-01 2016-09-01 spend                                                                   down payment on house from savings
annuities    s0                      250    2018-07-01 2035-08-01 history                                                                 monthly retirement and other annuity payments end date is unknown
annuities    s0                      50     2018-07-01 2035-08-01 history                                                                 any government pension payments
reservetotal s0          assumptions 0      2020-01-01 2044-01-01 assume   RSavings=. -2.5 [ RInvest=. -5.0 [ REquity=. -5.0 [ ROther=. 2 market tanks government introduces negative interest
loan         s0          buy car     10000  2020-07-01 2025-07-01 borrow   Interest=. 5 [ YearTerm=. 5 [ DCar=.1                          pay balance of car at 5% for 5 years
reservetotal s0          buy car     7000   2020-07-01 2020-08-01 spend                                                                   car down payment from savings
reservetotal s0          inherit     180000 2023-01-01 2023-02-01 reserve  Initial=.1                                                     inheritance to savings
reservetotal s0          buy house   150000 2023-03-01 2023-04-01 transfer Fee=. 1500 [ DHouse=.1                                         pay off remaining mortgage balance after inheritance fee is closing cost
salary       s0                      1400   2023-07-01 2035-08-01 history                                                                 estimated social security payments spread over expected life
insurance    s0                      700    2023-07-01 2024-12-01 history                                                                 medical insurance in the gap between retirement and spouse medicare eligibility
annuities    s0                      100    2024-12-01 2044-01-01 history                                                                 any retirement pension payments to spouse
annuities    s0                      100    2035-08-01 2044-01-01 history                                                                 any us social security survivor benefit after first death                       

Again the first header row is a simple list of names. Most scenario names are self-explanatory but four OnDate, OffDate, Method, and MethodArguments merit some explanation. SWAG series methods assume, history, reserve, transfer, borrow, and spend are modeled on what people typically do with cash.

1. assume sets expected interest rates and other global assumptions for a given time period. SWAG series methods operate over a well-defined time period. The period is defined by OnDate and OffDate.
2. history looks at past periods and estimates a numeric value that is projected into the future. Currently, history computes simple means but the underlying code can use arbitrary time series verbs.
3. reserve manages savings, investments, equity and other cash-like instruments.
4. borrow borrows money and sets future loan payments. borrow supports simple amortization loans but is also capable of reading an arbitrary payment schedule that can be used for exotic2 loans.
5. transfer moves money between reserves, debts, expenses and income series.
6. spend does just what you expect.

SWAG series methods adjust all the series affected by the method. As you might expect SWAG arguments methods are detailed. MethodArguments uses a restricted J syntax to set SWAG arguments. Argument order does not matter but only supported names are allowed. Many examples of SWAG MethodArguments can be found in the EXCEL spreadsheet tp.xlsx. I use EXCEL as a scenario editor. By setting EXCEL filters, you can manage many scenarios.

The final SWAG input is a name cross-reference table. It is another TAB delimited text file that defines SWAG names. You can inspect a typical cross-reference table here.

## Running SWAG

To run SWAG you:

1. Prepare input files.
2. Start J, any front-end jconsole, JQT or JHS will do, and load the Swag script.
3. Execute RunTheNumbers.
4. Open the EXCEL spreadsheet swag.xlsx, click on the data ribbon and then press the “Refresh All” button.

Let’s work through the steps.

## Prepare Input Files

By far the most difficult step is the first. Here you review your financial status which means checking bank balances, stock values, loan balances and so on. Depending on your holdings this could take anywhere from minutes to hours. I call this updating actuals. Not only is updating actuals the most difficult and time-consuming step it is also the most valuable. Money that is not closely watched leaks away.

I store my actuals in a simple tabbed spreadsheet. Each tab maintains an image of a text file. I enter my data and then cut and paste the sheets into a text editor where I apply final tweaks and then save the sheets as TAB delimited text files.

Monthly income, expenses and debts are easy to update but some of my holdings do not offer monthly statements. The verb RawReservesFromLast in Swag.ijs fills in missing months with the last known values. When I’m finished preparing input files I’m left with four actual TAB delimited files, RawIncome.txt, RawExpenses.txt, RawReserves.txt, and RawDebts.txt. You can inspect example actual files here.

## Start J and load the Swag script.

The SWAG script is relatively self-contained. It can be run in any J session that loads the standard J profile. Load Swag with the standard load utility.

 load 'c:/pd/fd/swag/swag.ijs'

Here SWAG is loaded in JHS.

Execute RunTheNumbers

RunTheNumbers sets the SWAG configuration, loads scenarios, copies actuals to each scenario, and then evaluates each scenario. Scenarios are numbered. I use positive numbers for “production” scenarios and negative numbers for test scenarios. It sounds more complicated that it is. This is all you have to do to execute RunTheNumbers

 RunTheNumbers 0 1 2 3 4 

The code is simple and shows what’s going on.

RunTheNumbers=:3 : 0

NB.*RunTheNumbers v-- compute all scenarios on list (y).
NB.
NB. monad:  blclFiles =. RunTheNumbers ilScenarios
NB.
NB.   RunTheNumbers 0 1 2 3 4

NB. parameters sheet is the last config sheet
ModelConfiguration_Swag_=:MainConfiguration_Swag_
parms=. ".;{:LoadConfig 0
scfx=. ScenarioPrefix

ac=. toHOST fmttd ActualSheet 0
ac write TABSheetPath,'MainActuals',SheetExt

sf=. 0\$a:
for_sn. y do.
ac write TABSheetPath,scfx,(":sn),'Actuals',SheetExt
sf=. sf , parms Swag sn [ LoadSheets sn
end.

sf
)

RunTheNumbers writes a pair of TAB delimited forecast and statistics files for each scenario it evaluates.

Open swag.xlsx and press “Refresh All”

The spreadsheet swag.xlsx loads SWAG TAB delimited text files and plots results.3 I plot monthly cash flow, estimated net worth and debt/equity for each scenario. The following is a typical cash flow plot. It estimates mean monthly cash balance over the scenario time range.

The polynomial displayed on the graph is an estimated trend line. Things are looking bleak.

Here’s a typical net worth plot.

In this happy scenario, we die broke and leave a giant bill for the government.4

So far SWAG has met my basic needs and forced me to pay more attention to the proverbial bottom line. As I use the system I will fix bugs, refine rough spots, and add strictly necessary features. Feel free to use or modify SWAG for your own purposes. If you find SWAG useful please leave a note on this blog or follow the SWAG repository on GitHub.

1. What do you call dis-integrated collections of programs that you use to solve problems? Declaring such dog piles “systems” demeans the word “system” and gives the impression that everything has been planned. This is not how I roll. “Mob” is far more appropriate. It conveys a proper sense of disorder and danger.
2. When borrowing money you should always plan on paying it all back. Insist on a complete iron clad repayment schedule. If such a schedule cannot be provided run like hell or prepare for the thick end of a baseball bat to be rammed up your financial ass.
3. It may be necessary to adjust file paths on the EXCEL DATA ribbon to load SWAG TAB delimited text files.
4. They can see me in Hell to collect.

# Turning JOD Dump Script Tricks

Have you ever wondered how extremely prolific bloggers do it? How is it possible to crank out thousands of blog entries per year without creating a giant stinking pile of mediocre doo-doo? Like most deep medium mysteries it’s not very deep and there are no mysteries. The spewers, people who post like teenage girls tweet, use two basic strategies:

1. Multiple authors: The heroic image of the lone blogger waging holy war against a sea of Internet idiocy is largely a myth. Many popular prolific blogs are the work of many hands. The editor at Analyze the Data not the Drivel eschews this tactic. Apparently he’s an incontinent and argumentative prima donna that sane people steer clear of.
2. Content recycling: In elementary school this was called copying. Now that we’re all grown up we use terms like, “excerpting”, “abstracting”, and my favorite “re-purposing.” The basic idea is simple. Take something you’ve written elsewhere and repackage it as something new. Hey, all the cool kids are doing it!

The following is a slightly edited new appendix I have just added to the JOD manual. I am working to properly publish the JOD manual mostly so I can say that I’ve written a legitimate, albeit strange and queer, book.

I created this post by running the $\LaTeX$ code of the manual appendix through the excellent utility pandoc, tweaking the resulting markdown, and then using pandoc again to generate html for this blog. pandoc is a great “re-purposing” tool!

Finally, re-purposing is not entirely cynical. The act of moving material from one medium to another exposes problems. I found a few editing errors while creating this post that eluded my $\LaTeX$ eyes. If you find more this is your chance to tell me what a moron I am.

# Turning JOD Dump Script Tricks

Dump script generation is my favorite JOD feature. Dump scripts serialize JOD dictionaries; they are mainly used to back up dictionaries and interact with version control systems. However, dump scripts are general J scripts and can do much more! Maintaining a stable of healthy JOD dictionaries is easier if you can turn a few dump script tricks.1

1. Flattening reference paths: Open JOD dictionaries define a reference path. For example, if you open the following dictionaries:
   NB. open four dictionaries
od ;:'smugdev smug image utils'
+-+-----------------------+-------+----+-----+-----+
|1|opened (ro/ro/ro/ro) ->|smugdev|smug|image|utils|
+-+-----------------------+-------+----+-----+-----+

the reference path is /smugdev/smug/image/utils.

When objects are retrieved each dictionary on the path is searched in reference path order. If there are no compelling reasons to maintain separate dictionaries you can improve JOD retrieval performance and simplify dictionary maintenance by flattening all or part of the path.

To flatten the reference path do:

   NB. reopen the first three dictionaries on the path
od ;:'smugdev smug image' [ 3 od ''
+-+--------------------+-------+----+-----+
|1|opened (ro/ro/ro) ->|smugdev|smug|image|
+-+--------------------+-------+----+-----+

NB. dump to a temporary file (df)
df=: {: showpass make jpath '~jodtemp/smugflat.ijs'
+-+---------------------------+-----------------------+
|1|object(s) on path dumped ->|c:/jodtemp/smugflat.ijs|
+-+---------------------------+-----------------------+

NB. create a new flat dictionary
newd 'smugflat';jpath '~jodtemp/smugflat' [ 3 od ''
+-+---------------------+--------+--------------------+
|1|dictionary created ->|smugflat|c:/jodtemp/smugflat/|
+-+---------------------+--------+--------------------+

NB. open the flat dictionary and (utils)
od ;:'smugflat utils'
+-+-----------------+--------+-----+
|1|opened (rw/ro) ->|smugflat|utils|
+-+-----------------+--------+-----+

NB. reload dump script ... output not shown ...
0!:0 df

The collapsed path /smugflat/utils will return the same objects as the longer path. It is important to understand that the collapsed dictionary smugflat does not necessarily contain the same objects found in the three original dictionaries smugdev, smug and image. If objects with the same name exist in the original dictionaries only the first one found will be in the collapsed dictionary.

2. Merging dictionaries: If two dictionaries contain no overlapping objects it might make sense to merge them. This is easily achieved with dump scripts. To merge two or more dictionaries do:
   NB. open and dump first dictionary
od 'dict0' [ 3 od ''
+-+--------------+-----+
|1|opened (rw) ->|dict0|
+-+--------------+-----+
df0=: {: showpass make jpath '~jodtemp/dict0.ijs'
+-+---------------------------+--------------------+
|1|object(s) on path dumped ->|c:/jodtemp/dict0.ijs|
+-+---------------------------+--------------------+

NB. open and dump second dictionary
od 'dict1' [ 3 od ''
+-+--------------+-----+
|1|opened (rw) ->|dict1|
+-+--------------+-----+
df1=: {: showpass make jpath '~jodtemp/dict1.ijs'
+-+---------------------------+--------------------+
|1|object(s) on path dumped ->|c:/jodtemp/dict1.ijs|
+-+---------------------------+--------------------+

NB. create new merge dictionary
newd 'mergedict';jpath '~jodtemp/mergedict' [ 3 od ''
+-+---------------------+---------+---------------------+
|1|dictionary created ->|mergedict|c:/jodtemp/mergedict/|
+-+---------------------+---------+---------------------+

NB. open merge dictionary and run dump scripts
od 'mergedict'
+-+--------------+---------+
|1|opened (rw) ->|mergedict|
+-+--------------+---------+

NB. reload dump scripts ... output not shown ...
0!:0 df0
0!:0 df1

Be careful when merging dictionaries. If there are common objects the last object loaded is the one retained in the merged dictionary.

3. Updating master file parameters: When a new parameter is added to jodparms.ijs it will not be available in existing dictionaries. With dump scripts you can rebuild existing dictionaries and update parameters. To rebuild a dictionary with new or custom parameters do:
   NB. save current dictionary registrations
(toHOST ; 1 { 5 od '') write_ajod_ jpath '~temp/jodregister.ijs'

NB. open dictionary requiring parameter update
od 'dict0' [ 3 od ''
+-+--------------+-----+
|1|opened (rw) ->|dict0|
+-+--------------+-----+

NB. dump dictionary and close
df=: {: showpass make jpath '~jodtemp/dict0.ijs'
+-+---------------------------+--------------------+
|1|object(s) on path dumped ->|c:/jodtemp/dict0.ijs|
+-+---------------------------+--------------------+

3 od ''
+-+---------+-----+
|1|closed ->|dict0|
+-+---------+-----+

NB. erase master file and JOD object id file
ferase jpath '~addons/general/jod/jmaster.ijf'
1
ferase jpath '~addons/general/jod/jod.ijn'
1

NB. recycle JOD - this recreates (jmaster.ijf) and (jod.ijn)
NB. using the new dictionary parameters defined in (jodparms.ijs)
(jodon , jodoff) 1
1 1

NB. re-register dictionaries
load jpath '~temp/jodregister.ijs'

NB. create a new dictionary - it will have the new parameters
newd 'dict0new';jpath '~jodtemp/dict0new' [ 3 od ''
+-+---------------------+---------+-------------------+
|1|dictionary created ->|dict0new|c:/jodtemp/dict0new/|
+-+---------------------+---------+-------------------+

od 'dict0new'
+-+--------------+--------+
|1|opened (rw) ->|dict0new|
+-+--------------+--------+

NB. reload dump script ... output not shown ...
0!:0 df  

Before executing complex dump script procedures back up your JOD dictionary folders and play with dump scripts on test dictionaries. Dump scripts are essential JOD dictionary maintenance tools but like most powerful tools they must be used with care.

1. Spicing up one’s rhetoric with a double entendre like “turning tricks” may be construed as a microaggression. The point of colored language is to memorably make a point. You are unlikely to forget turning dump script tricks.

# JOD Update: Version 0.9.97*

In the last year much has changed in the J world.

1. There are new official J 8.0x builds for all supported platforms.
2. The QT based IDE JDE has matured and is in widespread use.
3. The column oriented J database JD is drawing new users to J and enticing J veterans to reconsider how we use databases.
4. There is a small group of J system builders experimenting with additions, extensions and revisions of core J source code.

In short, there are have been enough changes to revisit and update JOD.

JOD version 0.9.97*1 is the first JOD update in many years that mocks the god of software compatibility. In particular:

1. The syntax of the jodhelp verb has changed.
2. The jodsource addon no longer uses a zip file to distribute JOD dump files.
3. JOD online help will no longer be supported or updated.
4. Volume size is no longer checked before creating new JOD dictionaries.
5. There is a new version of jod.pdf.

#### jodhelp changes (#1, #3 and #5)

jodhelp has always been a kludge. In programmer speak a kludge is some half-baked facility added to a system after more essential features have stabilized. The original versions of jodhelp pointed at my rough notes. It was all the “documentation” I needed! Then others stared using JOD which resulted in an “evolved” online version of my notes. I originally thought that hosting my notes online would simultaneously serve user needs and cut the amount of time I spent maintaining documentation. In retrospect this wasn’t even wrong!

I used Google Documents to host my notes. If you’ve ever wondered why completely free Google Documents hasn’t obliterated expensive Microsoft Word or hoary old excellent $\LaTeX$ I invite you to maintain a set of long-duration-documents with Google Documents. During jodhelp‘s online lifetime the basic internal format of Google Documents changed in a screw-your-old-documents upgrade which forced me to spend days repairing broken hyper-links and reformatting. I was not amused; you still get what you pay for!

I originally choose Google Documents because of its alleged global accessibility. Sadly, Google Documents is now often blocked by corporate and national firewalls. Even when it isn’t blocked it renders like a dog peeing on a fire hydrant. All these problems forced me to rewrite JOD documentation with a completely reliable tool: good old-fashioned $\LaTeX$. The result of my labors, jod.pdf, is now distributed by the joddocument addon and is easily browsed with jodhelp.

After jod.pdf‘s appearance another irritant surfaced: synchronizing jod.pdf and the online version. I tried using pandoc and markdown to generate both the online and PDF versions from the same source files but jod.pdf is too complex for not-to-fancy portable approaches. I was faced with a choice, lower my jod.pdf standards, or get rid of something I never really liked. I opted to drown a child and abandon online help. I don’t expect a lot of mourners at the funeral.

Using the new version of jodhelp requires installing the addon joddocument and configuring a J PDF reader. It’s also good idea to define a JQT PF key to pop up JOD help with a keystroke. To configure a J PDF reader edit the configuration file:

 ~config/base.cfg

this file is directly available from the JQT Edit\Configure menu. base.cfg defines a number of operating system dependent utilities. Make changes to the systems you use, save your changes, and restart J. The following example shows my Win64 system settings.

 case. 'Win' do.
BoxForm=: 1
Browser=: 'c:/Program Files (x86)/Google/Chrome/Application/chrome.exe'
Browser_nox=: ''
EPSReader=: 'c:/program files/ghostgum/gsview/gsview64.exe'
PDFReader=: 'c:/uap/sumatra/SumatraPDF.exe'
XDiff=: 'c:/uap/WinMerge-2.14.0-exe/winmergeu.exe'
Editor=: 'c:/uap/notepad++/notepad++.exe %f'
Editor_nox=: '' 

I use SumatraPDF to read PDF files on Windows. It’s a fast, lightweight, program that efficiently renders jod.pdf. Good PDF readers are available for all commonly used platforms.

To define JQT PK keys edit the configuration file:2

 ~config/userkeys.cfg


This file is also directly available from Edit\Configure menu. My JOD specific PF keys are:

 F3;1;Require JOD;require 'general/jod'
Shift+F3;1;JOD Help;jodhelp 0
F6;1;Dev Dicts;od cut 'joddev jod utils' [ 3 od ''
Shift+F6;1;Fit Dev Dicts;od cut 'jodfit joddev jod utils' [ 3 od ''
Ctrl+Shift+F6;1;Test Dev Dicts;od cut 'jodtest joddev jod utils' [ 3 od ''


Pressing Shift+F3 executes jodhelp 0 which pops up JOD help.

#### jodsource changes (#2)

The jodsource addon is a collection of JOD dump scripts. Dump scripts are serialized versions of binary JOD dictionaries. When executed they merge objects into the current JOD put dictionary. I use them primarily to move dictionaries around but they have other uses as well. Prior to this version I distributed the three main JOD development dump scripts, joddev, jod, and utils in one compressed zip file to reduce the size of JAL downloads.

The distributed script jodsourcesetup.ijs used the zfiles addon to extract these scripts and rebuild JOD development dictionaries. This worked on 32 bit Windows systems but failed elsewhere. J now runs on 32/64 bit Windows, Mac, Linux, IOS and Android systems. To better support all these variants I eliminated the zfiles dependency and pruned the JOD development dictionaries. The result is a more portable and smaller jodsource addon.

#### Bye bye volume sizing (#4)

Early versions of JOD ran in the now bygone era of floppy disks. It was possible to create many JOD dictionaries on a single standard 800 kilobyte 3.5 inch floppy. Compared to modern porcine-ware JOD, which many J’ers consider a huge system, is lithe and lean. In floppy days it was important to check if there was enough space on a floppy before creating another huge 48K empty JOD dictionary. This is a bit ridiculous today! If you don’t have 48K free on whatever device you are running you have far more serious problems than not being able to create JOD dictionaries.

Volume sizing code remained in JOD for years until it started giving me problems. Returning the size of very large network volumes can be time-consuming and there are serious portability issues. Every operating system calls different facilities to return volume sizes. Even worse, security settings on corporate networks and cloud architectures sometimes refuse to divulge national secrets like free byte counts.

To eliminate all these headaches this version of JOD no longer checks volume size when the FREESPACE noun is zero. To restore the previous behavior you have to edit the file

 ~addons/general/jod.ijs

and change the line FREESPACE=:0 to whatever byte count you want. Alternatively, you could NGAF3 and just assume you have 48K free on your terabyte size volumes.

#### Still to come

You may have surmised from JOD’s version number that the system is still not feature complete.  The JOD manual lists a few words that I am planning to implement. I only develop JOD when I need something or I am bored out of my mind at work and need a break. Such intermittent motivators seldom insure project completion but I have found a new reason to finish JOD. To list a book on Goodreads or Amazon you need an ISBN number.  The hardcopy version of the JOD manual is a sort-of-published book. To complete the publishing process I need an ISBN. If I am going to bother with such formalities I might as well complete the system the manual describes. So there you have it a new software development motivator: vanity.

1. The version number is *‘ed because you are always a point release from done!
2. userkeys.cfg is only available for J 8.03 systems.
3. Not Give a F%&k!

# Parsing the Bitcoin Genesis Block with J

The genesis block is the first block on the Bitcoin blockchain. Satoshi Nakamoto, the mysterious entity that created Bitcoin, mined the genesis block on January 3, 2009. It’s been five years since the genesis block’s birth and Satoshi is still unknown, Bitcoin is bigger than ever, and the blockchain is longer than 300,000 blocks and growing.

One of the most important features of the blockchain is its immutability. After the Bitcoin network accepts a block and adds it to the blockchain it can never be altered. This makes Bitcoin blocks rare durable binary artifacts. The cryptographic hash algorithms that underpin the Bitcoin protocol enforce block immutability. If someone decides to tinker with a block, say maliciously flip a single bit, the block’s hash will change and the network will reject it. This is what makes it almost impossible to counterfeit Bitcoins. Bitcoins have been lost and stolen but they have never been successfully counterfeited. This sharply contrasts with funny money like the US dollar that is so routinely and brazenly counterfeited that many suspect the US government turns a blind eye.

The exceptional durability of Bitcoin blocks, coupled with the mysterious origins of Bitcoin, makes the genesis block one of the most intriguing and important byte runs in the world. This post was inspired by the now defunct post 285 bytes that changed the world. I would love to give you a link but this post has vanished. A secondary, but excellent reference is John Ratcliff’s How to Parse the Bitcoin BlockChain. I am adapting John’s nomenclature in what follows.

When programmers start exploring Bitcoin they often cut their teeth on parsing the genesis block. If you Google “blockchain parsing” you’ll find examples in dozens of programming languages. The most popular are C, C++, Java, PHP, C#, JavaScript, and the rest of the mainstream suspects. What you will not find, until now, are J examples.

So what does J bring to the table that makes yet another genesis block parser worth a look? Let’s take a look at Bitcoin addresses. The following is the Bitcoin address of this blog’s tip jar. Feel free to send as many Satoshis and full Bitcoins as you like to this address.

   tip=. '17MfYvFqSyeZcy7nKMbFrStFmmvaJ143fA'

There is nothing deep or mysterious about this funny string of letters; it’s just a plain old number in Bitcoin base 58 clothing. So, what is this number in standard format? Here’s how it’s calculated with J.

   BASE58=. '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

dfb58=. 58x #. BASE58 i. ]

dfb58 tip
1709618896654985460726422911112500711652231559804656492485

The second line that defines dfb58, (decimal from base 58), is the complete J program! That’s it folks. You can troll the internet for days looking at base 58 to big integer converters and it’s unlikely you will find a shorter or more elegant conversion program. Not only is the J version short and sweet it’s also fast and versatile. Suppose you wanted to convert ten thousand Bitcoin addresses. The following converts ten thousand copies of tip.

   dfb58 10000 # ,: tip
1709618896654985460726422911112500711652231559804656492485 17096188966549854607264...

At this point fanboys of mainstream programming languages typically pipe up with something like, “changing number encodings is inherently trivial; what about something more demanding like going the other way, say converting Bitcoin public keys to the base 58 address format?”

The public key in the genesis block is encoded in what many call the “challenge script.” Here is the genesis block’s challenge script in hex.

41 04 67 8A FD B0 FE 55 48 27 19 67 F1 A6 71 30 B7 10 5C D6
A8 28 E0 39 09 A6 79 62 E0 EA 1F 61 DE B6 49 F6 BC 3F 4C EF
38 C4 F3 55 04 E5 1E C1 12 DE 5C 38 4D F7 BA 0B 8D 57 8A 4C
70 2B 6B F1 1D 5F AC

Public keys take a number of forms in the blockchain. John Ratcliff’s post summarizes the many forms you will run into. The genesis block uses the 65 byte ECDSA form. Converting this form to base 58 requires taking SHA-256 and RIPEMD-160 hashes. These hashes are available in OpenSSL which is conveniently distributed with J 8.02 JQT. Here’s how to convert the genesis block’s public key to base 58 with J.

   load 'c:/bitjd/scripts/sslhash.ijs'

Base58frKey65=:3 : 0

NB.*Base58frKey65 v-- 65 byte public Bitcoin key bytes to base 58.
NB.
NB. monad:  clB58 =. Base58frKey65 clBytes

ekey=. (0{a.) , sr160 s256 y
csum=. 4 {. s256 s256 ekey
Base58Check ekey,csum
)

Base58frKey65 }. }: ChallengeScript
1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa


The ChallengeScript noun holds the bytes given in hex above. The verbs sr150, s256 and Base58Check are available in the J scripts sslhash and ParseGenesisBlock that I have put in the jacks repository on GitHub.

The following J verb ParseGenesisBlock reads the first full node Bitcoin block file and then extracts and checks the genesis block. ParseGenesisBlock tests the various verbs, (functions), it employs. As a side effect it clearly describes the layout of the genesis block and provides test data for anyone that’s interested.

If this post peeks your curiosity about J a good place to start learning about the language is the recently released New Dictionary of J. You can download a version of J for Windows, Linux, OS/X, IOS, and Android at Jsoftware’s main site.

ParseGenesisBlock=:3 : 0

NB.*ParseGenesisBlock v-- parse and check Bitcoin genesis block.
NB.
NB. monad:  clMsg =. ParseGenesisBlock clBlockFile
NB.
NB.   file=. 'c:/bitjd/blocks/blk00000.dat'
NB.   ParseGenesisBlock file

NB. fetch genesis block data
dat=. read y

NB. first 4 bytes are "sort of" block delimiters
MagicID=: (i. offset=. 4) { dat
'MagicID mismatch' assert 'F9BEB4D9' -: ,hfd a. i. MagicID

NB. next 4 bytes gives following block length
offset=. offset + 4 [ BlockLength=: _2 ic (offset + i. 4) { dat
'BlockLength mismatch' assert 285 = BlockLength

NB. next 4 bytes block format version - has changed
offset=. offset + 4 [ VersionNumber=: _2 ic (offset + i. 4) { dat

NB. next 32 bytes is previous block hash - genesis block
NB. has no previous hash and all bytes are set to 0
offset=. offset + 32 [ PreviousBlockHash=: (offset + i. 32) { dat
'PreviousBlockHash mismatch' assert (32#0) -: a. i. PreviousBlockHash

NB. next 32 bytes is the Merkle tree root hash
offset=. offset + 32 [ MerkleRoot=: (offset + i. 32) { dat
grh=. '3BA3EDFD7A7B12B27AC72C3E67768F617FC81BC3888A51323A9FB8AA4B1E5E4A'
'MerkleRoot mismatch' assert grh -: ,hfd a. i. MerkleRoot

NB. next 4 bytes is a unix epoch timestamp - rolls over 7th feb 2106
NB. there is no timezone information - it is interpreted as utc
offset=. offset + 4 [ TimeStamp=: _2 ic (offset + i. 4) { dat
'TimeStamp mismatch' assert 2009 1 3 18 15 5 -: ,tsfrunixsecs TimeStamp

NB. next 4 bytes represents block target difficulty
offset=. offset + 4 [ TargetDifficulty=: _2 ic (offset + i. 4) { dat
'TargetDifficulty mismatch' assert 486604799 = TargetDifficulty

NB. next 4 bytes is a random number nonce
offset=. offset + 4 [ Nonce=: (offset + i. 4) { dat
'Nonce mismatch' assert '1DAC2B7C' -: ,hfd a. i. Nonce

NB. next 1 to 9 bytes is the transaction count stored as a variable length integer
NB. see:  https://en.bitcoin.it/wiki/Protocol_specification#Variable_length_integer
offset=. offset + vlen [ 'vlen TransactionCount'=: vint (offset + i. 9) { dat
'TransactionCount mismatch' assert TransactionCount = 1  NB. (*)=. vlen

NB. next 4 bytes transaction version number
offset=. offset + 4 [ TransactionVersionNumber=: _2 ic (offset + i.4) { dat
'TransactionVersionNumber mismatch' assert 1 = TransactionVersionNumber

NB. next 1 to 9 bytes is the number of transaction inputs
offset=. offset + vlen [ 'vlen TransactionInputNumber'=: vint (offset + i. 9) { dat

NB. next 32 bytes is the hash of the input transaction
offset=. offset + 32 [ TransactionHash=: (offset + i. 32) { dat
'TransactionHash mismatch' assert (32#0) -: a. i. TransactionHash

NB. next 4 bytes is the input transaction index
offset=. offset + 4 [ TransactionIndex=: _2 ic (offset + i. 4) { dat
'TransactionIndex mismatch' assert _1 = TransactionIndex

NB. input script length is next
offset=. offset + vlen [ 'vlen InputScriptLength'=: vint (offset + i. 9) { dat
'InputScriptLength mismatch' assert 77 = InputScriptLength

NB. script data
offset=. offset + InputScriptLength [ InputScript=: (offset + i. InputScriptLength) { dat

NB. sequence number 4 bytes
offset=. offset + 4 [ SequenceNumber=: ,hfd a. i. (offset + i. 4) { dat
'SequenceNumber mismatch' assert 'FFFFFFFF' -: SequenceNumber

NB. output count 1 to 9 bytes
offset=. offset + vlen [ 'vlen OutputCount'=: vint (offset + i.9) { dat

NB. output value - number of satoshis sent
offset=. offset + 8 [ OutputSatoshis=: (offset + i.8) { dat  NB. 64 bit unsigned integer
'OutputSatoshis mismatch' assert '00F2052A01000000' -: ,hfd a. i. OutputSatoshis
OutputSatoshis=: ](_3&ic)@.IF64 OutputSatoshis

NB. challenge script length
offset=. offset + vlen [ 'vlen ChallengeScriptLength'=: vint (offset + i.9) { dat
'ChallengeScriptLength mismatch' assert 67 = ChallengeScriptLength

NB. challenge script - contains elliptic curve signatures
offset=. offset + ChallengeScriptLength [ ChallengeScript=: (offset + i. ChallengeScriptLength) { dat
'ChallengeScript mismatch' assert GenesisBlockChallengeScript -: ,hfd a. i. ChallengeScript

NB. challenge script is 67 bytes drop first and last byte to
NB. compute the familiar Bitcoin base 58 address - compare with block explorer
NB. http://blockexplorer.com/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
OutputAddress=: Base58frKey65 }. }: ChallengeScript
'Genesis Block address mismatch' assert GenesisBlockOutputAddress -: OutputAddress

NB. last 4 bytes lock time
TransactionLockTime=: (offset + i.4) { dat
'TransactionLockTime mismatch' assert 0 0 0 0 -: a. i. TransactionLockTime

'Genesis Block Parsed and Checked'
)


# JOD Update: J 8.02 QT/JHS/64 bit Systems

I have pushed out a JOD update that makes it possible to run the addon on J 8.02 systems. In the last eight months a QT based J IDE has been developed that runs on Linux, Windows and Mac platforms. To maintain JOD’s compatibility across all versions of J from 6.02 on I had to tweak a few verbs.

The only significant changes are how JOD interacts with various J system editors.  I have tested the system on Windows  J 6.02, J 7.01, J 8.02, and Mac J 7.01 systems. I expect it will behave on 32 and 64 bit Linux systems from J 7.01 on, but I have yet to test these setups. My hardware budget limits my ability to run common variants of Windows, Linux and Mac systems.

JOD is still not complete; that’s why the version number has not been bumped past 1.0.0. The missing features are noted in the table of contents of jod.pdf, (also available in the joddocument addon), with the suffix “NIMP,” which means “not implemented.”  I will fill in these blanks as I need them. Most of the time JOD meets my needs so don’t hold your breath.

If you want to make your own additions to JOD the program and documentation source is available on GitHub. Just follow the links and enjoy.

As a last note: I will be at the J Conference in Toronto (July 24 and 25, 2014) where I will be giving a short presentation and handing out a few hardcopy versions of the JOD manual to one or two JOD fans.

# APL Software Archaeology .dbi Edition

Have yourself a merry little APL Christmas.

I joke that my job title should be software archaeologist because I often find myself resurrecting, not refactoring, code that dates to primitive and primeval eras. The language I’m typically hired to resurrect is APL. APL, the language with funny symbols, is a software vampire. People keep paying us to kill it, but no matter how many stakes we pound through its heart it keeps coming back.

There are good reasons for this. APL embodies many timeless ideas and I’m confident that programming in the future will look a lot more like APL than many expect. If you doubt me just press the Siri button on your iPhone and ask, “Integrate X squared times sine X from 0 to 2.” What comes back has more of an APL than QWERTYUIOP flavor. Strange Unicode characters are creeping into many mainstream languages. This is a good thing because restricting programming to the miserly key sets of ancient typewriters was, is, and always will be a spectacularly bad idea. Ken Iverson deserves rich accolades for pointing this out more than fifty years ago and beating this drum incessantly during his lifetime. Iverson taught that notation is a tool of thought and that if you care about ideas you must care about how they are expressed. Why is this even remotely controversial?

Siri’s results use appropriate mathematical notations. As we move away from keyboards programming languages and mathematical notation will merge. APL was way ahead of its time in this respect.

The genius of APL continues to exert influence on many programming languages, but APL’s rise had little to do with its abstract notation and a lot to do with how it was implemented. APL was one of the first programming environments that nonprogrammers could use. It was the spreadsheet of the late 1960’s and 1970’s and just like spreadsheets of today a lot of utterly horrid, poorly structured, lame amateur messes were created with it. If you’ve ever cracked open a gigantic Excel model that looks like it was developed by a roomful of quarreling ADHD afflicted unionized chimpanzees then you know what the standard APL mess feels like. Many programmers blamed APL for this just like gun control advocates blame firearms for shootings. They argued that it would have been impossible to concoct such monsters in clean compiled languages like Pascal. “It wouldn’t even compile.” This is not even wrong. I’ve dealt with plenty of dreadful messes that do compile! The tool is always neutral; don’t blame the paintbrush for the painting.

Allowing rubes to code yields mountains of rubbish and the occasional ruby. It will shock many programmers to learn they are not the only smart people in the world. It turns out that nonprogrammers occasionally have good ideas and, miraculously, some of them can ably express their ideas in code. Before spreadsheets such user rubies congealed in APL where some still run. Part of my day job is extracting these precious stones from layers and layers of kluges, hacks, patch jobs, retro-fits and workarounds and recoding them in modern programming languages like C# and JavaScript.

Recently I recovered1 an ancient inverted file system embedded in the APL systems of my employer and rendered it in C#. This system uses the extension .dbi. I don’t know who created this system; the code is old. The most recent code comments date from the year 2000, but I am pretty sure that .dbi files predate component files in APL+WIN, formerly STSC APL, which pushes the design back to the 1980’s or earlier. I know many APL’ers check this blog. If any of you know who created the original .dbi APL code please leave a note.

Somehow this .dbi system survived unsupported, with few user complaints, for decades of daily use. How is this possible? Astonishingly, good ideas age well and the core .dbi idea is inverted data. Modern high-performance databases make heavy use of this method. Inversion is so effective that hoary old interpreted APL code still beats compiled and optimized ADO.Net when fetching large numeric vectors and tables.

Restoring the .dbi system was a two-step process.2 I first converted the APL system to J. I used J because it is a close relative of APL but not so close that you can cut and paste. Translating nontrivial APL to J forces you to understand the APL at the nit-bitty level. The translation to J also allowed me to fix the APL interface. The original system used global variables, rampant branches and other lamentable coding practices that C# will not abide. After matching the APL and J systems I then translated the J to C# and then rematched all three systems.

Comparing multiple systems is a very effective testing technique. I found bugs in all three systems. I fixed the J and C# bugs but left the original APL code unchanged. Software archaeology is a delicate field. You don’t “fix” old code just like you don’t correct errors in cuneiform tablets. Original and important program code belongs in museums with other significant cultural artifacts.

Original inverted file code probably belongs in a museum. This .dbi APL code is old, but it certainly derives from earlier programs so it’s not museum worthy. Even if it was the APL and C# .dbi systems belong to my employer. However, I am placing the J scaffold version, which matches the performance of the other systems, into the public domain. The script is available on GitHub and here. The .dbi system gets right down to bits in some cases and illustrates some J techniques for dealing with indexed binary inverted file data. Enjoy!

1.  .dbi files held many gigabytes of actuarially tuned data. Dumping them was not an option. We either had to convert to a new store or produce a component that could read old data in new systems.
2. Restoring old code is somewhat like restoring old pictures. When working on old pictures you’re always tempted to improve them. With pictures you usually have a choice. This may not hold for old code. Changes in software may force updates.

# Jacks Repository

The other day I attempted to browse a J script described in an old blog post only to find that my employer’s network monkeys had blocked the file sharing service. I’ve railed about IT control freaks in the past. They will not rest until it’s impossible to do useful work. I fumed and grumbled until I perceived a bigger problem. I have so many references to program code in this blog that it’s getting tedious tracking them down. Wouldn’t it be nice if my hacks were neatly organized in one coherent repository?

Let me introduce jacks. jacks, or “J-hacks”, organizes the J related code referenced in this blog into a single GitHub repository. Most of the scripts in jacks are one-offs but some have proven so useful that it makes sense to store them in a repository and track changes. From now on jacks will be the first place to look for code from this blog. You pull the contents of jacks into a new Git repository with the commands:

git init
git remote add jacks https://github.com/bakerjd99/jacks.git
git pull jacks master


It took me a few moments to settle on the name “jacks.” I considered “jokes” because programmers often take their code too seriously and “jocks” because J programmers are wild out of control convention eschewing code jocks but jacks` won out when I remembered the refrain “jack be nimble, jack be quick, jack jump over” whatever coding problem is pissing you off.