Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Sunday, March 18, 2018

A Tale of a JavaScript Memory Leak

Abstract: Matching JavaScript regular expressions against large input strings with V8 can result in memory leaks. In this post, I explain how to troubleshoot the issue using Google Chrome heap snapshots. Finally, a fix proposed by my son David (age 14) is presented.

Background

At Just-BI we developed a browser-based application for one of our customers. One way the application gets its data is by loading and parsing Microsoft Excel files. The app is succesful and our customers are happy, a fact they express by attempting to load ever larger files.

On mobile Safari (iPad), our app starts crashing when the files reach a certain size. This happens around 5 to 6 MB. Argueably, that's not that large, but things are a bit more complicated: Microsft Excel files, at least those of the .xlsx variety, are actually zip-compressed folders, containing mostly OOXML spreadsheet documents.

It is a well known fact that XML is really verbose, and I suppose we should be grateful that our 5 - 6 MB excel files uncompress to only 40 MB of XML.

We could debug the issue somewhat, and we noticed that by the time Safari crashes, it does so reporting it is out of heap space. We can't be sure if that's the actual cause, but we think we might be able to overcome or at least postpone this issue by somehow cutting down on memory usage.

This brings us to the main topic of our tale.

Parsing xlsx files in the Browser

To parse xlsx files, we use a particular javascript library called js-xlsx. This is actually a pretty nice piece of work, and I do not hesitate to recommend it. We have used it for quite a while without major issues; It's just that the particular strategey that this library uses to parse the xlsx file will temporarily spike memory usage, and we believe this triggers some bug in Safari, which eventually leads to a crash.

So, we're currently investigating a less general, less standards-compliant way to parse xlsx files. In return, this allows us to parse xlsx faster, and with a much reduced peak-memory usage.

I don't want to talk too much in detail about the xlsx parser we're developing. All I can say it is not meant to be a general, fully featured xlsx parser; the only requirement it is designed to fulfill is to avoid or at least postpone the crash we observe in Safari, and to parse portions of xlsx workbooks having a well-known structure specific to our application requirements.

I am happy to report that, with just one day of work, we managed to get an initial version of our parser to work. It has a peak-memory usage that is half that of the previous solution. And it sounds even more spectacular when I write: 100% less memory!

As an added bonus, the new solution is just a little less than 10x as fast as the old solution. For some reason, it does not sound much cooler when I say the new solution is about an order of magnitude faster, so I won't.

JavaScript Regular Expressions

Our parser relies on JavaScript regular expressions, which are exposed through the global built-in RegExp object.

One might be aware that for at least 100 different programming languages there at least 10,000 stackexchange answers to wittily denounce any attempt to parse XML using regular expressions. Some bloggers' entire careers seems built entirely around their particular brand of scorn and disdain about this topic.

We have little to add to discussions like these, other than that in modern JavaScript runtimes, regular expressions are a very productive and powerful tool for quickly building tokenizers. These tokenizers can have amazing performance, and can serve admirably as a foundation to build parsers of many kinds, including but certainly not limited to XML-parsers.

A Memory Leak

Despite the initial success, not all is well with our new xlsx parser. We found that, notwithstanding lower peak-memory consumption, it did suffer from a memory leak. We noticed this by creating a simple sample application, loading only our parser, and then making heap snapshots using Chrome developer tools during various phases of the process. See the screenshot below:



This is what happens:
  1. First heap snapshot was made directly after loading the application, and measures 6.5 MB. Whether you think this is a lot or not, this is our baseline, and there is not much we can do about it now.
  2. Next, the user picks a xlsx workbook, and the application opens it. The snapshot is now 12.6 MB, which is an increase of 6.1 MB as compared to our baseline. The workbook file is a little less than 6 MB and accounts for most of the increase. At this point, our sample application has also extracted and parsed the list of worksheets contained within the workbook, as well as the shared string table. I haven't looked at that in detail, but for now I am satisfied to believe that this accounts for the remaining extra memory.
  3. At this point, we extracted the worksheet of interest from the workbook and uncompressed it into a javascript string. This made our heap snapshot increase by almost 34 MB. That is certainly a lot! However, the filesize of the worksheet document itself is 34,445 kB, so it seems everything is accounted for.
  4. The next heap snapshot was taken after parsing the worksheet and building a parse tree. The snapshot weighs 77.3 MB - an increase another 31 MB. Now, the sheet has 32,294 rows with 24 cells of data each, and most of the cells are unique decimal numbers, so it is a decent chunk of data. But even then, it still feels as if this is way too large.

    That said, things probably look worse than they really are. Our new parser is event based: the parse method accepts a configuration object that contains only a callback, which is called every time a new row is extracted from the sheet. For our sample application, the callback is only a very naive proof of concept. I suspect there are plenty opportunities to make the parse tree builder smarter and the parse tree smaller.
  5. The last heap snapshot was taken after the parse. At this point, the parse tree, the workbook object, and the XML string went out of scope. But we are still looking at a heap snapshot of more than 40 MB! This is bad news: we really should be back at something close to heap snapshot 1. So, there's about 34 MB unaccounted for.
In the screenshot, you can also see what's hogging the memory: in the top right pane, we find our XML document string, which indeed accounts for the retained 34 MB of memory. In the bottom right pane, we can see who's still referencing it: it's some property called parent of sliced string @15298471. And these are referenced twice in some array, which is referenced by something called regexp_last_match_info in the native context.

Memory Leak, Explained

Now, what I think we're looking at is the lastMatch property of the global built-in RegExp-object.

If you're not familiar with JavaScript regular expressions, it might be helpful to consider exactly how our parser uses them. We're using code like this:
function parse(){
  //regular expression to match a <row> start-tag.
  var regexp = /<row\s([^>]+)\s*>/g;

  var match, data, xml = "...this is our huge XML document, loaded into a JavaScript String...";

  match = regexp.exec(xml);
  if (match) {

    //...do something with matched substrings contained as array elements in match...
    data = match[1];
    ...etc...

  }
}
(Note that this is just an example of the concept - not literally the actual code)

The parse() function first assigns a literal regular expression to the regexp variable. Under the covers, this literal regular expression results in calling the built-in global RegExp constructor, instantiating a new RegExp instance. Then, the exec-method of the RegExp instance is called, passing the -huge- XML document string. The exec-method returns a object representing the result: if there was no match, null is returned; if there is a match an object is returned that contains information about the match(es).

If there was a match, the match object will look a lot like an overloaded array object, having the matched parts of the string argument as elements. The element at index 0 of the match object (match[0]) is the substring matching the entire regular expression, the element at index 1 is the substring that matches the first parenthesized capturing group, and so on.

Now, since the match variable is a local variable in our parse function, everything should be garbage collectible after the function ends, right?

Yes. But No.

About RegExp.lastMatch

As it turns out, when an instance of the RegExp object finds a match, then the corresponding match info object containing all the matching substrings is stored in the lastMatch property of the global built-in RegExp-object. So, even if our parse-method is out of scope, the last match made by some regular expression inside it is still dangling around, attached to the global RegExp object in its lastMatch property.

Substrings in V8

Now, if the the lastMatch-object is still around, then the substrings representing the matches are also still around. As it turns out, V8 implements these substrings as "slice" objects. From within the JavaScript environment, they act and behave like String objects, but internally, the V8 javascript engine implements them as objects that have a parent property to keep a reference to the original String object from which they are a substring, along with some indexes to indicate what part of the original string makes up the substring.

Now, if you think about it, this way of implementing substrings is actually pretty clever, since it allows V8 to do many string manipulations very efficiently, minimizing overhead and memory consumption due to copying parts of strings to and through. In my case, it just becomes an atrocious memory hog because of the RegExp object, that has decided to maintain a reference to the last match object (for whatever reason).

Other people have ran into issues due to V8's substring design as well, and a bug was filed here:

https://bugs.chromium.org/p/v8/issues/detail?id=2869

Solutions

My oldest son, David of 14 years old, came up with a pretty creative solution: what if we'd write our own substring implementation, overriding the native one? If this makes you cringe, just think of 30 MB memory leaks and crashing browsers: it puts things in perspective. If this still sounds crazy to you, you should realize that when he came up with this idea, we had been looking together at this issue for two hours already. And even though we felt we knew the substring issue was related, we still had no way to prove that this was actually the case. His idea was feasible and might possibly confirm our suscpicions, so we went ahead and did it, and attached our own implementations of substring and substr to the __proto__ object of our XML string to override only these methods of that string instance.

As was to be expected, our own substring implementations were way slower than the native ones, and the parse took about 25 times longer than before. However, it *did* solve the memory leak. This was a strong indication that we were on the right track.

Then, David suggested another solution: why don't we simply clear out the lastMatch property of the global built-in RegExp object? We tried to do this directly, simply by assignment:
RegExp.lastMatch = null;
Unfortunately, this does not work. Although it does not throw a runtime exception, the RegExp object is protected against this kind of assignment, and the property never gets overwritten. However, it is still possible to achieve what we want, simply by instantiating a new RegExp object, and then forcing a match against a known, short string. We can then wrap that in a utility function, so we can always call it after doing some serious regular expression matching on large strings:
function freeRegExp(){
  /\s*/g.exec("");
}
Here's the heap snapshot after applying this fix:

Summary

  • Globals are bad.
  • Side-effects are bad, in particular if the modifications are global.
  • V8's substring implementation may lead to unexpected memory leaks.
  • Chrome heap snapshots are a powerful tool to troubleshoot them.
  • After applying regular expressions to huge strings, always force a match against a small string to prevent memory leaks.
  • David Rocks! He truly impressed me with his troubleshooting skills and his knack for pragmatic, feasible solutions.

Thursday, September 22, 2016

SAP UI5: Internationalization for each view - Addendum for Nested Views

After writing my previous post on SAP UI5: Per-view Internationalization, I found out that the solution does not work completely as intended when using nested views.

If you're using nested views, each view would still have its own set of unique texts that are entirely specific to just that view, and for those cases, the solution as described still works. But there might also be a number of texts that are shared by both the outer and one or more of the inner views. It would make sense to be able to define those texts in the i18n model at the level of the outer view, and have the i18n models of the nested view pick up and enhance the i18n model of the outer view.

Problem: onInit() is not the right place to initialize the i18n model

The problem with the original solution is that the onInit() method of the nested views gets called before that of the outer view. It makes sense - the whole can be initialized only after its parts have been initialized. But this does mean that the onInit() method is not the right place to initialize the i18n model.

Please consider these lines from the _initI18n() method that I proposed to initialize the i18n model:

      //Use the bundledata to create or enhance the i18n model
      var i18nModel = this.getModel(i18n);
      if (i18nModel) {
        i18nModel.enhance(bundleData);
      }
      else {
        i18nModel = new ResourceModel(bundleData);
      }

      //set this i18n model.
      this.setModel(i18nModel, i18n);

Suppose this code runs as part of a nested view's onInit(). The call to getModel() will try to acquire the i18n model that is already set, or else the i18n model of the owner component. That's how the getModel() method in the base controller works (please see my previous blog post to review that code).

Now, at this point, no i18n model has been set for the view, and so the owner component's i18n model will be picked up. The i18n model of the outer view will however never be found, since the onInit() of the controller of the outer view has not been called yet (and therefore, its _initI18n() has not been called either).

Solution: Use onBeforeRendering() rather than onInit()

It turns out that this can be solved by calling the _initI18N() method in the onBeforeRendering() method rather than in the onInit() method. While nested views are initialized before initializaing the outer view, it's the other way around for the rendering process. This makes sense: as the outer view is being rendered, this requires rendering of its containing views. So the onBeforeRendering() method of the outer view will be called before the onBeforeRendering() method of its nested views. (It's the other way around for onAfterRendering(): outer views will be done rendering after its containing views are rendered).

Ensure i18n initialization occurs only once

There is one extra consideration in moving the i18n initialization from the onInit() to onBeforeRendering(). The reason is that views may go trough multiple rendering cycles, whereas the onInit() will only run once. If there are repeated rendering cycles, we do not want to reinitialize the i18n model, so we add a lock that ensures the i18n model is initialized only once:

    ...
    onInit: function(){
      this._initI18n();
    },
    onBeforeRendering: function(){
      this._initI18n();
    },
    _i18nInitialized: false,
    _initI18n: function(){
      if (this._i18nInitialized === true) {
        return;
      }
      var i18n = "i18n";

      //create bundle descriptor for this controllers i18n resource data
      var metadata = this.getMetadata();
      var nameParts = metadata.getName().split(".");
      nameParts.pop();
      nameParts.push(i18n);
      nameParts.push(i18n);
      var bundleData = {bundleName: nameParts.join(".")};

      //Use the bundledata to create or enhance the i18n model
      var i18nModel = this.getModel(i18n);
      if (i18nModel) {
        i18nModel.enhance(bundleData);
      }
      else {
        i18nModel = new ResourceModel(bundleData);
      }

      //set this i18n model.
      this.setModel(i18nModel, i18n);
      this._i18nInitialized = true;
    },
    ...

Overriding onBeforeRendering() in extensions of the base controller

And of course, when extending the base controller, you'll need to remember to call the onBeforeRendering() method of the ascendant when overriding the onBeforeRendering() method:

sap.ui.define([
  "just/bi/apps/components/basecontroller/BaseController"
], function(Controller){
  "use strict";
  var controller = Controller.extend("just.bi.apps.components.mainpanel.MainPanel", {
    onBeforeRendering: function(){
      Controller.prototype.onBeforeRenderingcall(this);
      ...
    }
  });
  return controller;
});

Finally

I hope you enjoyed this addendum. Feel free to share your insights if you think there is a better way to do handle i18n.

Sunday, September 18, 2016

SAP UI5: Per-view Internationalization

NOTE: There is an addendum to this blog post that suggests a number of improvements. You can check out the addendum here: SAP UI5: Internationalization for each view - Addendum for Nested Views.

Quite recently, I dove into SAP UI5 development. To educate myself, I followed a workshop and I used the Walkthrough.

During my explorations, I ran into a particular issue which I didn't see very readily addressed. I also found a solution for this particular issue, and even though I still have a ton to learn, I think it is worth sharing. So, here goes:

The Feature: Translatable texts and the i18n model

One of the SAP UI5 features highlighted in the Walkthrough is treatment of translatable texts. In the walkthrough this is realized by setting up a resource model, the i18n model.

The i18n model is sourced form i18n .properties files, which are essentially lists of key/value pairs, one per line, and separated by an equals sign:

# Each line is a key=value pair.
greetingAction=Say Hello
greeting=Hello {0}!

To actually setup a i18n model using these texts, you can explicitly instantiate a sap.ui.model.resource.ResourceModel:

sap.ui.define([
    "sap/ui/core/mvc/Controller",
    "sap/ui/model/resource/ResourceModel"
], function(Controller, ResourceModel){
    "use strict";
    return Controller.extend("my.app.App", {
        onInit: function(){
            var i18nModel = new ResourceModel({
                bundleName: "just.bi.apps.JustBiApp.i18n.i18n"
            });
            this.getView().setModel(i18nModel, "i18n");
        }
    });
});

Or, you can have your application instantiate the model by listing it in the models property of the sap.ui5 entry in the manifest.json application descriptor file:

"models": {
 "i18n": {
   "type": "sap.ui.model.resource.ResourceModel",
    "settings": {
      "bundleName": "just.bi.apps.JustBiApp.i18n.i18n"
    }
  }
}

In many cases, the text is required for the static labels of ui elements like input fields, menus and so on. Inside a view, static texts may be retrieved from the i18n model through special data binding syntax, like so:

<-- Button text will read "Say Hello" -->
<Button text="{i18n>greetingAction}"/>

Texts may also be retrieved programmatically inside controller code by calling the .getText() method on the resource bundle object. The resource bundle object is may be obtained from the i18n resource model with the getResourceBundle() getter method:

var bundle = this.getModel("i18n").getResourceBundle();
var text = bundle.getText("greeting", ["World"]);      // text has value "Hello, World!"

Now, the cool thing is that you can write a separate i18n .properties file for each locale that you want to support. The framework discovers which locale is required by the client and use that to find the best matching i18n files appropriate for the client's locale.

The file name is used to identify to which language and/or locale the texts inside the file apply. For example, you'd put the German texts in a i18n_de.properties file, and the English texts in a i18n_en.properties file, and if you want to distinguish between British and American English, you'd create both a i18n_en_GB.properties and i18n_en_US.properties file.

(I haven't found out to exactly which standard the sap ui i18n .properties files apply, but from what I've seen so far I think it's safe to assume that you can use the two-letter lowercase ISO 639-1 code for the language and the two-letter uppercase ISO 3166-1 code for the country)


The Problem: One i18n Model for entire application

Now, the walkthrough demonstrates the feature by adding one i18n model for the entire application so that it becomes available in any of the views that make up the application. I appreciate that the walkthrough is not the right place to cover all kinds of more advanced scenarios, so I can understand why it settles for just one application-wide i18n model.

However, I can't help but feeling this is not an ideal approach. Main reason is that it seems at odds with the fact that many texts are specific to just one particular view. This challenges both the development workflow as well as the reusability of our application components:


  • Each time you create or modify a particular view, you also have to edit the global i18n .properties files. To keep things manageable, you will probably invent some kind of view-specific prefix to prefix the keys pertaining to that view, and you'll probably end up creating a view-specific block in that i18n file. At some point, you'll end up with a lot of lines per i18n file, which is not so maintainable
  • Suppose you want to reuse a particular view in another application. Contrary to the practice used in the Walthrough, I like to keep view and associated Controller together, and in a folder separate from any other view and controller. This way I can easily copy, move or remove the things that belong together. Except that the texts, which also belong to that view/controller, are in the global i18n .properties file, and need to be managed separately.

The Solution: Keep per-view i18n files near view and controller code

The solution I found is to create a i18n subfolder beneath the folder that contains my Controller and View. Since I already keep each associated view and controller together, and separate from the other views and controllers, this approach makes sense: It's just one step further in keeping code and resources that depend directly on each other physically together.


So, this is what my file and folder structure looks like:

FolderStructure.png

So, the webapp folder is the root of the sap ui5 project. The components folder is where I keep subfolders for each functional unit (i.e. View+Controller+resources) of the application. In the picture, you see two such subfolders, basecontroller (more about that below) and mainpanel.

The mainpanel folder is the one that contains an actual component of my application - a MainPanel View, and its controller (in MainPanel.view.xml and MainPanel.controller.js respectively). Here we also find the i18n folder specific to this view, and inside are the i18n .properties files (one for each locale we need to support).

In order to load and apply the view-specific i18n .properties files, I'm using generic extension of sap.ui.core.mvc.Controller which loads the "local", view-specific i18n resource bundle. This extension is called BaseController and is in the basecontroller folder. Here's the code:

sap.ui.define([
  "sap/ui/core/mvc/Controller",
  "sap/ui/model/resource/ResourceModel"
], function(Controller, ResourceModel){
  "use strict";
  var controller = Controller.extend("just.bi.apps.components.basecontroller.BaseController", {
    onInit: function()
      this._initI18n();
    },
    _initI18n: function(){
      var i18n = "i18n";

      //create bundle descriptor for this controllers i18n resource data
      var metadata = this.getMetadata();
      var nameParts = metadata.getName().split(".");
      nameParts.pop();
      nameParts.push(i18n);
      nameParts.push(i18n);
      var bundleData = {bundleName: nameParts.join(".")};

      //Use the bundledata to create or enhance the i18n model
      var i18nModel = this.getModel(i18n);
      if (i18nModel) {
        i18nModel.enhance(bundleData);
      }
      else {
        i18nModel = new ResourceModel(bundleData);
      }

      //set this i18n model.
      this.setModel(i18nModel, i18n);
    },
    getModel: function(modelname){
      var view = this.getView();
      var model = view.getModel.apply(view, arguments);
      if (!model) {
        var ownerComponent = this.getOwnerComponent();
        if (ownerComponent) {
          model = ownerComponent.getModel(modelname);
        }
      }
      return model;
    },
    setModel: function(model, modelName){
      var view = this.getView();
      view.setModel.apply(view, arguments);
    },
  });
  return controller;
});

Note how the BaseController initializes the i18 model by calling the _init118n() method. In this method we extract the className of the this object from its metadata (using the .getName() getter on the metadata obtained using the .getMetadata() getter), and we pop off the unqualified classname to obtain its namespace. We then add the string "i18n" twice - once for the folder, and once for the files inside it. We use this to create the bundlename which we use to instantiate the actual ResourceModel.

Before setting that model to the controller's view, we check if there is already an i18n model set using getModel(). This is a utility method that gets the model from this controller's associated view, or of the component that "owns" the view and this controller.

If a i18n model is already available, we enhance that by calling the .enhance() method on it, rather than replacing it. This way, any texts defined at a higher level are still available in this controller and view. This gives us a functional i18n model, which we then set using setModel(), which simply calls setModel() on the view associated with this controller.

To actually use this BaseController, we extend it when creating a "real" controller:

sap.ui.define([
  "just/bi/apps/components/basecontroller/BaseController"
], function(Controller){
  "use strict";
  var controller = Controller.extend("just.bi.apps.components.mainpanel.MainPanel", {
    onInit: function(){
      Controller.prototype.onInit.call(this);
      ...
    }
  });
  return controller;
});

Note that if that real controller has its own onInit() method, we need to first call the onInit() method of BaseController, or rather, of whatever class we're extending. Fortunately, since we are extending it we already have a reference to it (in the snippet above, it's the Controller parameter injected into our definition), so we call its onInit() method via the prototype while using the controller that is currently being defined (this) as scope.

Finally

I hope you enjoyed this article! I hope it will be of use to you. If you have an alternative solution - quite possiby, a better one - then please feel free to leave a comment and point out your solution. I'm eager to hear and learn so don't hesitate to share your opinion and point of view.

ADDENDUM: Nested views

It turns out the approach described in this post does not work well when using nested views. Fortunately, a simple improvement of the ideas in this post solves that problem. The approach is described in my next blog post, SAP UI5: Internationalization for each view - Addendum for Nested Views.

Tuesday, December 29, 2015

jjsml: a Module Loader for the Nashorn JavaScript Shell

jjs is a JavaScript shell that ships with Oracle Java 1.8. I recently found myself in a situation where it seemed worth while to check it out, so I did. I do not want to use this post to elaborate too much on why I started looking at jjs, but I intend to write about that shortly. For now I just want to share a few observations, as well as a solution to a particular obstacle I encountered.

What is jjs?

Java 1.8 (both SDK and JRE) ships a new executable called jjs. This executable implements a command-line JavaScript shell - that is, a program that runs from the command line and which "speaks" JavaScript. It is based on Nashorn - a JavaScript engine written in Java and first released with Java 1.8.

Nashorn can be used to offer embedded JavaScript functionality in Java applications; jjs simply is such an application that happens to be desigend as shell.

Why do I think jjs is cool?

The concept of a JavaScript shell is not at all new. See this helpful page from Mozilla for a comprehensive list. The concept of a JavaScript engine written in Java is also not new: The Rhino engine has been shipping with Java since version 1.6.

Even so, I think jjs has got a couple of things going for it that makes it uniquely useful:
jjs is an executable shell
Even though Java shipped a javascript engine since Java 1.6, (the Rhino engine), you'd still have to get a shell program externally.
Ships with Java
This means it will be available literally everywhere. By "available everywhere" I don't just mean that it will be supported on many different operating systems - I mean that it will in fact be installed on many actual systems, and in many cases it will even be in the path so that you can simply run it with no extra configuration or setup. This is not the case for any other javascript shell.
Java Integration
jjs comes with extensions that make it really quite simple to instantiate and work with Java classes and objects (but of course, you get to do it using JavaScript syntax). This may not mean much if you're not familiar with the Java platform. But if you are it means you get to use tons and tons of high-level functionality basically for free, and you get to use it through an interface you are already familiar with. I'm sure other JavaScript shells allow you to create your own extensions so you can make external functionality scriptable, but then you'd still need to create such a module, and you'd need to invent the way how to bind that external functionality to shell built-ins. Because Java and JavaScript both support an objected-oriented language paradigm the integration is virtually seamless.
It's JavaScript!
To some, this may sound hardly as an argument in favor, but to me, it is. While Java is great in that it offers so much functionality, I just can't comfortably use it for quick and dirty programs. There are many reasons why this is so - very verbose and explicit syntax, compilation, static typing etc. I'm not saying these language features are categorically bad - just that they get in the way when you just want to make a small program real quick. I really think JavaScript helps to take a lot of that pain away.
Scripting extensions
In addition to offering JavaScript with Java language integration, jjs throws in a couple of features that are neither Java nor JavaScript: String Interpolation and Here document support. Together, these features make it very easy to use jjs for templating and text output generation. Again such features themselves are very far from unique. But in my opinion, they complement the Java/JavaScript language environment in a pretty significant way and greatly increase its ease of use.
So, in short, I'm not saying any particular feature is unique about jss. But I do think the particular combination of features make it a very interesting tool, especially for those that are used to Java and/or JavaScript and that have the need for ubiquitous and reliable shell scripting.

Quick example

The Nashorn Manual already provides pretty complete (but concise) documentation with regard to both the Java language integration and the typical shell-scripting features, so I won't elaborate too much on that. Instead, I just want to provide a really simple example to immediately give you an idea of how jjs works, and what it would be like to write scripts for it.

Here's my example script called "fibonacci.js":
//get the number of arguments passed at the command-line
var n = $ARG.length;
if (n === 0) {
  //if no arguments were passed, we can't calculate anything, so exit.
  print("Enter a space-separated list of integers to calculate their corresponding fibonacci numbers.");
  exit();
}

//a function to calculate the n-th number in the fibonacci sequence
function fibonacci(n){
  var i, fibPrev = 0, fibNext = 1;
  if (n === 1) return fibPrev;
  if (n === 2) return fibNext;
  for (i = 2; i < n; i++, fibNext = fibPrev + (fibPrev = fibNext));
  return fibNext;
}

var i, arg;

//process the arguments passed at the command line:
for (i = 0; i < n; i++) {
  arg = $ARG[i];

  //validate the argument. Is it a positive integer?
  if (!/^[1-9]\d*$/g.test(arg)) {

    //Not valid, skip this one and report.
    print(<<EOD
Skipping "${arg}": not a positive integer.
    EOD);
    continue;
  }

  //Calculate and print the fibonacci number.
  print(<<EOD
fibonacci(${arg}): ${fibonacci(parseInt(arg, 10))}
  EOD);
}
As you might have guessed the script calculates the fibonacci number corresponding to the sequence number(s) entered by the user on the command-line. While this may not be a very useful task, this example does illustrate the most important elements that are key to typical shell scripts:
  • Collect and validate command-line arguments passed by the user
  • Process the arguments - use them to do some work deemed useful
  • Print out information and results
Assuming that jjs is in the path, and fibonacci.js is in the current working directory, then we can execute it with this command:
$ jjs -scripting fibonacci.js
There are three parts to this command: jjs, the actual executable program, the -scripting option, and finally fibonacci.js, which is the path to our script file.

I think the executable and the script file parts are self-explanatory. The -scripting option may need some explanation: without this, jjs only supports a plain, standard javascript environment without any extensions that make it behave like a proper shell-scripting environment. Personally I think it's a bit annoying we have to explicitly pass it, but such is life. Just make sure you always pass it.

On *nix based systems, you can even make the script itself executable by prepending the code with a shebang, like so:
#!/usr/bin/jjs
When we run it, the output is:
Enter a space-separated list of integers to calculate their corresponding fibonacci numbers.
Which is not surprising, since we didn't actually provide any input arguments. So let's fix that:
$ jjs -scripting fibonacci.js -- 1 2 3 4 5 6
fibonacci(1): 0
fibonacci(2): 1
fibonacci(3): 1
fibonacci(4): 2
fibonacci(5): 3
fibonacci(6): 5
Note the -- delimiter in the command line. This is a special token that tells the jjs executable to treat anything that appears after the -- token as command line arguments targeted at the script. We will see in a bit how you can access those arguments programmatically from within your JavasSript code.

Now, it's not necessary to analyze every aspect of this script. Instead, let's just highlight the features that are specific to the jjs environment itself. In the code sample above, I marked up those elements that are specific to Nashorn/jjs in lovely fuchsia
  • We can use the built-in global $ARG property to refer to the arguments passed at the command line. $ARG is essentially an array that will contain any token appearing after the -- delimiter on the jjs command-line is an element. Since $ARG can be treated as an array, we can use its length property to see how many arguments we have, and we can use the array access operator (square braces) to get an element at a particular index.
  • We can use the built-in print() function to write to standard out.
  • We can call the built-in function exit() to terminate the jjs program. This will exit the shell, and return you to whatever program spawned jjs.
  • Here documents are strings delimited by <<EOD and EOD delimiters. At runtime, Here documents are simply javascript strings, but their syntaxis allows the string to span multiple lines, and to contain unescaped regular string literal delimiters (single and double quotes, " and '). This makes Here documents extremely useful for generating largish pieces of text.
  • Literal strings and here documents can contain ${<expression>} placeholders, and jjs will automatically substitute these with the value of the expression. Expressions can be simple variable names, but also more complex expressions, like function calls, or operations.

Next step: reusing existing functionality with load()

We already mentioned that the program does three distinct things (collect input, process input to create output, and print output). Obviously, these different tasks are related or else they wouldn't have been in the same script. But at the same time, we can acknowledge that the fibonacci() function that does the actual work of calculating numbers from the Finonacci sequence might be usable by other scripts, whereas collecting input and printing output (let's call it the user-interface) are quite specific for exactly this program.

The desire to separate these concerns into distinct scripts is only natural and will become stronger as programs grow bigger and more complex. So let's cut it up.

For now let's assume we only want to be able to reuse the fibonacci() function in other scripts. In order to do that we at least have to separate that in put it in a new script. Let's call that fibonacci.js, and let's store it in some central directory where we store all of our reusable scripts - say, scripts/fibonacci.js. Handling of both input and output can stay together in the same script for now - let's just call that fibonacci-ui.js.

So, in order to actually make this happen we can rename the orignal file to fibonacci-ui.js and create a new and empty fibonacci.js which we store in the scripts directory. We can then cut the code for the entire fiboncci() from fibonacci-ui.js and paste it into fibonacci.js.

Of course, the code in fibonacci-ui.js is now missing its definition of the fibonacci() function. But since it is still calling the function, we somehow need to import the function definition from scripts/fibonacci.js. To do that, the Nashorn scripting environment provides a built-in function called load().

The load() function takes a single string argument, which represents a file path or a URL that identifies a script. Load will evaluate the script immediately, and it returns the evaluation result. (It may be bit strange to think of the evaluation result of script, but this is simply the value of the last expression. It need not concern us right now since the fibonacci() function is global anyway - we can call it regardless of whether we have the evaluation result of scripts/fibonacci.js or not.)

So, putting it all together, we now have scripts/fibonacci.js:
//a function to calculate the n-th number in the fibonacci sequence
function fibonacci(n){
  var i, fibPrev = 0, fibNext = 1;
  if (n === 1) return fibPrev;
  if (n === 2) return fibNext;
  for (i = 2; i < n; i++, fibNext = fibPrev + (fibPrev = fibNext));
  return fibNext;
}
and fibonacci-ui.js:
//get the number of arguments passed at the command-line
var n = $ARG.length;
if (n === 0) {
  //if no arguments were passed, we can't calculate anything, so exit.
  print("Enter a space-separated list of integers to calculate their corresponding fibonacci numbers.");
  exit();
}

//acquire the fibonacci function
load("scripts/fibonacci.js");

var i, arg;

//process the arguments passed at the command line:
for (i = 0; i < n; i++) {
  arg = $ARG[i];

  //validate the argument. Is it a positive integer?
  if (!/^[1-9]\d*$/g.test(arg)) {

    //Not valid, skip this one and report.
    print(<<EOD
Skipping "${arg}": not a positive integer.
    EOD);
    continue;
  }

  //Calculate and print the fibonacci number.
  print(<<EOD
fibonacci(${arg}): ${fibonacci(parseInt(arg, 10))}
  EOD);
}
Assuming that jjs is in the path, and the directory where we stored fibonacci-ui.js is also the current working directory, we can now run it like this:
$ jjs -scripting fibonacci-ui.js -- 1 2 3 4 5 6
If all went well, we would get the same output as we got before.

The problem with load()

While it is cool that we can load external scripts with the built-in load() function, not all is well. We just ran our fibonacci-ui.js script while our current working directory was also the directory where our script resides. Suppose that, for some reason, our current working directory is the scripts directory - i.e. in a subdirectory of the directory where fibonacci-ui.js resides.

Obviously, we need to modify our command line to point to the right location of fibonacii-ui.js, like so:
$ jjs -scripting ../fibonacci-ui.js -- 1 2 3 4 5 6
But if we run this, we get an error message:
../fibonacci-ui.js:7 TypeError: Cannot load script from scripts/fibonacci.js
This tells us is that in our entry point script, ../fibonacci-ui.js, an error occurred at line 7. This is our call to load() and the complaint is that it cannot seem to find the external script file as it was passed to load, scripts/fibonacci.js.

So, it looks like load() resolves relative paths against the current working directory. This is a bit of a bummer since it poses a serious challenge to creating reusable, portable scripts. What I would find more intuitive is if load() would resolve relative paths against the directory of the current script (that is, the directory where the script that calls out to load() resides).

Alas, it does not so we have to find a solution.

UPDATE: @sundararajan_a kindly pointed me to a page in the Open JDK wiki which explains that there actually does exist a solution. Nashorn/jjs provides the built-ins __DIR__ and __FILE__ which hold the directory and file of the current script. There's also a __LINE__ built-in which holds the current linenumber in the script. So we can write load(__DIR__ + relative_path) to resolve a relative path against the directory of the current script.


Without any extra measures, I think there are only two possible "solutions":
  • Abstain from using relative paths - only pass absolute paths to load().
  • Write your entry point scripts with one fixed working directory in mind, and ensure that is the current working directory before running your script with jss.
Neither of these "solutions" should make you happy: requiring a fixed directory for all reusable scripts means our reusable scripts aren't portable. We can't just demand that the location of our reusable scripts are the same, regardless of platform. And even if we could, we would be unable to have multiple copies (say, one copy for active development, one for production purposes) of our reusable scripts on one system. So clearly this is solution is not without its own share of problems. Requiring a fixed working directory for our top-level entry point scripts is maybe a little bit better, but would require some external solution to ensure the correct working directory for our script.

Despite the possibility of using these workarounds, there is one particular scenario that I think just can't be solved - at least, not without a way to resolve relative paths against the location of the "current" script. Suppose you would create a script that is intended for reuse. But now suppose that this script itself relies on functionality from other reusable scripts. Either this script chooses to use absolute paths to acquire the scripts it depends upon, in which case the entire solution becomes unportable. Or this script would require whichever script that needs to use it to first set the current working directory so that correct loading of its dependencies is ensured.

No matter which way I look at it, load() puts us between a rock and a hard place.

A better load()?

Let's imagine for a moment we can write "a better load()" - that is, a function that works just like the built-in load(), but which resolves any relative paths against "the current script". This function would also need to have some sort of starting point - that is, it needs to know the current working directory. For now let's call this function a_better_load().

As it turns out, all the elements that we need to actually build a_better_load() are present in the jjs/Nashorn scripting environment. In pseudo code it would look something like this:
//only create the function if it doesn't already exist
if (!a_better_load) {

  //create a stack to keep track of the current working directory
  //$PWD is provided by jjs and contains the current working directory
  cwd = [$PWD];

  function a_better_load(path){

    //separate path in a directory and a file
    dir = getDir(path);
    file = getFile(path);

    if (path is absolute) {

      //path is absolute - push it unto the cwd stack so that any load requests 
      //that might occur inside the script we are now loading get resolved against 
      //the absolute path of this current script.
      cwd.push(dir)

    }
    else {
  
      //path is relative - take the path that is currently on top of the cwd stack,
      //and append the relative dir path
      //This should be the dir of the current script.
      cwd.peek() += dir

    }
 
    //use the built-in load to actually acquire the external script;
    ret = load(cwd.peek() + file);

    //after loading, we have to restore the state of the cwd stack

    if (path is absolute) {

      //the absolute path of the current script is on top of the stack.
      //remove it.
      cwd.pop()

    }
    else {
  
      //path is relative - take the path on top of the stack and remove
      //the part of the path that was added by the relative dir of the 
      //current script
      cwd.peek() -= dir

    }

    //return the evaluated script, just like load() would do.
    return ret;
  }

}

jjsml: A module loader for jjs

I actually implemented something like a_better_load() and then I started to think about the problem a bit more. Sure, a_better_load() sovles the script portability problem. But it adds a new global, and it would require all scripts to use this instead of plain, built-in load(). Alternatively, I could modify the script for a_better_load() a bit more and actually overwrite the built-in load(). But this would actually be worse in a way, since I would then need to distinguish between those scripts that know about this modified behavior of load() and those that, for some reason or other rely on the default behavior of load() (which would basically be any third party script).

I ended up creating a solution familiar from the browser world - a module loader like RequireJS. The solution is called jjsml and you can find it here on github: https://github.com/rpbouman/jjsutils/blob/master/src/jjsml/jjsml.js.

You might wonder what a module loader is, and why you'd need it - indeed, it may seem we already solved the problem by creating a better load(), why would we need to introduce a new concept?

I just identified a couple of problems by introducing a_better_load(). It seems self-evident to me that no matter what solution we end up with, new scripts would need to use it and become dependent upon it to actually benefit from it. This would even be the case if we'd overwrite the built-in load() function, which seems like a good argument to me to not do such a thing at all, ever, since a visible dependency is much better than a magical, invisible one.

So, if we're going to need to accept that we'd have to write our scripts to explicitly use this solution, then we'd better make sure the solution is attractive as possible, and offers some extra functionality that makes sense in the context of external script and dependency loading. I'm not sure if I succeeded, but check out the next section and let me know in the comments what you think.

Using jjsml

jjsml.js provides a single new global function called define(). The name and design was borrowed directly from RequireJS and it is called like that because it's purpose is to define a module. A module is simply some bag of related functionalities and it may take the form of an object, or a function. Instead of being a referenceable value itself, the module may even manifest itself simply by exposing new globals. Defining a module simply means creating it, and doing everything that presumes creating it, such as loading any dependencies and running any initialization code.

The define() function has the following signature:
<module> define([<scriptPath1> ,..., <scriptPathN>], <moduleConstructor>) 
  • <module> is a module - typically an object or a function that provides some functionality.
  • <scriptPath> is either a relative or an absolute path that points to a script. Ideally loading this script would itself return a module. Note that the square braces in the signature indicate that the argument is optional, and can be multiple - In other words, you can pass as many (or as little) of these as you like. Currently, define() does not handle an array of dependencies (but I should probably modify it so that it does. At least, RequireJS does it that way too.)
  • <moduleConstructor> is a module constructor - some thing that actually creates the module, and typically runs the code necessary to initialize the module.
While this describes it in a very generalized way, there are a few more things to it to get the most out of this design:
  • An important point to make is that the various <scriptPath>'s are guaranteed to be loaded prior to evaluating the <moduleConstructor>. The idea is that each <scriptPath> represents a dependency for the module that is being defined.
  • In many cases, the <moduleConstructor> is a callback function. If that is the case, then this callback will be called after all dependencies are loaded, and those dependencies would be passed to the callback function as arguments, in the same order that the dependencies were passed. Of course, to actually use the dependencies in this way, evaluating the <scriptPath> should result in a referenceable value. So this works best if the <scriptPath> are themselves proper modules. The immediate advantage of this design is that no module ever really needs to add any new globals: any functionality provided by a module is, in principle, managed in isolation from any functionalities provided by any other modules.
  • Proper modules are loaded only once, and are then cached. Subsequent references (typically, because another module tries to load it as a dependency) to an already loaded module will be served from the cache. This ensures that no time is wasted loading and running modules, or worse, to mess up module initialization.

Modular fibobacci example

This may sound a bit abstract so here's a concrete example, based on our earlier Fibonacci example. Let's first turn scripts/fibonacci.js into a proper module:
(function(){

  //a function to calculate the n-th number in the fibonacci sequence
  function fibonacci(n){
    var i, fibPrev = 0, fibNext = 1;
    if (n === 1) return fibPrev;
    if (n === 2) return fibNext;
    for (i = 2; i < n; i++, fibNext = fibPrev + (fibPrev = fibNext));
    return fibNext;
  }

  return fibonacci;

})();
Note that the script itself is an anonymous function, that is called immediately. The purpose of this construct is to establish a scope wherein we can create any private variables and functions - things only our script can see but which are not visible from the outside. The only interaction this script has with its surroundings is via its return value. In this case, the return value is simply the fibonacci() function itself. Also note that this script does not actually run any code, apart from defining the function. That's because this module does not require any initialization, and does not rely on any private data. It simply provides a pure function, and that's that.

To modify our fibonacci-ui.js example accordingly, we could simply change this line:
//acquire the fibonacci function
load("scripts/fibonacci.js");
to this:
//acquire the fibonacci function
var fibonacci = load("scripts/fibonacci.js");
This is a small but crucial difference: in the setup we had earlier, scripts/fibonacci.js would create a new fibonacci() function as a global. Since scripts/fibonacci.js is now a proper module, it returns the function rather than adding a new global itself. So in order to use the modularized fibonacci() function, we capture the result of our call to load(), and store it in a local fibonacci variable.

However, this change only has to do with the modular design of our modified scripts/finbonacci.js script. It still uses the old, built-in load() function, and is this not portable.

To actually benefit from define(), we should slightly rewrite the fibonacci-ui.js script in this way:
(function(){

  define(
    "scripts/fibonacci.js",
    function(fibonacci){
      //get the number of arguments passed at the command-line
      var n = $ARG.length;
      if (n === 0) {
        //if no arguments were passed, we can't calculate anything, so exit.
        print("Enter a space-separated list of integers to calculate their corresponding fibonacci numbers.");
        exit();
      }

      var i, arg;

      //process the arguments passed at the command line:
      for (i = 0; i < n; i++) {
        arg = $ARG[i];

        //validate the argument. Is it a positive integer?
        if (!/^[1-9]\d*$/g.test(arg)) {

          //Not valid, skip this one and report.
          print(<<EOD
Skipping "${arg}": not a positive integer.
          EOD);
          continue;
        }

        //Calculate and print the fibonacci number.
        print(<<EOD
fibonacci(${arg}): ${fibonacci(parseInt(arg, 10))}
        EOD);
      }
    }
  );

})();
Just like the modified scripts/fibonacci.js script, we wrapped the original code in an anonyumous function that is immediately called, thus keeping any variable and function definitions completely private and isolated from the global space. Inside that anonymous function, we have a single call to define(), passing the relative path to our reusable and modularized scripts/fibonacci.js script.

The last argument to define() is the module constructor. In this case, it is a callback function that will get called after the scripts/fibonacci.js dependency is loaded, and which is responsible for creating the actual program. The callback has a single argument, that directly corresponds to the dependency - when the callback is called, the fibonacci() function that was returned by the scripts/fibonacci.js script will be passed via this argument, and will this become available to the module constructor code.

Running scripts with jjsml

Suppose we acquired the jjsml.js script and stored it in the same directory as fibonacci-ui.js, then we can run the program using the following command line:
$ jjs -scripting -Djjsml.main.module=fibonacci-ui.js jjsml.js -- 1 2 3 4 5 6
You'll notice the same command line elements as we used before, plus one extra: -Djjsml.main.module=fibonacci-ui.js.

As you can see, in the command line, the actual script that jjs gets to run is jjsml.js, and not fibonacci-ui.js. Instead, fibonacci-ui.js is passed via the jjsml.main.module property of the java.lang.System object. You may recognize the -D prefix from other java programs: this is what you use to set a so-called system property, and this is what the jjsml.js script looks out for after attaching the define() function to the global object. If specified, the jjsml.js will attempt to load that as the initial script, i.e. the entry point of the shell scripted program.

Now, at this point, you may wonder - was all this really worth it? I would say it was, for the following reasons:
  • Modularization improved the quality of our scripts. Since they run in complete isolation there is no chance of undesired side effects
  • The fibonacci() function is now truly reusable, and any other script that may need it can order it as a dependency via a call to define(), and no matter how often it will be pulled in, it will be loaded exactly once
  • Last but not least, any relative paths used to identify dependencies will be resolved against the location of the script that pulls in the dependency, thus making all solutions completely portable
Arguably, our example was so trivially simple that we may not notice these benefits, but as you start to rely more on reusable scripts, and those scripts themselves start to depend on other scripts, you most surely will be happy that these things are managed for you jjsml.js.

Finally

I created jjsml.js not beacause of some theorethical principle, but because I really do need to write scripts that have dependencies, and I cannot afford to assume an absolute, fixed location for my scripts. You may have noticed that jjsml.js itself is part of a larger project called jjsutils. Inside this project are already a few reusable components (for example, for JDBC database access) as well as some top-level utilities. I plan to write more about jjsutils in the future.

In the mean while - let me know what you think! I really appreciate your comments, and you're free to check out and use both jjsml.js as well as the entire jjsutils project. There's API documentation, a few examples, and since the entire project is on github you can file issues or send me pull requests. Be my guest!

Wednesday, April 08, 2015

CSS tricks for (conditional) formatting of numbers and dates

Here's a bunch of CSS tricks that can help to format numbers and dates in HTML. You can even use it to achieve (basic) conditional formatting!

A Stackoverflow question: conditionally hiding zero values in a table

Today I stumbled upon this question on stackoverflow:
Is there a way to hide a data cell based on a specific value using just HTML/CSS? For example I have this code:
<table>

 <caption>Test</caption>

 <tr>
  <th>Values</th>
  <td>$100</td>
 </tr>

 <tr>
  <th>Initial value</th>
  <td>$0</td>
 </tr>

</table>
Is there a way to hide the cells that are equal to $0 using HTML/CSS only? Let's say instead of $0 I have a variable called fee that can be a variety of values: $0, $5, $20, etc. Is there a way to check what value it is and if it is found to be $0 can I then hide it?
As it turns out, this is actually possible with HTML5 data attributes, the CSS :before or :after pseudo-class, a CSS content property using a value of the type attr(), and attribute-value selector syntax to control conditional formatting:
<!doctype html>
<html>

 <head>

  <style type="text/css">
    
    /* make the cells output the value of their data-value attribute */
    td:after {
      content: attr(data-value);
    }
    
    /* hide the output if the data-value is equal to "$0" */
    td[data-value="$0"]:after {
      content: "";
    }

  </style>

 </head>

 <body>

  <table>

   <caption>Test</caption>

   <tr>
    <th>Values</th>
    <td data-value="$100"></td>
   </tr>

   <tr>
    <th>Initial value</th>
    <td data-value="$0"></td>
   </tr>

  </table>

 </body>

</html>
In summary, the ingredients of the solution are:
  • Encode the cell values as a custom data attribute, for example: data-value. The actual cells are empty.
  • Make the cell value show up using the :after pseudo-class of the td element. This is done by setting the CSS content property to the value attr(). Values of this type take an attribute name between the parenthesis, so in our example this becomes attr(data-value).
  • Use the attribute-value selector syntax for conditional formatting. In our example the requirement was to "hide" the value of cells with an amount equal to "$0". We can express this as td[data-value="$0"]. And since we display the value through the content property of the :after pseudo-class, we have to add :after to our td selector and specify a content property of "" to override the previous rule that outputs the value using attr().
The result looks something like this:

Values $100
Initial value


Browser compatibility

When I first tried to implement the idea I tested with latest chrome (41) and firefox (37) where it worked just fine. Much to my surprise and joy, it works without modification in IE8 as well! I'm so happy that I don't want to spoil it by testing other IE versions, but if anyone dares to try then I'd be grateful if you could post the result in the comments. Now personally, I'm not interested in hiding cell values. But this little trick does offer some possibilities for some basic conditional formatting.

Monetary amount formatting: red vs black

Consider a balance sheet of monetary amounts. Amounts should be right aligned, and we want the positive amounts to be displayed in black, and negative amounts in red:
<!doctype html>
<html>

 <head>

  <style type="text/css">
    
    /* right-align monetary amounts */
    td[data-monetary-amount] {
      text-align: right;
    }

    /* make the cells output their value */
    td[data-monetary-amount]:after {
      content: attr(data-monetary-amount);
    }

    /* make debit amounts show up in red */
    td[data-monetary-amount^="-"]:after {
      color: red;
    }
    
  </style>

 </head>

 <body>

  <table border="1">

   <tr>
    <th>Gain</th>
    <td data-monetary-amount="$100"></td>
   </tr>

   <tr>
    <th>Losst</th>
    <td data-monetary-amount="-$100"></td>
   </tr>

  </table>

 </body>

</html>
Note the data-monetary-amount^="-" syntax. This is a so-called substring matching attribute selector, which is specified in CSS 3. The comparison operator ^= tests whether the attribute value starts with a particular string, in this case the minus sign "-", which indicates we have a negative amount.

CSS 3 specifies similar comparison operators for a postfix match ($=) and an instring or "mid" match (*=).

The result looks something like this:

Gain $100
Loss -$100

Browser compatibility

As if I hadn't been blessed enough, this solution too works in IE8 (as well as Chrome and Firefox of course). Yay!

A slightly less nice solution that works in CSS 2.1

You can achieve the same effect with CSS 2.1 if you encode the value in 2 data attributes, one for the sign and one for the actual absolute amount:
<!doctype html>
<html>

 <head>

  <style type="text/css">

    /* right-align monetary amounts */
    td[data-monetary-amount] {
      text-align: right;
    }

    /* make the value show up */
    td[data-monetary-amount]:after {
      content: attr(data-monetary-amount);
    }

    /* make negative amounts show up in red, prefixed by the sign */
    td[data-sign="-"]:after {
      color: red;
      content: attr(data-sign) attr(data-monetary-amount);
    }

  </style>

 </head>

 <body>

  <table border="1">

   <tr>
    th>Debit</th>
    <td data-sign="+" data-monetary-amount="$100"></td>
   </tr>

   <tr>
    th>Credit</th>
    <td data-sign="-" data-monetary-amount="$100"></td>
   </tr>

  </table>

 </body>

</html>
An interesting bit of this last example is that it shows you can compose the value of the content property out of multiple pieces of content, in this case, two attr() values: attr(data-sign) to ensure that in case of negative values, we display the minus sign, and attr(data-value) to output the absolute value of the amount.

Locale dependent date formatting

The elements we saw in the previous example can be used for basic locale dependent date formatting. Let's keep it simple and format dates either in USA format, mon/d/yyyy, or in a format that is more easily understood outside the USA, d/mon/yyyy:
<!doctype html>
<html>

 <head>

  <style type="text/css">
      /* year comes last */
      time[datetime]:after {
        float: right;
        content: attr(datetime);
      }

      /* month and day come first */
      time[datetime*="-"] {
        float: left;
      }

      /* Months (non-USA) */
      time[datetime^="01-"]:after {
        content: "jan/";
      }

      ...rules for the other months go here...

      time[datetime^="12-"]:after {
        content: "dec/";
      }

      /* Days (non-USA) */
      time[datetime$="-01"]:before {
        content: "1/";
      }

      ...rules for the other days go here...

      time[datetime$="-31"]:before {
        content: "31/";
      }

      /* Months (USA) */
      *[lang="en-US"] time[datetime^="01-"]:before {
        content: "jan/";
      }

      ...rules for the other months go here...

      *[lang="en-US"] time[datetime^="12-"]:before {
        content: "dec/";
      }

      /* Days (USA) */
      *[lang="en-US"] time[datetime$="-01"]:after {
        content: "1/";
      }

      ...rules for the other days go here...

      *[lang="en-US"] time[datetime$="-31"]:after {
        content: "31/";
      }

  </style>

 </head>

 <body>

  <table border="1">

   <tr>
    <td lang="en-US">
     <time datetime="2015">
      <time datetime="04-08"/>
     </time>
    </td>
   </tr>

   <tr>
    <td lang="en-GB">
     <time datetime="2015">
      <time datetime="04-08"/>
     </time>
    </td>
   </tr>

  </table>

 </body>

</html>
This solution uses the HTML5 time-element. The time element can have a datetime attribute that contains the date/time in a machine readable format, and it may contain text content, which should be a human-readable representation of the date/time.

Now, personally, I do not think the HTML5 time element is an example of good or convenient design. At least, not from the perspective of the HTML5 author.

It is a great idea to require a machine-readable representation of the date. This potentially allows user agents to do useful things with the content. And allowing the user to manually specify the human-readable representation is also not a bad idea per se. But IMO, the time-element would have been much more useful if authors would be allowed to only specify the machine-readable representation of the date/time and, in absence of a manually entered human representation of the date/time, let the browser figure out how that date appears in the output in a human-readable representation. That way the browser could use information about the language of the document or document section to auto-format the date, or otherwise apply some user-preference. Another idea would be to allow the HTML author to control the output format using another attribute for a format string.

Anyway, this is not the case so we can try and see what we can do on our end. The solution above is as follows:
  • In the example above, a date is expressed using two time elements: one for the year-part and one for the month and day parts of the date. The year-part uses a non-negative integer for the datetime attribute, indicating a year. The mont/day-part uses a datetime attribute to represent a valid yearless date string. I nested the time element that represents the month and day part inside the one that represents the year. That said, it would have been much nicer if I could've just used a single time-element using a single datetime attribute containing all dateparts, but I couldn't figure out how to manipulate such a value with CSS. So I settled for a less optimal solution, which is certainly more verbose. At least, it does not duplicate any data, which seems a requirement that we never should let go off.
  • The first two CSS rules ensure that month and day appear first (using float:left) and the year appears last (using float: right). The first CSS rule specifies that all time elements having a datetime attribute should float right. The way we set it up, this matches the time elements that match the year part. The second CSS rule uses the substring-matching attribute selector *= to check if the datetime attribute of the time element contains a hyphen. Since the hyphen separates the day and month parts in the yearless date string format, this rule will match all time elements that represent a month/day part of a date.
  • The remaining rules are required for formatting the month and date parts as well as the separators. (Wich is a slash, /).
  • The prefix matching attribute selector ^= is used to test which month is identified by the prefix of the value of the datetime attribute. For each month, with prefixes 01 through 12, there is a rule, and its content property is used to output the month abbreviation like jan, feb, mar etc.
  • The postfix matching attribute selector $= is used to test which day is identified by the postfix of the value of the datetime attribute. For each day, with postfixes 01 through 31, there is a rule, and its content property is used to output the day number.
  • The upper set of rules matching the month-prefix and day-postfix are used to generate :after and :before pseudo-classes respectively to ensure that by default, the day part is displayed before the month part.
  • To accommodate the USA date format, the bottom set of rules was added. These are essentially a duplication of the prefix- and postfix matching rules for the month and day part respectively, but these rules have an initial selector part like this *[lang="en-US"] to ensure that these rules are active only if the time element is contained in a section that was marked as being localized for the USA. For these rules, the month parts are used to generate :before pseudo-classes, and the day parts are used to generate :after pseudo-classes, thus reversing the default order of displaying the month and day part.
The result looks something like this:

apr/8/2015
8/apr/2015

Browser compatibility

This solution works again fine in Chrome and Firefox, but does not render in IE8. Support for the time element was added in IE9, and the example works just fine there. Of course, if you really want it to work for IE8, you can, just don't use a time element but something generic such as span, and use a custom data- attribute for the datetime value, like data-datetime or similar.

Finally...

I hope this was useful information. Personally I think we still have a long way to go before we can use a pure css solution to solve all our data formatting problems, and I believe that esp. for web-applications, programmatic solutions (either on the server or on the client side) are still essential to deliver an acceptable result.

That said, every little bit of functionality in CSS can help you build a solution, even if such a solution is still controlled or generated by a programmatic backend.

Any comments and feedback are greatly appreciated.

DuckDb Performance: min, max, and median vs quantile

I was playing with some classical statistics in DuckDB and I ran into something I'd like to share. It's about the measures minimum,...