# NumPy another Iverson Ghost

During my recent SmugMug API and Python adventures I was haunted by an Iverson ghost: NumPy

An Iverson ghost is an embedding of APL like array programming features in nonAPL languages and tools.

You would be surprised at how often Iverson ghosts appear. Whenever programmers are challenged with processing large numeric arrays they rediscover bits of APL. Often they’re unaware of the rich heritage of array processing languages but in NumPy's case, they indirectly acknowledged the debt. In Numerical Python the authors wrote:

“The languages which were used to guide the development of NumPy include the infamous APL family of languages, Basis, MATLAB, FORTRAN, S and S+, and others.”

I consider “infamous” an upgrade from “a mistake carried through to perfection.”

Not only do developers frequently conjure up Iverson ghosts. They also invariably turn into little apostles of array programming that won’t shut up about how cutting down on all those goddamn loops clarifies and simplifies algorithms. How learning to think about operating on entire arrays, versus one dinky number at a time, frees the mind. Why it’s almost as if array programming is a tool of thought.

Where have I heard this before?

Ahh, I’ve got it, when I first encountered APL almost fifty years ago.

Yes, I am an old programmer, a fossil, a living relic. My brain is a putrid pool of punky programming languages. Python is just the latest in a longish line of languages. Some people collect stamps. I collect programming languages. And, just like stamp collectors have favorite stamps, I find some programming languages more attractive than others. For example, I recognize the undeniable utility of C/C++, for many tasks they are the only serious options, yet as useful and pervasive as C/C++ are they have never tickled my fancy. The notation is ugly! Yeah, I said it; suck on it C people. Similarly, the world’s most commonly used programming language JavaScript is equally ugly. Again, JavaScript is so damn useful that programmers put up with its many warts. Some have even made a few bucks writing books about its meager good parts.

I have similar inflammatory opinions about other widely used languages. The one that is making me miserable now is SQL, particularly Microsoft’s variant T-SQL. On purely aesthetic grounds I find well-formed SQL queries less appalling than your average C pointer fest. Core SQL is fairly elegant but the macro programming features that have grown up around it are depraved. I feel dirty when forced to use them which is just about every other day.

At the end of my programming day, I want to look on something that is beautiful. I don’t particularly care about how useful a chunk of code is or how much money it might make, or what silly little business problem it solves. If the damn code is ugly I don’t want to see it.

People keep rediscovering array programming, best described in Ken Iverson’s 1962 book A Programming Language, for two basic reasons:

1. It’s an efficient way to handle an important class of problems.
2. It’s a step away from the ugly and back towards the beautiful.

Both of these reasons manifest in NumPy‘s resounding success in the Python world.

As usual, efficiency led the way. The authors of Numerical Python note:

Why are these extensions needed? The core reason is a very prosaic one, and that is that manipulating a set of a million numbers in Python with the standard data structures such as lists, tuples or classes is much too slow and uses too much space.

Faced with a “does not compute” situation you can either try something else or fix what you have. The Python people fixed Python with NumPy. Pythonistas reluctantly embraced NumPy but quickly went apostolic! Now books like Elegant SciPy and the entire SciPy toolset that been built on NumPy take it for granted.

Is there anything in NumPy for programmers that have been drinking the array processing Kool-Aid for decades? The answer is yes! J programmers, in particular, are in for a treat with the new Python3 addon that’s been released with the latest J 8.07 beta. This addon directly supports NumPy arrays making it easy to swap data in and out of the J/Python environments. It’s one of those best of both worlds things.

The following NumPy examples are from the SciPy.org NumPy quick start tutorial. For each NumPy statement, I have provided a J equivalent. J is a descendant of APL. It was largely designed by the same man: Ken Iverson. A scumbag lawyer or greedy patent troll might consider suing NumPy‘s creators after looking at these examples. APL’s influence is obvious. Fortunately, Ken Iverson was more interested in promoting good ideas that profiting from them. I suspect he would be flattered that APL has mutated and colonized strange new worlds and I think even zealous Pythonistas will agree that Python is a delightfully strange world.

## Some Numpy and J examples

Selected Examples from https://docs.scipy.org/doc/numpy-dev/user/quickstart.html Output has been suppressed here. For a more detailed look at these examples browse the Jupyter notebook:  NumPy and J Make Sweet Array Love.

## Creating simple arrays


# numpy
a = np.arange(15).reshape(3, 5)

NB. J
a =. 3 5 $i. 15 # numpy a = np.array([2,3,4]) NB. J a =. 2 3 4 # numpy b = np.array([(1.5,2,3), (4,5,6)]) NB. J b =. 1.5 2 3 ,: 4 5 6 # numpy c = np.array( [ [1,2], [3,4] ], dtype=complex ) NB. J j. 1 2 ,: 3 4 # numpy np.zeros( (3,4) ) NB. J 3 4$ 0

# numpy - allocates array with whatever is in memory
np.empty( (2,3) )

NB. J - uses fill - safer but slower than numpy's trust memory method
2 3 $0.0001  ## Basic operations  # numpy a = np.array( [20,30,40,50] ) b = np.arange( 4 ) c = a - b NB. J a =. 20 30 40 50 b =. i. 4 c =. a - b # numpy - uses previously defined (b) b ** 2 NB. J b ^ 2 # numpy - uses previously defined (a) 10 * np.sin(a) NB. J 10 * 1 o. a # numpy - booleans are True and False a < 35 NB. J - booleans are 1 and 0 a < 35 ## Array processing  # numpy a = np.array( [[1,1], [0,1]] ) b = np.array( [[2,0], [3,4]] ) # elementwise product a * b NB. J a =. 1 1 ,: 0 1 b =. 2 0 ,: 3 4 a * b # numpy - matrix product np.dot(a, b) NB. J - matrix product a +/ . * b # numpy - uniform pseudo random a = np.random.random( (2,3) ) NB. J - uniform pseudo random a =. ? 2 3$ 0

# numpy - sum all array elements - implicit ravel
a.sum(a)

NB. J - sum all array elements - explicit ravel
+/ , a

# numpy
b = np.arange(12).reshape(3,4)
# sum of each column
b.sum(axis=0)
# min of each row
b.min(axis=1)
# cumulative sum along each row
b.cumsum(axis=1)
# transpose
b.T

NB. J
b =. 3 4 $i. 12 NB. sum of each column +/ b NB. min of each row <./"1 b NB. cumulative sum along each row +/\"0 1 b NB. transpose |: b ## Indexing and slicing  # numpy a = np.arange(10) ** 3 a[2] a[2:5] a[ : :-1] # reversal NB. J a =. (i. 10) ^ 3 2 { a (2 + i. 3) { a |. a # 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.

# 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=: ''
XDiff=: 'c:/uap/WinMerge-2.14.0-exe/winmergeu.exe'
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

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

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.

# More about JHS with the DHTMLX Grid

I have resolved my DHTMLX standard edition row data extraction problem. The standard edition does not serialize grids or track user cell changes. You have to pay for such luxuries. Because I’m a foul software Grinch and this is just an exploratory hack I had to roll my own. I am posting the relevant JavaScript because I could not find similar examples. Here is how you can fetch rows from standard edition DHTMLX grids and save them as JSON in a hidden textarea element. Eric Iverson suggested hidden textareas and they work like a charm.

function ev_saveme_click(){

if ('undefined' != typeof grid0){

if (0 == grid0.getRowsNum()){
jbyid("rerowcnt").innerHTML = "No rows to save";
return;
}

var st = new Date().getTime(),  // start time
ids = grid0.getAllRowIds(","),
ccnt = 1 + grid0.getColumnsNum();  // includes id

ids = ids.split(",");
var rcnt = ids.length,
tab = new Array(rcnt);

// header row - tab[0][0] cell ignored
tab[0] = new Array(ccnt);
for (var i = 1; i < ccnt; i++) {
tab[0][i] = grid0.getColumnLabel(i-1,0);
}

// cells with leading row id
for (var i = 0 , si = 1 ; i < rcnt; i++ , si++) {
tab[si] = new Array(ccnt);
for (var j = 1; j < ccnt; j++) {
tab[si][j] = grid0.cells((+ids[i]),j-1).getValue();
}
tab[si][0] = ids[i];
}

// prefix row column counts
var pfx = (rcnt+1) + " " + ccnt + "*";
jbyid("gridchgs").innerHTML = pfx + JSON.stringify(tab);
jdoajax(["gridchgs","tout"],"");

var et = new Date().getTime() - st;  // end time
jbyid("rerowcnt").innerHTML= " row count= " + grid0.getRowsNum() +
",  JavaScript ms= " + et;

} else {

jbyid("rerowcnt").innerHTML= "Nothing to save";
}
}


Passing data back to J is fast but the J JSON addon convert\json burps on large datasets. For this demo I substituted a simple table oriented parser that is much faster.

# JHS with the DHTMLX Grid

Grids are the most important GUI user object. It’s hard to think of a user-friendly data munching application that doesn’t have a grid beating at its heart. Consequently, any serious GUI interface contender must support grids. My previous post showed how to use MathJax with JHS. MathJax is an impressive and important JavaScript library; it clearly demonstrates the potential of CHJ1 GUI interfaces but let’s face it, mathematical typesetting will not win many consulting contracts. Grids won’t seal the deal either but their absence is a huge “next” signal. To support serious business and technical applications JHS needs grids.

Fortunately, the JavaScript world is grid saturated. The difficulty is not finding a grid but choosing among dozens of candidates. For this demo I Googled around and found DHTMLX. According to this probably biased article the DHTMLX grid performs well on large inputs and, more importantly, there is an open source version.

You have to start somewhere so I opted to use DHTMLX to build a simple CSV file editor. The CSV files I am going to edit are TAB delimited text files. Each file has a fixed number of columns with column names in the first row. Here is an example TAB delimited file. The idea is to load the file data into the grid. Tweak a few rows and save the result. By increasing the size of the CSV file we can gauge the performance of the grid. Let’s get started.

Using the DHTMLX grid requires some preparation.

1. Create a local directory and edit J’s ~config/folders.cfg to reference the directory with the name GridDemo. jpath '~GridDemo' should return the full directory path.
2. Download the files in the GridDemo folder and copy them to ~GridDemo.
3. Download the Standard Edition (Version 3.5) of DHTMLX. The distribution file dhtmlxGrid.zip contains the grid source and supporting files.
4. Extract the /dhtmlxGrid/codebase/ directory from dhtmlxGrid.zip and copy the entire directory tree to ~GridDemo.
5. Also extract /dhtmlxGrid/samples/common from dhtmlxGrid.zip and copy the directory to ~GridDemo.

When you’re finished the top-level of ~GridDemo will look like the following where names without extensions are directories.

    calendar           dhtmlxgrid.js         GridDemo.ijs   t100rows.txt
common             dhtmlxgrid_skins.css  imgs           t5000rows.txt
dhtmlxcommon.js    excells               jodoval.png
dhtmlxgridcell.js  ext                   skins
dhtmlxgrid.css     favicon.ico           t1000rows.txt

The main J script is ~GridDemo\GridDemo.ijs. Start JHS and load this file.

    load '~GridDemo/GridDemo.ijs'

Then browse to this site.

    http://127.0.0.1:65001/GridDemo

If all goes well you will see the following GridDemo page after pressing the Edit Grid button.

Screenshot of GridDemo running on Chrome

To load and edit files enter their fully qualified names in the Input and Output boxes and press Edit Grid. To edit a cell double-click it. To save changes press Save Grid.2 There are more sophisticated ways to pick files on JavaScript pages. It’s easy to pop up standard host OS file dialogs but it’s not particularly easy to determine host directory paths. This post outlines the demons web programmers must slay to select host files. JHS circumvents these difficulties by asking the J server, which is a typically a local console process, to do the dirty work. JavaScript’s access to local files is limited for security reasons but J has no such restrictions. Use the force Luke!

Three test files t100rows.txt, t1000rows.txt, and t5000rows.txt are included with the demo. On my test machines load times vary from fractions of a second for the smaller files to nine seconds for the largest. This is competitive with the basic C# grid control and fast enough for serious work.

In subsequent posts I will explore JavaScript/JHS graphics options and start the process of integrating, grids, graphs and MathJax with JHS.

1. CSS, HTML and JavaScript.
2. The freebie version of DHTMLX does not support grid serialization. Here is how to roll your own.