Related
I am trying to add text label to bar chart, but it not showing it. Here is a example i want to achieve
Here is code
{ "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "background": "#EFF1EF", "width": 500, "height": 26, "autosize":"pad", "data": { "values": [ { "standarts": { "divisions": [ { "a": { "mean": 135, "part1": 10, "part2": 60, "part5": 130,
"part7": 198, "part9": 255, "goal": { "value": 150 } } } ] } } ] }, "transform": [ {"calculate": "datum.standarts.divisions", "as": "D"}, {"flatten": ["D"]}, {"calculate": "datum.D.a", "as": "x"} ], "encoding": { "x": {"field": "x", "type": "quantitative","scale":{"domain":[0,300]},
"stack": null}, "opacity": {"value": 1} }, "layer": [ { "mark":{"type":"bar", "color" : "#b2b7b4", "cornerRadius": 40}, "encoding": {"x": {}} }, { "mark": {"type": "bar", "color": "#0ef9e5", "height": 25}, "encoding": {"x": {"field": "x.mean"}} }, { "mark":{"type":
"text", "align":"center"}, "encoding": {"text": {"field": "x.mean"}} }, { "mark":{"type": "rule"}, "encoding": {"x": {"field":"x.goal.value", "title":["Target"],"axis":{ "titleFont": "Google Sans", "titleFontSize": 16, "titleFontWeight":700, "titleY":
8} }}} ], "config": { "axis": {"ticks": false, "labels": false, "domain": false}, "rule": { "strokeWidth": 4, "strokeDash": [ 0.2, 8 ], "strokeCap": "round", "align":"center" } } }
this is code
And link to editor
vega-lite editor
text part is still not working.
I used documentation on vega-lite website and example codes, but still no success.
Thanks for the help.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"background": "#EFF1EF",
"width": 500,
"height": 26,
"autosize": "pad",
"data": {
"values": [
{
"standarts": {
"divisions": [
{
"a": {
"mean": 135,
"part1": 10,
"part2": 60,
"part5": 130,
"part7": 198,
"part9": 255,
"goal": {"value": 150}
}
}
]
}
}
]
},
"transform": [
{"calculate": "datum.standarts.divisions", "as": "D"},
{"flatten": ["D"]},
{"calculate": "datum.D.a", "as": "x"}
],
"encoding": {
"x": {
"field": "x",
"type": "quantitative",
"scale": {"domain": [0, 300]},
"stack": null
},
"opacity": {"value": 1}
},
"layer": [
{
"mark": {"type": "bar", "color": "#b2b7b4", "cornerRadius": 40},
"encoding": {"x": {}}
},
{
"mark": {"type": "bar", "color": "#0ef9e5", "height": 25},
"encoding": {"x": {"field": "x.mean"}}
},
{
"mark": {"type": "text", "align": "right", "dx": -10},
"encoding": {"text": {"field": "x.mean"}, "x": {"field": "x.mean"}}
},
{
"mark": {"type": "text", "align": "center", "dy": -30},
"encoding": {
"text": {"field": "x.goal.value"},
"x": {"field": "x.goal.value"}
}
},
{
"mark": {"type": "rule"},
"encoding": {
"x": {
"field": "x.goal.value",
"title": ["Target"],
"axis": {
"titleFont": "Google Sans",
"titleFontSize": 16,
"titleFontWeight": 700,
"titleY": 8
}
}
}
}
],
"config": {
"axis": {"ticks": false, "labels": false, "domain": false},
"rule": {
"strokeWidth": 4,
"strokeDash": [0.2, 8],
"strokeCap": "round",
"align": "center"
}
}
}
I am trying to create a VegaLite chart with labelled highlighted areas which are specified in a separate dataset using [min_x, max_x] coordinates.
I've managed to highlight the area itself using a rect mark, but I'm struggling to properly position the label at the top edge of the chart.
This is the end result I'm trying to achieve. In this example I'm using the dy property of the text mark to position the label. Unfortunately this only works when the chart height is known in advance, which doesn't work for my use case.
If there is a better way to achieve the result I want, please let me know. This is the Vegalite specification for the chart above, without previously mentioned dy property:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"datasets": {
"test_data": [
{"x": 0, "y": 1.5},
{"x": 5, "y": 2},
{"x": 9, "y": 4},
{"x": 14, "y": 0}
],
"highlight_data": [
{"from_x": 2.3, "to_x": 3, "label": "AAA"},
{"from_x": 6.3, "to_x": 8, "label": "BBB"}
]
},
"data": {"name": "test_data"},
"layer": [
{
"data": {"name": "highlight_data"},
"transform": [
{"calculate": "(datum.from_x + datum.to_x) / 2", "as": "mean_x"}
],
"layer": [
{
"mark": {"type": "rect", "opacity": 0.3},
"encoding": {
"x": {"field": "from_x", "type": "quantitative"},
"x2": {"field": "to_x"},
"color": {"value": "#fcfc00"}
}
},
{
"mark": {"type": "text"},
"encoding": {
"text": {"field": "label"},
"x": {"field": "mean_x", "type": "quantitative"}
}
}
]
},
{
"mark": {"type": "line"},
"encoding": {
"x": {"field": "x", "type": "quantitative", "title": "X Label"},
"y": {"field": "y", "type": "quantitative", "title": "Y Label"}
}
}
],
"title": "Title",
"width": 800,
"height": 500
}
You can reference height inside an expression to make it dynamic.
"dy": { "expr": "-height + (height/2) -10"}
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"datasets": {
"test_data": [
{"x": 0, "y": 1.5},
{"x": 5, "y": 2},
{"x": 9, "y": 4},
{"x": 14, "y": 0}
],
"highlight_data": [
{"from_x": 2.3, "to_x": 3, "label": "AAA"},
{"from_x": 6.3, "to_x": 8, "label": "BBB"}
]
},
"data": {"name": "test_data"},
"layer": [
{
"data": {"name": "highlight_data"},
"transform": [
{"calculate": "(datum.from_x + datum.to_x) / 2", "as": "mean_x"}
],
"layer": [
{
"mark": {"type": "rect", "opacity": 0.3},
"encoding": {
"x": {"field": "from_x", "type": "quantitative"},
"x2": {"field": "to_x"},
"color": {"value": "#fcfc00"}
}
},
{
"mark": {"type": "text", "dy": { "expr": "-height + (height/2) -10"}},
"encoding": {
"text": {"field": "label"},
"x": {"field": "mean_x", "type": "quantitative"}
}
}
]
},
{
"mark": {"type": "line"},
"encoding": {
"x": {"field": "x", "type": "quantitative", "title": "X Label"},
"y": {"field": "y", "type": "quantitative", "title": "Y Label"}
}
}
],
"title": "Title",
"width": 800,
"height": 500
}
I am working with Elasticsearch which provides the min, max, Q1, Q2 and Q3 data. All I have to do is to plot it in form of a box plot. Kibana as of now only supports vega-lite version 2.6.0 and vega 4.3.0.
Here is a complete sample I have made.
{
"$schema": "https://vega.github.io/schema/vega-lite/v2.json",
"width": 100,
"height": 200,
"padding": 10,
"data": {
"name": "sample",
"values": [
{
"task": "A",
"min" : 72.66500091552734,
"max" : 139.54299926757812,
"q1" : 98.68599700927734,
"q2" : 120.12850189208984,
"q3" : 121.82099914550781
},
{
"task": "B",
"min" : 71.66500091552734,
"max" : 159.54299926757812,
"q1" : 88.68599700927734,
"q2" : 110.12850189208984,
"q3" : 141.82099914550781
},
{
"task": "c",
"min" : 45.66500091552734,
"max" : 169.54299926757812,
"q1" : 88.68599700927734,
"q2" : 110.12850189208984,
"q3" : 141.82099914550781
}
]
},
"layer": [
{
"width": 5,
"encoding": {
"x": {"type": "ordinal","field": "task"},
"y": {"type": "quantitative","field": "min"},
"y2": {"type": "quantitative","field": "max"},
"color": {"value": "#2CB5E8"}
},
"mark": {
"type": "bar"
}
},
{
"width": 20,
"encoding": {
"x": {"type": "ordinal","field": "task"},
"y": {"type": "quantitative","field": "q1"},
"y2": {"type": "quantitative","field": "q3"},
"color": {"value": "#EB985E"}
},
"mark": "bar"
},
{
"encoding": {
"x": {"type": "ordinal","field": "task"},
"y": {"type": "quantitative","field": "q2"},
"color": {"value": "#090502"}
},
"mark": "point"
}
]
}
This is what the plot looks like:
But box plot look something like this
The current version of vega-lite does support the boxplot. But I am stuck with older version.
I am trying to reduce the width of the bar plot for min and max. And keep it thick for Q1 and Q3. Somehow it is not working.
Also is it possible to plot Q2 as a flat line instead of a point?
You can construct a boxplot manually using a layer chart with a bar, tick, and rule mark. For example (view in editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v2.json",
"width": 100,
"height": 200,
"data": {
"name": "sample",
"values": [
{
"task": "A",
"min": 72.66500091552734,
"max": 139.54299926757812,
"q1": 98.68599700927734,
"q2": 120.12850189208984,
"q3": 121.82099914550781
},
{
"task": "B",
"min": 71.66500091552734,
"max": 159.54299926757812,
"q1": 88.68599700927734,
"q2": 110.12850189208984,
"q3": 141.8209991455078
},
{
"task": "c",
"min": 45.66500091552734,
"max": 169.54299926757812,
"q1": 88.68599700927734,
"q2": 110.12850189208984,
"q3": 141.8209991455078
}
]
},
"layer": [
{
"encoding": {
"x": {"type": "ordinal", "field": "task"},
"y": {"type": "quantitative", "field": "min"},
"y2": {"type": "quantitative", "field": "max"}
},
"mark": {"type": "rule", "color": "black"}
},
{
"encoding": {
"x": {"type": "ordinal", "field": "task"},
"y": {"type": "quantitative", "field": "q1"},
"y2": {"type": "quantitative", "field": "q3"}
},
"mark": {"type": "bar", "color": "#EB985E", "size": 20}
},
{
"encoding": {
"x": {"type": "ordinal", "field": "task"},
"y": {"type": "quantitative", "field": "q2"}
},
"mark": {"type": "tick", "color": "gray", "size": 20}
}
]
}
I would like to parse JSON data using jq and curl from command line but I haven't been successful. In fact, I would like to get the value of response > textAnnotations > description but i'm doing something wrong. Here is my command :
curl -X POST > response.txt \
-H "Content-Type: application/json; charset=utf-8" \
--data "{
'requests': [
{
'image': {
'source': {
'imageUri': 'http://adn-cdn2.avadeo.net/articles/vignettes/grandes/146.jpg'
}
},
'features': [
{
'type': 'TEXT_DETECTION'
}
]
}
]
}" "https://vision.googleapis.com/v1/images:annotate?key=XXXXXXXXXXXXXXXXXXX" | jq -r '.responses.textAnnotations.description'
And here is the Curl answer if I do not filter with JQ :
{
"responses": [
{
"textAnnotations": [
{
"locale": "und",
"description": "24\nmois\n12\nmois\n",
"boundingPoly": {
"vertices": [
{
"x": 12,
"y": 24
},
{
"x": 285,
"y": 24
},
{
"x": 285,
"y": 206
},
{
"x": 12,
"y": 206
}
]
}
},
{
"description": "24",
"boundingPoly": {
"vertices": [
{
"x": 216,
"y": 24
},
{
"x": 285,
"y": 24
},
{
"x": 285,
"y": 83
},
{
"x": 216,
"y": 83
}
]
}
},
{
"description": "mois",
"boundingPoly": {
"vertices": [
{
"x": 223,
"y": 83
},
{
"x": 280,
"y": 84
},
{
"x": 280,
"y": 110
},
{
"x": 223,
"y": 109
}
]
}
},
{
"description": "12",
"boundingPoly": {
"vertices": [
{
"x": 12,
"y": 122
},
{
"x": 81,
"y": 122
},
{
"x": 81,
"y": 179
},
{
"x": 12,
"y": 179
}
]
}
},
{
"description": "mois",
"boundingPoly": {
"vertices": [
{
"x": 19,
"y": 177
},
{
"x": 76,
"y": 176
},
{
"x": 76,
"y": 205
},
{
"x": 19,
"y": 206
}
]
}
}
],
"fullTextAnnotation": {
"pages": [
{
"width": 300,
"height": 225,
"blocks": [
{
"boundingBox": {
"vertices": [
{
"x": 216,
"y": 24
},
{
"x": 285,
"y": 24
},
{
"x": 285,
"y": 83
},
{
"x": 216,
"y": 83
}
]
},
"paragraphs": [
{
"boundingBox": {
"vertices": [
{
"x": 216,
"y": 24
},
{
"x": 285,
"y": 24
},
{
"x": 285,
"y": 83
},
{
"x": 216,
"y": 83
}
]
},
"words": [
{
"boundingBox": {
"vertices": [
{
"x": 216,
"y": 24
},
{
"x": 285,
"y": 24
},
{
"x": 285,
"y": 83
},
{
"x": 216,
"y": 83
}
]
},
"symbols": [
{
"boundingBox": {
"vertices": [
{
"x": 216,
"y": 25
},
{
"x": 248,
"y": 25
},
{
"x": 248,
"y": 76
},
{
"x": 216,
"y": 76
}
]
},
"text": "2"
},
{
"property": {
"detectedBreak": {
"type": "EOL_SURE_SPACE"
}
},
"boundingBox": {
"vertices": [
{
"x": 255,
"y": 24
},
{
"x": 285,
"y": 24
},
{
"x": 285,
"y": 83
},
{
"x": 255,
"y": 83
}
]
},
"text": "4"
}
]
}
]
}
],
"blockType": "TEXT"
},
{
"boundingBox": {
"vertices": [
{
"x": 223,
"y": 83
},
{
"x": 280,
"y": 84
},
{
"x": 280,
"y": 110
},
{
"x": 223,
"y": 109
}
]
},
"paragraphs": [
{
"boundingBox": {
"vertices": [
{
"x": 223,
"y": 83
},
{
"x": 280,
"y": 84
},
{
"x": 280,
"y": 110
},
{
"x": 223,
"y": 109
}
]
},
"words": [
{
"boundingBox": {
"vertices": [
{
"x": 223,
"y": 83
},
{
"x": 280,
"y": 84
},
{
"x": 280,
"y": 110
},
{
"x": 223,
"y": 109
}
]
},
"symbols": [
{
"boundingBox": {
"vertices": [
{
"x": 223,
"y": 89
},
{
"x": 242,
"y": 89
},
{
"x": 242,
"y": 108
},
{
"x": 223,
"y": 108
}
]
},
"text": "m"
},
{
"boundingBox": {
"vertices": [
{
"x": 246,
"y": 88
},
{
"x": 259,
"y": 88
},
{
"x": 259,
"y": 108
},
{
"x": 246,
"y": 108
}
]
},
"text": "o"
},
{
"boundingBox": {
"vertices": [
{
"x": 262,
"y": 83
},
{
"x": 264,
"y": 83
},
{
"x": 264,
"y": 109
},
{
"x": 262,
"y": 109
}
]
},
"text": "i"
},
{
"property": {
"detectedBreak": {
"type": "EOL_SURE_SPACE"
}
},
"boundingBox": {
"vertices": [
{
"x": 269,
"y": 89
},
{
"x": 280,
"y": 89
},
{
"x": 280,
"y": 108
},
{
"x": 269,
"y": 108
}
]
},
"text": "s"
}
]
}
]
}
],
"blockType": "TEXT"
},
{
"boundingBox": {
"vertices": [
{
"x": 12,
"y": 122
},
{
"x": 81,
"y": 122
},
{
"x": 82,
"y": 206
},
{
"x": 13,
"y": 206
}
]
},
"paragraphs": [
{
"boundingBox": {
"vertices": [
{
"x": 12,
"y": 122
},
{
"x": 81,
"y": 122
},
{
"x": 82,
"y": 206
},
{
"x": 13,
"y": 206
}
]
},
"words": [
{
"boundingBox": {
"vertices": [
{
"x": 12,
"y": 122
},
{
"x": 81,
"y": 122
},
{
"x": 81,
"y": 179
},
{
"x": 12,
"y": 179
}
]
},
"symbols": [
{
"boundingBox": {
"vertices": [
{
"x": 12,
"y": 122
},
{
"x": 43,
"y": 122
},
{
"x": 43,
"y": 175
},
{
"x": 12,
"y": 175
}
]
},
"text": "1"
},
{
"property": {
"detectedBreak": {
"type": "EOL_SURE_SPACE"
}
},
"boundingBox": {
"vertices": [
{
"x": 50,
"y": 122
},
{
"x": 81,
"y": 122
},
{
"x": 81,
"y": 179
},
{
"x": 50,
"y": 179
}
]
},
"text": "2"
}
]
},
{
"boundingBox": {
"vertices": [
{
"x": 19,
"y": 177
},
{
"x": 76,
"y": 176
},
{
"x": 76,
"y": 205
},
{
"x": 19,
"y": 206
}
]
},
"symbols": [
{
"boundingBox": {
"vertices": [
{
"x": 19,
"y": 186
},
{
"x": 38,
"y": 186
},
{
"x": 38,
"y": 205
},
{
"x": 19,
"y": 205
}
]
},
"text": "m"
},
{
"boundingBox": {
"vertices": [
{
"x": 42,
"y": 186
},
{
"x": 55,
"y": 186
},
{
"x": 55,
"y": 206
},
{
"x": 42,
"y": 206
}
]
},
"text": "o"
},
{
"boundingBox": {
"vertices": [
{
"x": 58,
"y": 177
},
{
"x": 60,
"y": 177
},
{
"x": 60,
"y": 205
},
{
"x": 58,
"y": 205
}
]
},
"text": "i"
},
{
"property": {
"detectedBreak": {
"type": "EOL_SURE_SPACE"
}
},
"boundingBox": {
"vertices": [
{
"x": 65,
"y": 186
},
{
"x": 76,
"y": 186
},
{
"x": 76,
"y": 205
},
{
"x": 65,
"y": 205
}
]
},
"text": "s"
}
]
}
]
}
],
"blockType": "TEXT"
}
]
}
],
"text": "24\nmois\n12\nmois\n"
}
}
]
}
Can you please help me ?
Thank you all :)
Both responses and textAnnotations are arrays, so as far as i remember, you have to either loop through them, or access the first response element's first textAnnotation like so: responses[0].textAnnotations[0].description
I suggest looping if possible.
If you want all the descriptions under .responses[].textAnnotations you could write:
.responses[].textAnnotations[].description
which is short for:
.responses[] | .textAnnotations[] |.description
which is effectively a "for" loop within a "for" loop.
Today I read that Rovio released Angry birds for Chrome i.e HTML5 compatible. Does it mean that anyone can see the source code of the HTML5 version of the game now?
Yes, but it's not very readable as it looks to be generated from a Java input, probably via GWT.
The levels are stored as JSON – here's the level 2 file:
{
"camera": [
{
"bottom": -51.69,
"id": "Slingshot",
"left": -28.397,
"right": 47.013,
"top": -51.69,
"x": 28.621,
"y": -13.985
},
{
"bottom": -49.048,
"id": "Castle",
"left": 12.344,
"right": 82.582,
"top": -49.048,
"x": 66.776,
"y": -13.929
}
],
"counts": {
"birds": 5,
"blocks": 27
},
"id": "pack1/Level57.lua",
"scoreEagle": 29000,
"scoreGold": 60000,
"scoreSilver": 47000,
"theme": "BACKGROUND_BLUE_GRASS",
"world": {
"bird_1": {
"angle": 0,
"id": "BIRD_RED",
"x": 9.93,
"y": -4.328
},
"bird_2": {
"angle": 0,
"id": "BIRD_RED",
"x": 7.489,
"y": -4.339
},
"bird_3": {
"angle": 0,
"id": "BIRD_RED",
"x": 5.417,
"y": -4.249
},
"bird_4": {
"angle": 0,
"id": "BIRD_RED",
"x": 3.42,
"y": -4.339
},
"bird_5": {
"angle": 0,
"id": "BIRD_RED",
"x": 0,
"y": -1.035
},
"block_1": {
"angle": 90.027,
"id": "STONE_BLOCK_4X1",
"x": 61.498,
"y": -7.314
},
"block_10": {
"angle": 180,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 74.143,
"y": -0.157
},
"block_11": {
"angle": 180,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 83.499,
"y": -0.107
},
"block_12": {
"angle": 180,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 92.925,
"y": -0.058
},
"block_13": {
"angle": 0,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 7.156,
"y": 1.484
},
"block_14": {
"angle": 135,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 111.252,
"y": -18.195
},
"block_15": {
"angle": 24.537,
"id": "TERRAIN_TEXTURED_HILLS_5X5",
"x": 3.616,
"y": -0.22
},
"block_16": {
"angle": 45,
"id": "TERRAIN_TEXTURED_HILLS_5X5",
"x": 11.912,
"y": -0.041
},
"block_17": {
"angle": 45,
"id": "TERRAIN_TEXTURED_HILLS_5X5",
"x": 103.199,
"y": -0.037
},
"block_18": {
"angle": 45,
"id": "TERRAIN_TEXTURED_HILLS_5X5",
"x": 106.374,
"y": -3.514
},
"block_19": {
"angle": 45,
"id": "TERRAIN_TEXTURED_HILLS_5X5",
"x": 109.7,
"y": -0.188
},
"block_2": {
"angle": 89.999,
"id": "STONE_BLOCK_4X1",
"x": 68.165,
"y": -7.317
},
"block_20": {
"angle": 359.713,
"id": "PIG_BASIC_SMALL",
"x": 85.85,
"y": -15.34
},
"block_21": {
"angle": 2.262,
"id": "PIG_BASIC_SMALL",
"x": 75.084,
"y": -11.419
},
"block_22": {
"angle": 7.16,
"id": "PIG_BASIC_SMALL",
"x": 68.143,
"y": -11.427
},
"block_23": {
"angle": 0.153,
"id": "PIG_BASIC_SMALL",
"x": 61.475,
"y": -11.411
},
"block_24": {
"angle": 179.984,
"id": "WOOD_BLOCK_4X1",
"x": 85.911,
"y": -13.755
},
"block_25": {
"angle": 180.065,
"id": "WOOD_BLOCK_4X1",
"x": 75.051,
"y": -9.834
},
"block_26": {
"angle": 180.172,
"id": "WOOD_BLOCK_4X1",
"x": 68.284,
"y": -9.842
},
"block_27": {
"angle": 0.112,
"id": "WOOD_BLOCK_4X1",
"x": 61.463,
"y": -9.83
},
"block_3": {
"angle": 90.017,
"id": "STONE_BLOCK_4X1",
"x": 74.983,
"y": -7.316
},
"block_4": {
"angle": 270,
"id": "STONE_BLOCK_8X1",
"x": 85.892,
"y": -9.272
},
"block_5": {
"angle": 359.999,
"id": "TERRAIN_TEXTURED_HILLS_32X2",
"x": 75.877,
"y": -4.433
},
"block_6": {
"angle": 225.001,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 98.165,
"y": -5.15
},
"block_7": {
"angle": 225.001,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 104.615,
"y": -11.599
},
"block_8": {
"angle": 90,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 64.836,
"y": -0.135
},
"block_9": {
"angle": 135,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 60.034,
"y": 1.675
}
}
}
This means that you could potentially inject your own levels by intercepting the requests.
Yes, but it is heavily obfuscated, see small part of code below:
function d3(){this.b=new Date}
function MK(){this.o=EU.d.Nc()}
function TE(b,c){b.i.k=c;b.f=4}
function PU(b,c,d){b.f=c;b.g=d}
function YF(b){b.f=6;b.b=false}
function YH(b){b.f=6;b.b=false}
function iG(b){b.f=7;b.b=false}
They use the google PlayN framework for the HTML5 port.
See https://developers.google.com/playn/
It means you can see the HTML5 code, but it will not be very useful since it's compiled with GWT and not very understandable.