e2b8f5dc9ae4

Just Use Make™
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Sun, 28 Feb 2016 11:51:50 +0000
parents 37c769f2a211
children 1f29d302c82d
branches/tags (none)
files Makefile content/blog/2016/02/midpoint-displacement.html fabfile.py media/js/terrain1.js media/js/terrain1.wisp media/js/wisp/terrain1.js media/js/wisp/terrain1.wisp requirements.txt settings.py

Changes

--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Sun Feb 28 11:51:50 2016 +0000
@@ -0,0 +1,26 @@
+.PHONY: all clean generate regen serve deploy
+
+wisps := $(shell ffind --literal '.wisp')
+javascripts := $(subst .wisp,.js,$(wisps))
+
+all: media/js/terrain1.js
+
+media/js/wisp/%.js: media/js/wisp/%.wisp
+	cat $< | wisp > $@
+
+media/js/terrain1.js: $(javascripts)
+	browserify media/js/wisp/terrain1.js -o $@
+
+clean:
+	rm -rf ./deploy
+
+generate: all
+	hyde -g -s .
+
+serve:
+	hyde -w -s . -k
+
+regen: clean generate
+
+deploy: generate
+	rsync -avz ./deploy/ sl:/var/www/stevelosh.com
--- a/content/blog/2016/02/midpoint-displacement.html	Fri Feb 19 19:48:12 2016 +0000
+++ b/content/blog/2016/02/midpoint-displacement.html	Sun Feb 28 11:51:50 2016 +0000
@@ -13,10 +13,6 @@
         <script data-cfasync="false" src="/media/js/TrackballControls.js"></script>
 
         <script data-cfasync="false" src="/media/js/terrain1.js"></script>
-
-        <script type="text/javascript">
-            $(function () { run(); });
-        </script>
     {% endblock extra_js %}
 
     {% block article %}
--- a/fabfile.py	Fri Feb 19 19:48:12 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-from fabric.api import *
-import os
-import fabric.contrib.project as project
-
-PROD = 'sl'
-DEST_PATH = '/var/www/stevelosh.com/'
-ROOT_PATH = os.path.abspath(os.path.dirname(__file__))
-DEPLOY_PATH = os.path.join(ROOT_PATH, 'deploy')
-
-def clean():
-    local('rm -rf ./deploy')
-
-def generate():
-    local('hyde -g -s .')
-
-def regen():
-    clean()
-    generate()
-
-def serve():
-    local('hyde -w -s . -k')
-
-def reserve():
-    regen()
-    serve()
-
-def smush():
-    local('smusher ./media/images')
-
-@hosts(PROD)
-def publish():
-    regen()
-    project.rsync_project(
-        remote_dir=DEST_PATH,
-        local_dir=DEPLOY_PATH.rstrip('/') + '/',
-        delete=True
-    )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/media/js/terrain1.js	Sun Feb 28 11:51:50 2016 +0000
@@ -0,0 +1,523 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+var width = exports.width = 610;
+var height = exports.height = 400;
+var wireframe = exports.wireframe = true;
+var wireframeWidth = exports.wireframeWidth = 1.2;
+var terrainHeight = exports.terrainHeight = 50;
+var terrainSize = exports.terrainSize = 100;
+void 0;
+void 0;
+void 0;
+void 0;
+void 0;
+void 0;
+var l = exports.l = function l(v) {
+    return console.log(v);
+};
+var midpoint = exports.midpoint = function midpoint(a, b) {
+    return (a + b) / 2;
+};
+var average2 = exports.average2 = function average2(a, b) {
+    return (a + b) / 2;
+};
+var average4 = exports.average4 = function average4(a, b, c, d) {
+    return (a + b + c + d) / 4;
+};
+var safeAverage = exports.safeAverage = function safeAverage(a, b, c, d) {
+    return function () {
+        var totalø1 = 0;
+        var countø1 = 0;
+        a ? (function () {
+            totalø1 = totalø1 + a;
+            return countø1 = countø1 + 1;
+        })() : void 0;
+        b ? (function () {
+            totalø1 = totalø1 + b;
+            return countø1 = countø1 + 1;
+        })() : void 0;
+        c ? (function () {
+            totalø1 = totalø1 + c;
+            return countø1 = countø1 + 1;
+        })() : void 0;
+        d ? (function () {
+            totalø1 = totalø1 + d;
+            return countø1 = countø1 + 1;
+        })() : void 0;
+        return totalø1 / countø1;
+    }.call(this);
+};
+var rand = exports.rand = function rand() {
+    return Math.random();
+};
+var randAroundZero = exports.randAroundZero = function randAroundZero(spread) {
+    return spread * rand() * 2 - spread;
+};
+var jitter = exports.jitter = function jitter(value, spread) {
+    return value + randAroundZero(spread);
+};
+void 0;
+var heightmapGetSafe = exports.heightmapGetSafe = function heightmapGetSafe(hm, x, y) {
+    return 0 <= x && x <= hm.last && (0 <= y && y <= hm.last) ? (function () {
+        return hm[y * hm.resolution + x];
+    })() : void 0;
+};
+void 0;
+var normalize = exports.normalize = function normalize(hm) {
+    return function () {
+        var maxø1 = 0 - Infinity;
+        var minø1 = Infinity;
+        (function () {
+            var G__1ø1 = hm.length;
+            return function loop() {
+                var recur = loop;
+                var iø1 = 0;
+                do {
+                    recur = iø1 < G__1ø1 ? (function () {
+                        (function () {
+                            var elø1 = hm[iø1];
+                            maxø1 < elø1 ? (function () {
+                                return maxø1 = elø1;
+                            })() : void 0;
+                            return minø1 > elø1 ? (function () {
+                                return minø1 = elø1;
+                            })() : void 0;
+                        }.call(this));
+                        return loop[0] = 1 + iø1, loop;
+                    })() : void 0;
+                } while (iø1 = loop[0], recur === loop);
+                return recur;
+            }.call(this);
+        }.call(this));
+        return function () {
+            var spanø1 = maxø1 - minø1;
+            return function () {
+                var G__2ø1 = hm.length;
+                return function loop() {
+                    var recur = loop;
+                    var iø1 = 0;
+                    do {
+                        recur = iø1 < G__2ø1 ? (function () {
+                            hm[iø1] = (hm[iø1] - minø1) / spanø1;
+                            return loop[0] = 1 + iø1, loop;
+                        })() : void 0;
+                    } while (iø1 = loop[0], recur === loop);
+                    return recur;
+                }.call(this);
+            }.call(this);
+        }.call(this);
+    }.call(this);
+};
+var zeroHeightmap = exports.zeroHeightmap = function zeroHeightmap(heightmap) {
+    (function () {
+        var G__3ø1 = heightmap.length;
+        return function loop() {
+            var recur = loop;
+            var iø1 = 0;
+            do {
+                recur = iø1 < G__3ø1 ? (function () {
+                    heightmap[iø1] = 0;
+                    return loop[0] = 1 + iø1, loop;
+                })() : void 0;
+            } while (iø1 = loop[0], recur === loop);
+            return recur;
+        }.call(this);
+    }.call(this));
+    return heightmap;
+};
+var makeHeightmap = exports.makeHeightmap = function makeHeightmap(exponent) {
+    return function () {
+        var resolutionø1 = 1 + Math.pow(2, exponent);
+        l('Creating ' + resolutionø1 + ' by ' + resolutionø1 + ' heightmap...');
+        var heightmap = new Array(resolutionø1 * resolutionø1);
+        heightmap.resolution = resolutionø1;
+        heightmap.exponent = exponent;
+        heightmap.last = resolutionø1 - 1;
+        return zeroHeightmap(heightmap);
+    }.call(this);
+};
+var randomNoise = exports.randomNoise = function randomNoise(heightmap) {
+    return function () {
+        var G__4ø1 = heightmap.length;
+        return function loop() {
+            var recur = loop;
+            var iø1 = 0;
+            do {
+                recur = iø1 < G__4ø1 ? (function () {
+                    heightmap[iø1] = rand();
+                    return loop[0] = 1 + iø1, loop;
+                })() : void 0;
+            } while (iø1 = loop[0], recur === loop);
+            return recur;
+        }.call(this);
+    }.call(this);
+};
+var mpdInitCorners = exports.mpdInitCorners = function mpdInitCorners(heightmap) {
+    heightmap[0 * heightmap.resolution + 0] = rand();
+    heightmap[heightmap.last * heightmap.resolution + 0] = rand();
+    heightmap[0 * heightmap.resolution + heightmap.last] = rand();
+    return heightmap[heightmap.last * heightmap.resolution + heightmap.last] = rand();
+};
+var mpdDisplace = exports.mpdDisplace = function mpdDisplace(heightmap, lx, rx, by, ty, spread) {
+    return function () {
+        var cxø1 = midpoint(lx, rx);
+        var cyø1 = midpoint(by, ty);
+        var bottomLeftø1 = heightmap[by * heightmap.resolution + lx];
+        var bottomRightø1 = heightmap[by * heightmap.resolution + rx];
+        var topLeftø1 = heightmap[ty * heightmap.resolution + lx];
+        var topRightø1 = heightmap[ty * heightmap.resolution + rx];
+        var topø1 = average2(topLeftø1, topRightø1);
+        var leftø1 = average2(bottomLeftø1, topLeftø1);
+        var bottomø1 = average2(bottomLeftø1, bottomRightø1);
+        var rightø1 = average2(bottomRightø1, topRightø1);
+        var centerø1 = average4(topø1, leftø1, bottomø1, rightø1);
+        heightmap[by * heightmap.resolution + cxø1] = jitter(bottomø1, spread);
+        heightmap[ty * heightmap.resolution + cxø1] = jitter(topø1, spread);
+        heightmap[cyø1 * heightmap.resolution + lx] = jitter(leftø1, spread);
+        heightmap[cyø1 * heightmap.resolution + rx] = jitter(rightø1, spread);
+        return heightmap[cyø1 * heightmap.resolution + cxø1] = jitter(centerø1, spread);
+    }.call(this);
+};
+var midpointDisplacement = exports.midpointDisplacement = function midpointDisplacement(heightmap) {
+    mpdInitCorners(heightmap);
+    (function loop() {
+        var recur = loop;
+        var iterø1 = 0;
+        var spreadø1 = 0.3;
+        do {
+            recur = iterø1 < heightmap.exponent ? (function () {
+                (function () {
+                    var chunksø1 = Math.pow(2, iterø1);
+                    var chunkWidthø1 = (heightmap.resolution - 1) / chunksø1;
+                    return function () {
+                        var G__5ø1 = chunksø1;
+                        return function () {
+                            var G__6ø1 = G__5ø1;
+                            return function loop() {
+                                var recur = loop;
+                                var xchunkø1 = 0;
+                                do {
+                                    recur = xchunkø1 < G__6ø1 ? (function () {
+                                        (function () {
+                                            var G__7ø1 = G__5ø1;
+                                            return function loop() {
+                                                var recur = loop;
+                                                var ychunkø1 = 0;
+                                                do {
+                                                    recur = ychunkø1 < G__7ø1 ? (function () {
+                                                        (function () {
+                                                            var leftXø1 = chunkWidthø1 * xchunkø1;
+                                                            var rightXø1 = leftXø1 + chunkWidthø1;
+                                                            var bottomYø1 = chunkWidthø1 * ychunkø1;
+                                                            var topYø1 = bottomYø1 + chunkWidthø1;
+                                                            return mpdDisplace(heightmap, leftXø1, rightXø1, bottomYø1, topYø1, spreadø1);
+                                                        }.call(this));
+                                                        return loop[0] = 1 + ychunkø1, loop;
+                                                    })() : void 0;
+                                                } while (ychunkø1 = loop[0], recur === loop);
+                                                return recur;
+                                            }.call(this);
+                                        }.call(this));
+                                        return loop[0] = 1 + xchunkø1, loop;
+                                    })() : void 0;
+                                } while (xchunkø1 = loop[0], recur === loop);
+                                return recur;
+                            }.call(this);
+                        }.call(this);
+                    }.call(this);
+                }.call(this));
+                return loop[0] = 1 + iterø1, loop[1] = spreadø1 * 0.5, loop;
+            })() : void 0;
+        } while (iterø1 = loop[0], spreadø1 = loop[1], recur === loop);
+        return recur;
+    }.call(this));
+    return normalize(heightmap);
+};
+var midpointDisplacementFinal = exports.midpointDisplacementFinal = function midpointDisplacementFinal(heightmap) {
+    mpdInitCorners(heightmap);
+    (function loop() {
+        var recur = loop;
+        var iterø1 = 0;
+        var spreadø1 = 0 + $('#input-starting-spread').val();
+        do {
+            recur = iterø1 < heightmap.exponent ? (function () {
+                (function () {
+                    var chunksø1 = Math.pow(2, iterø1);
+                    var chunkWidthø1 = (heightmap.resolution - 1) / chunksø1;
+                    return function () {
+                        var G__8ø1 = chunksø1;
+                        return function () {
+                            var G__9ø1 = G__8ø1;
+                            return function loop() {
+                                var recur = loop;
+                                var xchunkø1 = 0;
+                                do {
+                                    recur = xchunkø1 < G__9ø1 ? (function () {
+                                        (function () {
+                                            var G__10ø1 = G__8ø1;
+                                            return function loop() {
+                                                var recur = loop;
+                                                var ychunkø1 = 0;
+                                                do {
+                                                    recur = ychunkø1 < G__10ø1 ? (function () {
+                                                        (function () {
+                                                            var leftXø1 = chunkWidthø1 * xchunkø1;
+                                                            var rightXø1 = leftXø1 + chunkWidthø1;
+                                                            var bottomYø1 = chunkWidthø1 * ychunkø1;
+                                                            var topYø1 = bottomYø1 + chunkWidthø1;
+                                                            return mpdDisplace(heightmap, leftXø1, rightXø1, bottomYø1, topYø1, spreadø1);
+                                                        }.call(this));
+                                                        return loop[0] = 1 + ychunkø1, loop;
+                                                    })() : void 0;
+                                                } while (ychunkø1 = loop[0], recur === loop);
+                                                return recur;
+                                            }.call(this);
+                                        }.call(this));
+                                        return loop[0] = 1 + xchunkø1, loop;
+                                    })() : void 0;
+                                } while (xchunkø1 = loop[0], recur === loop);
+                                return recur;
+                            }.call(this);
+                        }.call(this);
+                    }.call(this);
+                }.call(this));
+                return loop[0] = 1 + iterø1, loop[1] = spreadø1 * (0 + $('#input-spread-reduction').val()), loop;
+            })() : void 0;
+        } while (iterø1 = loop[0], spreadø1 = loop[1], recur === loop);
+        return recur;
+    }.call(this));
+    return normalize(heightmap);
+};
+var mpdDisplaceD2 = exports.mpdDisplaceD2 = function mpdDisplaceD2(heightmap, lx, rx, by, ty, spread) {
+    return function () {
+        var cxø1 = midpoint(lx, rx);
+        var cyø1 = midpoint(by, ty);
+        var bottomLeftø1 = heightmap[by * heightmap.resolution + lx];
+        var bottomRightø1 = heightmap[by * heightmap.resolution + rx];
+        var topLeftø1 = heightmap[ty * heightmap.resolution + lx];
+        var topRightø1 = heightmap[ty * heightmap.resolution + rx];
+        var topø1 = average2(topLeftø1, topRightø1);
+        var leftø1 = average2(bottomLeftø1, topLeftø1);
+        var bottomø1 = average2(bottomLeftø1, bottomRightø1);
+        var rightø1 = average2(bottomRightø1, topRightø1);
+        heightmap[by * heightmap.resolution + cxø1] = jitter(bottomø1, spread);
+        heightmap[ty * heightmap.resolution + cxø1] = jitter(topø1, spread);
+        heightmap[cyø1 * heightmap.resolution + lx] = jitter(leftø1, spread);
+        return heightmap[cyø1 * heightmap.resolution + rx] = jitter(rightø1, spread);
+    }.call(this);
+};
+var midpointDisplacementD1 = exports.midpointDisplacementD1 = function midpointDisplacementD1(heightmap) {
+    return mpdInitCorners(heightmap);
+};
+var midpointDisplacementD2 = exports.midpointDisplacementD2 = function midpointDisplacementD2(heightmap) {
+    mpdInitCorners(heightmap);
+    return mpdDisplaceD2(heightmap, 0, heightmap.last, 0, heightmap.last, 0.1);
+};
+var midpointDisplacementD3 = exports.midpointDisplacementD3 = function midpointDisplacementD3(heightmap) {
+    mpdInitCorners(heightmap);
+    return mpdDisplace(heightmap, 0, heightmap.last, 0, heightmap.last, 0.1);
+};
+var makeDirectionalLight = exports.makeDirectionalLight = function makeDirectionalLight() {
+    return function () {
+        var lightø1 = new THREE.DirectionalLight(16777215, 1);
+        lightø1.position.set(100, 0, 150);
+        return lightø1;
+    }.call(this);
+};
+var makeCamera = exports.makeCamera = function makeCamera() {
+    return function () {
+        var cameraø1 = new THREE.PerspectiveCamera(55, width / height, 0.1, 1000);
+        cameraø1.position.set(0, -100, 150);
+        return cameraø1;
+    }.call(this);
+};
+var makeRenderer = exports.makeRenderer = function makeRenderer() {
+    return function () {
+        var rendererø1 = new THREE.WebGLRenderer({ 'antialias': false });
+        rendererø1.setClearColor(16777215);
+        rendererø1.setSize(width, height);
+        rendererø1.setPixelRatio(2);
+        return rendererø1;
+    }.call(this);
+};
+var makeGeometry = exports.makeGeometry = function makeGeometry(heightmap) {
+    return function () {
+        var geometryø1 = new THREE.PlaneGeometry(terrainSize, terrainSize, heightmap.resolution - 1, heightmap.resolution - 1);
+        geometryø1.dynamic = true;
+        return geometryø1;
+    }.call(this);
+};
+var makeControls = exports.makeControls = function makeControls(camera, renderer) {
+    return function () {
+        var controlsø1 = new THREE.TrackballControls(camera, renderer.domElement);
+        controlsø1.rotateSpeed = 1.4;
+        controlsø1.zoomSpeed = 0.5;
+        controlsø1.staticMoving = true;
+        controlsø1.dynamicDampingFactor = 0.3;
+        return controlsø1;
+    }.call(this);
+};
+var makePlane = exports.makePlane = function makePlane(geometry) {
+    return function () {
+        var materialø1 = new THREE.MeshLambertMaterial({
+            'wireframe': wireframe,
+            'wireframeLinewidth': wireframeWidth,
+            'color': 47872
+        });
+        return new THREE.Mesh(geometry, materialø1);
+    }.call(this);
+};
+var attachToDom = exports.attachToDom = function attachToDom(renderer, elName, refreshFn) {
+    return function () {
+        var containerø1 = document.getElementById(elName);
+        var settingsø1 = document.createElement('div');
+        var refreshButtonø1 = document.createElement('button');
+        var buttonTextø1 = document.createTextNode('Refresh');
+        var cancelScrollø1 = function (e) {
+            return e.preventDefault();
+        };
+        refreshButtonø1.onclick = refreshFn;
+        renderer.domElement.onmousewheel = cancelScrollø1;
+        renderer.domElement.addEventListener('MozMousePixelScroll', cancelScrollø1, false);
+        refreshButtonø1.appendChild(buttonTextø1);
+        containerø1.appendChild(renderer.domElement);
+        containerø1.appendChild(settingsø1);
+        return settingsø1.appendChild(refreshButtonø1);
+    }.call(this);
+};
+var updateGeometry = exports.updateGeometry = function updateGeometry(geometry, heightmap) {
+    (function () {
+        var G__11ø1 = geometry.vertices.length;
+        return function loop() {
+            var recur = loop;
+            var iø1 = 0;
+            do {
+                recur = iø1 < G__11ø1 ? (function () {
+                    geometry.vertices[iø1].z = terrainHeight * heightmap[iø1];
+                    return loop[0] = 1 + iø1, loop;
+                })() : void 0;
+            } while (iø1 = loop[0], recur === loop);
+            return recur;
+        }.call(this);
+    }.call(this));
+    geometry.verticesNeedUpdate = true;
+    geometry.computeFaceNormals();
+    geometry.computeVertexNormals();
+    geometry.computeMorphNormals();
+    return geometry;
+};
+var makeDemo = exports.makeDemo = function makeDemo(elementId, algorithm, size) {
+    var scene = new THREE.Scene();
+    scene.add(new THREE.AxisHelper(100));
+    var clock = new THREE.Clock();
+    var camera = makeCamera();
+    var renderer = makeRenderer();
+    var geometry = makeGeometry(makeHeightmap(size));
+    scene.add(makeDirectionalLight());
+    scene.add(new THREE.AmbientLight(16777215, 0.05));
+    scene.add(makePlane(geometry));
+    var refresh = function refresh() {
+        l('Refreshing ========================================');
+        return function () {
+            var heightmapø1 = makeHeightmap(size);
+            l('Generating terrain...');
+            (function () {
+                var G__12ø1 = new Date().getTime();
+                var G__14ø1 = (function () {
+                    return algorithm(heightmapø1);
+                })();
+                var G__13ø1 = new Date().getTime();
+                l('Elapsed time: ' + (G__13ø1 - G__12ø1) + 'ms.');
+                return G__14ø1;
+            }.call(this));
+            l('Refreshing geometry...');
+            (function () {
+                var G__15ø1 = new Date().getTime();
+                var G__17ø1 = (function () {
+                    return updateGeometry(geometry, heightmapø1);
+                })();
+                var G__16ø1 = new Date().getTime();
+                l('Elapsed time: ' + (G__16ø1 - G__15ø1) + 'ms.');
+                return G__17ø1;
+            }.call(this));
+            return l('Done!');
+        }.call(this);
+    };
+    attachToDom(renderer, elementId, refresh);
+    var controls = makeControls(camera, renderer);
+    var render = function render() {
+        return function () {
+            var deltaø1 = clock.getDelta();
+            requestAnimationFrame(render);
+            controls.update(deltaø1);
+            return renderer.render(scene, camera);
+        }.call(this);
+    };
+    render();
+    return void 0;
+};
+var makeFinal = exports.makeFinal = function makeFinal(elementId) {
+    var scene = new THREE.Scene();
+    scene.add(new THREE.AxisHelper(100));
+    var clock = new THREE.Clock();
+    var camera = makeCamera();
+    var renderer = makeRenderer();
+    var heightmap = makeHeightmap($('#input-exponent').val());
+    var geometry = makeGeometry(heightmap);
+    var plane = makePlane(geometry);
+    scene.add(makeDirectionalLight());
+    scene.add(new THREE.AmbientLight(16777215, 0.05));
+    scene.add(plane);
+    var refresh = function refresh() {
+        l('Refreshing ========================================');
+        scene.remove(plane);
+        heightmap = makeHeightmap($('#input-exponent').val());
+        geometry = makeGeometry(heightmap);
+        plane = makePlane(geometry);
+        scene.add(plane);
+        l('Generating terrain...');
+        (function () {
+            var G__18ø1 = new Date().getTime();
+            var G__20ø1 = (function () {
+                return midpointDisplacementFinal(heightmap);
+            })();
+            var G__19ø1 = new Date().getTime();
+            l('Elapsed time: ' + (G__19ø1 - G__18ø1) + 'ms.');
+            return G__20ø1;
+        }.call(this));
+        l('Refreshing geometry...');
+        (function () {
+            var G__21ø1 = new Date().getTime();
+            var G__23ø1 = (function () {
+                return updateGeometry(geometry, heightmap);
+            })();
+            var G__22ø1 = new Date().getTime();
+            l('Elapsed time: ' + (G__22ø1 - G__21ø1) + 'ms.');
+            return G__23ø1;
+        }.call(this));
+        return l('Done!');
+    };
+    attachToDom(renderer, elementId, refresh);
+    var controls = makeControls(camera, renderer);
+    var render = function render() {
+        return function () {
+            var deltaø1 = clock.getDelta();
+            requestAnimationFrame(render);
+            controls.update(deltaø1);
+            return renderer.render(scene, camera);
+        }.call(this);
+    };
+    render();
+    return void 0;
+};
+var run = exports.run = function run() {
+    makeDemo('demo-random', randomNoise, 7);
+    makeDemo('demo-mpd-1', midpointDisplacementD1, 2);
+    makeDemo('demo-mpd-2', midpointDisplacementD2, 2);
+    makeDemo('demo-mpd-3', midpointDisplacementD3, 2);
+    makeDemo('demo-mpd-4', midpointDisplacement, 3);
+    return makeFinal('demo-final');
+};
+$(run);
+
+
+},{}]},{},[1]);
--- a/media/js/terrain1.wisp	Fri Feb 19 19:48:12 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,391 +0,0 @@
-; Constants -------------------------------------------------------------------
-(set! exports {}) ; fuck off wisp
-(def width 610)
-(def height 400)
-(def wireframe true)
-(def wireframe-width 1.2)
-(def terrain-height 50)
-(def terrain-size 100)
-
-; General Utilities -----------------------------------------------------------
-(defmacro when [condition & body]
-  `(if ~condition
-     (do ~@body)))
-
-(defmacro do-times [varname limit & body]
-  (let [end (gensym)]
-    `(let [~end ~limit]
-       (loop [~varname 0]
-         (when (< ~varname ~end)
-           ~@body
-           (recur (+ 1 ~varname)))))))
-
-(defmacro do-nested [xname yname width & body]
-  (let [iterations (gensym)]
-    `(let [~iterations ~width]
-       (do-times ~xname ~iterations
-         (do-times ~yname ~iterations
-           ~@body)))))
-
-(defmacro inc! [place]
-  `(set! ~place (+ ~place 1)))
-
-(defmacro add! [place amount]
-  `(set! ~place (+ ~place ~amount)))
-
-(defmacro time [& body]
-  (let [start (gensym)
-        end (gensym)
-        result (gensym)]
-    `(let [~start (.getTime (new Date))
-           ~result (do ~@body)
-           ~end (.getTime (new Date))]
-       (l (+ "Elapsed time: " (- ~end ~start) "ms."))
-       ~result)))
-
-(defn l [v]
-  (console.log v))
-
-
-(defn midpoint [a b]
-  (/ (+ a b) 2))
-
-(defn average2 [a b]
-  (/ (+ a b) 2))
-
-(defn average4 [a b c d]
-  (/ (+ a b c d) 4))
-
-(defn safe-average [a b c d]
-  (let [total 0 count 0]
-    (when a (add! total a) (inc! count))
-    (when b (add! total b) (inc! count))
-    (when c (add! total c) (inc! count))
-    (when d (add! total d) (inc! count))
-    (/ total count)))
-
-
-(defn rand []
-  (Math.random))
-
-(defn rand-around-zero [spread]
-  (- (* spread (rand) 2) spread))
-
-
-(defn jitter [value spread]
-  (+ value (rand-around-zero spread)))
-
-
-; Heightmap Helpers -----------------------------------------------------------
-(defmacro heightmap-get [hm x y]
-  `(aget ~hm (+ (* ~y (.-resolution ~hm)) ~x)))
-
-(defn heightmap-get-safe [hm x y]
-  (when (and (<= 0 x hm.last)
-             (<= 0 y hm.last))
-    (heightmap-get hm x y)))
-
-(defmacro heightmap-set! [hm x y val]
-  `(set! (heightmap-get ~hm ~x ~y) ~val))
-
-
-(defn normalize [hm]
-  (let [max (- Infinity)
-        min Infinity]
-    (do-times i hm.length
-      (let [el (aget hm i)]
-        (when (< max el) (set! max el))
-        (when (> min el) (set! min el))))
-    (let [span (- max min)]
-      (do-times i hm.length
-        (set! (aget hm i)
-          (/ (- (aget hm i) min)
-             span))))))
-
-(defn zero-heightmap [heightmap]
-  (do-times i heightmap.length
-    (set! (aget heightmap i) 0.0))
-  heightmap)
-
-(defn make-heightmap [exponent]
-  (let [resolution (+ 1 (Math.pow 2 exponent))]
-    (l (+ "Creating " resolution " by " resolution " heightmap..."))
-    (def heightmap
-      (new Array (* resolution resolution)))
-    (set! heightmap.resolution resolution)
-    (set! heightmap.exponent exponent)
-    (set! heightmap.last (- resolution 1))
-    (zero-heightmap heightmap)))
-
-
-; Random Noise ----------------------------------------------------------------
-(defn random-noise [heightmap]
-  (do-times i heightmap.length
-    (set! (aget heightmap i) (rand))))
-
-
-; Midpoint Displacement -------------------------------------------------------
-(defn mpd-init-corners [heightmap]
-  (heightmap-set! heightmap 0 0 (rand))
-  (heightmap-set! heightmap 0 heightmap.last (rand))
-  (heightmap-set! heightmap heightmap.last 0 (rand))
-  (heightmap-set! heightmap heightmap.last heightmap.last (rand)))
-
-(defn mpd-displace [heightmap lx rx by ty spread]
-  (let [cx (midpoint lx rx)
-        cy (midpoint by ty)
-
-        bottom-left (heightmap-get heightmap lx by)
-        bottom-right (heightmap-get heightmap rx by)
-        top-left (heightmap-get heightmap lx ty)
-        top-right (heightmap-get heightmap rx ty)
-
-        top (average2 top-left top-right)
-        left (average2 bottom-left top-left)
-        bottom (average2 bottom-left bottom-right)
-        right (average2 bottom-right top-right)
-        center (average4 top left bottom right)]
-    (heightmap-set! heightmap cx by (jitter bottom spread))
-    (heightmap-set! heightmap cx ty (jitter top spread))
-    (heightmap-set! heightmap lx cy (jitter left spread))
-    (heightmap-set! heightmap rx cy (jitter right spread))
-    (heightmap-set! heightmap cx cy (jitter center spread))))
-
-(defn midpoint-displacement [heightmap]
-  (mpd-init-corners heightmap)
-  ; (mpd-displace heightmap 0 heightmap.last 0 heightmap.last 0.1)
-  (loop [iter 0
-         spread 0.3]
-    (when (< iter heightmap.exponent)
-      (let [chunks (Math.pow 2 iter)
-            chunk-width (/ (- heightmap.resolution 1) chunks)]
-        (do-nested xchunk ychunk chunks
-          (let [left-x (* chunk-width xchunk)
-                right-x (+ left-x chunk-width)
-                bottom-y (* chunk-width ychunk)
-                top-y (+ bottom-y chunk-width)]
-            (mpd-displace heightmap left-x right-x bottom-y top-y spread))))
-      (recur (+ 1 iter) (* spread 0.5))))
-  (normalize heightmap))
-
-
-(defn midpoint-displacement-final [heightmap]
-  (mpd-init-corners heightmap)
-  ; (let [spread ])
-  (loop [iter 0
-         spread (+ 0 (.val ($ "#input-starting-spread")))]
-    (when (< iter heightmap.exponent)
-      (let [chunks (Math.pow 2 iter)
-            chunk-width (/ (- heightmap.resolution 1) chunks)]
-        (do-nested xchunk ychunk chunks
-          (let [left-x (* chunk-width xchunk)
-                right-x (+ left-x chunk-width)
-                bottom-y (* chunk-width ychunk)
-                top-y (+ bottom-y chunk-width)]
-            (mpd-displace heightmap left-x right-x bottom-y top-y spread))))
-      (recur (+ 1 iter) (* spread
-                           (+ 0 (.val ($ "#input-spread-reduction")))))))
-  (normalize heightmap))
-
-
-(defn mpd-displace-d2 [heightmap lx rx by ty spread]
-  (let [cx (midpoint lx rx)
-        cy (midpoint by ty)
-
-        bottom-left (heightmap-get heightmap lx by)
-        bottom-right (heightmap-get heightmap rx by)
-        top-left (heightmap-get heightmap lx ty)
-        top-right (heightmap-get heightmap rx ty)
-
-        top (average2 top-left top-right)
-        left (average2 bottom-left top-left)
-        bottom (average2 bottom-left bottom-right)
-        right (average2 bottom-right top-right)]
-    (heightmap-set! heightmap cx by (jitter bottom spread))
-    (heightmap-set! heightmap cx ty (jitter top spread))
-    (heightmap-set! heightmap lx cy (jitter left spread))
-    (heightmap-set! heightmap rx cy (jitter right spread))))
-
-(defn midpoint-displacement-d1 [heightmap]
-  (mpd-init-corners heightmap))
-
-(defn midpoint-displacement-d2 [heightmap]
-  (mpd-init-corners heightmap)
-  (mpd-displace-d2 heightmap
-                   0 heightmap.last
-                   0 heightmap.last
-                   0.1))
-
-(defn midpoint-displacement-d3 [heightmap]
-  (mpd-init-corners heightmap)
-  (mpd-displace heightmap
-                0 heightmap.last
-                0 heightmap.last
-                0.1))
-
-
-
-; Three.js Helpers ------------------------------------------------------------
-(defn make-directional-light []
-  (let [light (new THREE.DirectionalLight 0xffffff 1)]
-    (light.position.set 100 0 150)
-    light))
-
-(defn make-camera []
-  (let [camera (new THREE.PerspectiveCamera
-                    55,
-                    (/ width height)
-                    0.1,
-                    1000)]
-    (camera.position.set 0 -100 150)
-    camera))
-
-(defn make-renderer []
-  (let [renderer (new THREE.WebGLRenderer {:antialias false})]
-    (renderer.setClearColor 0xffffff)
-    (renderer.setSize width height)
-    (renderer.setPixelRatio 2)
-    renderer))
-
-(defn make-geometry [heightmap]
-  (let [geometry (new THREE.PlaneGeometry
-                      terrain-size
-                      terrain-size
-                      (- heightmap.resolution 1)
-                      (- heightmap.resolution 1))]
-    (set! geometry.dynamic true)
-    geometry))
-
-(defn make-controls [camera renderer]
-  (let [controls (new THREE.TrackballControls camera renderer.domElement)]
-    (set! controls.rotateSpeed 1.4)
-    (set! controls.zoomSpeed 0.5)
-    (set! controls.staticMoving true)
-    (set! controls.dynamicDampingFactor 0.3)
-    controls))
-
-(defn make-plane [geometry]
-  (let [material (new THREE.MeshLambertMaterial
-                      {:wireframe wireframe
-                       :wireframeLinewidth wireframe-width
-                       :color 0x00bb00})]
-    (new THREE.Mesh geometry material)))
-
-
-(defn attach-to-dom [renderer el-name refresh-fn]
-  (let [container (document.getElementById el-name)
-        settings (document.createElement "div")
-        refresh-button (document.createElement "button")
-        button-text (document.createTextNode "Refresh")
-        cancel-scroll (fn [e] (.preventDefault e))]
-    (set! refresh-button.onclick refresh-fn)
-    (set! renderer.domElement.onmousewheel cancel-scroll)
-    (renderer.domElement.addEventListener "MozMousePixelScroll" cancel-scroll false)
-    (.appendChild refresh-button button-text)
-    (.appendChild container renderer.domElement)
-    (.appendChild container settings)
-    (.appendChild settings refresh-button)))
-
-(defn update-geometry [geometry heightmap]
-  (do-times i geometry.vertices.length
-    (set! (.-z (aget geometry.vertices i))
-      (* terrain-height (aget heightmap i))))
-  (set! geometry.verticesNeedUpdate true)
-  (geometry.computeFaceNormals)
-  (geometry.computeVertexNormals)
-  (geometry.computeMorphNormals)
-  geometry)
-
-
-; Main ------------------------------------------------------------------------
-(defn make-demo [element-id algorithm size]
-  (def scene (new THREE.Scene))
-  (scene.add (new THREE.AxisHelper 100))
-
-  (def clock (new THREE.Clock))
-  (def camera (make-camera))
-  (def renderer (make-renderer))
-  (def geometry (make-geometry (make-heightmap size)))
-
-  (scene.add (make-directional-light))
-  (scene.add (new THREE.AmbientLight 0xffffff 0.05))
-  (scene.add (make-plane geometry))
-
-  (defn refresh []
-    (l "Refreshing ========================================")
-    (let [heightmap (make-heightmap size)]
-      (l "Generating terrain...")
-      (time (algorithm heightmap))
-      (l "Refreshing geometry...")
-      (time (update-geometry geometry heightmap))
-      (l "Done!")))
-
-  (attach-to-dom renderer element-id refresh)
-  (def controls (make-controls camera renderer))
-
-  (defn render []
-    (let [delta (clock.getDelta)]
-      (requestAnimationFrame render)
-      (.update controls delta)
-      (renderer.render scene camera)))
-
-  (render)
-
-  nil)
-
-(defn make-final [element-id]
-  (def scene (new THREE.Scene))
-  (scene.add (new THREE.AxisHelper 100))
-
-  (def clock (new THREE.Clock))
-  (def camera (make-camera))
-  (def renderer (make-renderer))
-  (def heightmap (make-heightmap (.val ($ "#input-exponent"))))
-  (def geometry (make-geometry heightmap))
-  (def plane (make-plane geometry))
-
-  (scene.add (make-directional-light))
-  (scene.add (new THREE.AmbientLight 0xffffff 0.05))
-  (scene.add plane)
-
-  (defn refresh []
-    (l "Refreshing ========================================")
-    (scene.remove plane)
-    (set! heightmap (make-heightmap (.val ($ "#input-exponent"))))
-    (set! geometry (make-geometry heightmap))
-    (set! plane (make-plane geometry))
-    (scene.add plane)
-    (l "Generating terrain...")
-    (time (midpoint-displacement-final heightmap))
-    (l "Refreshing geometry...")
-    (time (update-geometry geometry heightmap))
-    (l "Done!"))
-
-  (attach-to-dom renderer element-id refresh)
-  (def controls (make-controls camera renderer))
-
-  (defn render []
-    (let [delta (clock.getDelta)]
-      (requestAnimationFrame render)
-      (.update controls delta)
-      (renderer.render scene camera)))
-
-  (render)
-
-  nil)
-
-
-(defn run []
-  (make-demo "demo-random" random-noise 7)
-  (make-demo "demo-mpd-1" midpoint-displacement-d1 2)
-  (make-demo "demo-mpd-2" midpoint-displacement-d2 2)
-  (make-demo "demo-mpd-3" midpoint-displacement-d3 2)
-  (make-demo "demo-mpd-4" midpoint-displacement 3)
-  (make-final "demo-final")
-  ; (make-demo "demo-midpoint" midpoint-displacement)
-  ; (make-demo "demo-diamond" diamond-square)
-
-  )
-
-
-; vim: lw+=do-times lw+=do-nested :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/media/js/wisp/terrain1.js	Sun Feb 28 11:51:50 2016 +0000
@@ -0,0 +1,520 @@
+var width = exports.width = 610;
+var height = exports.height = 400;
+var wireframe = exports.wireframe = true;
+var wireframeWidth = exports.wireframeWidth = 1.2;
+var terrainHeight = exports.terrainHeight = 50;
+var terrainSize = exports.terrainSize = 100;
+void 0;
+void 0;
+void 0;
+void 0;
+void 0;
+void 0;
+var l = exports.l = function l(v) {
+    return console.log(v);
+};
+var midpoint = exports.midpoint = function midpoint(a, b) {
+    return (a + b) / 2;
+};
+var average2 = exports.average2 = function average2(a, b) {
+    return (a + b) / 2;
+};
+var average4 = exports.average4 = function average4(a, b, c, d) {
+    return (a + b + c + d) / 4;
+};
+var safeAverage = exports.safeAverage = function safeAverage(a, b, c, d) {
+    return function () {
+        var totalø1 = 0;
+        var countø1 = 0;
+        a ? (function () {
+            totalø1 = totalø1 + a;
+            return countø1 = countø1 + 1;
+        })() : void 0;
+        b ? (function () {
+            totalø1 = totalø1 + b;
+            return countø1 = countø1 + 1;
+        })() : void 0;
+        c ? (function () {
+            totalø1 = totalø1 + c;
+            return countø1 = countø1 + 1;
+        })() : void 0;
+        d ? (function () {
+            totalø1 = totalø1 + d;
+            return countø1 = countø1 + 1;
+        })() : void 0;
+        return totalø1 / countø1;
+    }.call(this);
+};
+var rand = exports.rand = function rand() {
+    return Math.random();
+};
+var randAroundZero = exports.randAroundZero = function randAroundZero(spread) {
+    return spread * rand() * 2 - spread;
+};
+var jitter = exports.jitter = function jitter(value, spread) {
+    return value + randAroundZero(spread);
+};
+void 0;
+var heightmapGetSafe = exports.heightmapGetSafe = function heightmapGetSafe(hm, x, y) {
+    return 0 <= x && x <= hm.last && (0 <= y && y <= hm.last) ? (function () {
+        return hm[y * hm.resolution + x];
+    })() : void 0;
+};
+void 0;
+var normalize = exports.normalize = function normalize(hm) {
+    return function () {
+        var maxø1 = 0 - Infinity;
+        var minø1 = Infinity;
+        (function () {
+            var G__1ø1 = hm.length;
+            return function loop() {
+                var recur = loop;
+                var iø1 = 0;
+                do {
+                    recur = iø1 < G__1ø1 ? (function () {
+                        (function () {
+                            var elø1 = hm[iø1];
+                            maxø1 < elø1 ? (function () {
+                                return maxø1 = elø1;
+                            })() : void 0;
+                            return minø1 > elø1 ? (function () {
+                                return minø1 = elø1;
+                            })() : void 0;
+                        }.call(this));
+                        return loop[0] = 1 + iø1, loop;
+                    })() : void 0;
+                } while (iø1 = loop[0], recur === loop);
+                return recur;
+            }.call(this);
+        }.call(this));
+        return function () {
+            var spanø1 = maxø1 - minø1;
+            return function () {
+                var G__2ø1 = hm.length;
+                return function loop() {
+                    var recur = loop;
+                    var iø1 = 0;
+                    do {
+                        recur = iø1 < G__2ø1 ? (function () {
+                            hm[iø1] = (hm[iø1] - minø1) / spanø1;
+                            return loop[0] = 1 + iø1, loop;
+                        })() : void 0;
+                    } while (iø1 = loop[0], recur === loop);
+                    return recur;
+                }.call(this);
+            }.call(this);
+        }.call(this);
+    }.call(this);
+};
+var zeroHeightmap = exports.zeroHeightmap = function zeroHeightmap(heightmap) {
+    (function () {
+        var G__3ø1 = heightmap.length;
+        return function loop() {
+            var recur = loop;
+            var iø1 = 0;
+            do {
+                recur = iø1 < G__3ø1 ? (function () {
+                    heightmap[iø1] = 0;
+                    return loop[0] = 1 + iø1, loop;
+                })() : void 0;
+            } while (iø1 = loop[0], recur === loop);
+            return recur;
+        }.call(this);
+    }.call(this));
+    return heightmap;
+};
+var makeHeightmap = exports.makeHeightmap = function makeHeightmap(exponent) {
+    return function () {
+        var resolutionø1 = 1 + Math.pow(2, exponent);
+        l('Creating ' + resolutionø1 + ' by ' + resolutionø1 + ' heightmap...');
+        var heightmap = new Array(resolutionø1 * resolutionø1);
+        heightmap.resolution = resolutionø1;
+        heightmap.exponent = exponent;
+        heightmap.last = resolutionø1 - 1;
+        return zeroHeightmap(heightmap);
+    }.call(this);
+};
+var randomNoise = exports.randomNoise = function randomNoise(heightmap) {
+    return function () {
+        var G__4ø1 = heightmap.length;
+        return function loop() {
+            var recur = loop;
+            var iø1 = 0;
+            do {
+                recur = iø1 < G__4ø1 ? (function () {
+                    heightmap[iø1] = rand();
+                    return loop[0] = 1 + iø1, loop;
+                })() : void 0;
+            } while (iø1 = loop[0], recur === loop);
+            return recur;
+        }.call(this);
+    }.call(this);
+};
+var mpdInitCorners = exports.mpdInitCorners = function mpdInitCorners(heightmap) {
+    heightmap[0 * heightmap.resolution + 0] = rand();
+    heightmap[heightmap.last * heightmap.resolution + 0] = rand();
+    heightmap[0 * heightmap.resolution + heightmap.last] = rand();
+    return heightmap[heightmap.last * heightmap.resolution + heightmap.last] = rand();
+};
+var mpdDisplace = exports.mpdDisplace = function mpdDisplace(heightmap, lx, rx, by, ty, spread) {
+    return function () {
+        var cxø1 = midpoint(lx, rx);
+        var cyø1 = midpoint(by, ty);
+        var bottomLeftø1 = heightmap[by * heightmap.resolution + lx];
+        var bottomRightø1 = heightmap[by * heightmap.resolution + rx];
+        var topLeftø1 = heightmap[ty * heightmap.resolution + lx];
+        var topRightø1 = heightmap[ty * heightmap.resolution + rx];
+        var topø1 = average2(topLeftø1, topRightø1);
+        var leftø1 = average2(bottomLeftø1, topLeftø1);
+        var bottomø1 = average2(bottomLeftø1, bottomRightø1);
+        var rightø1 = average2(bottomRightø1, topRightø1);
+        var centerø1 = average4(topø1, leftø1, bottomø1, rightø1);
+        heightmap[by * heightmap.resolution + cxø1] = jitter(bottomø1, spread);
+        heightmap[ty * heightmap.resolution + cxø1] = jitter(topø1, spread);
+        heightmap[cyø1 * heightmap.resolution + lx] = jitter(leftø1, spread);
+        heightmap[cyø1 * heightmap.resolution + rx] = jitter(rightø1, spread);
+        return heightmap[cyø1 * heightmap.resolution + cxø1] = jitter(centerø1, spread);
+    }.call(this);
+};
+var midpointDisplacement = exports.midpointDisplacement = function midpointDisplacement(heightmap) {
+    mpdInitCorners(heightmap);
+    (function loop() {
+        var recur = loop;
+        var iterø1 = 0;
+        var spreadø1 = 0.3;
+        do {
+            recur = iterø1 < heightmap.exponent ? (function () {
+                (function () {
+                    var chunksø1 = Math.pow(2, iterø1);
+                    var chunkWidthø1 = (heightmap.resolution - 1) / chunksø1;
+                    return function () {
+                        var G__5ø1 = chunksø1;
+                        return function () {
+                            var G__6ø1 = G__5ø1;
+                            return function loop() {
+                                var recur = loop;
+                                var xchunkø1 = 0;
+                                do {
+                                    recur = xchunkø1 < G__6ø1 ? (function () {
+                                        (function () {
+                                            var G__7ø1 = G__5ø1;
+                                            return function loop() {
+                                                var recur = loop;
+                                                var ychunkø1 = 0;
+                                                do {
+                                                    recur = ychunkø1 < G__7ø1 ? (function () {
+                                                        (function () {
+                                                            var leftXø1 = chunkWidthø1 * xchunkø1;
+                                                            var rightXø1 = leftXø1 + chunkWidthø1;
+                                                            var bottomYø1 = chunkWidthø1 * ychunkø1;
+                                                            var topYø1 = bottomYø1 + chunkWidthø1;
+                                                            return mpdDisplace(heightmap, leftXø1, rightXø1, bottomYø1, topYø1, spreadø1);
+                                                        }.call(this));
+                                                        return loop[0] = 1 + ychunkø1, loop;
+                                                    })() : void 0;
+                                                } while (ychunkø1 = loop[0], recur === loop);
+                                                return recur;
+                                            }.call(this);
+                                        }.call(this));
+                                        return loop[0] = 1 + xchunkø1, loop;
+                                    })() : void 0;
+                                } while (xchunkø1 = loop[0], recur === loop);
+                                return recur;
+                            }.call(this);
+                        }.call(this);
+                    }.call(this);
+                }.call(this));
+                return loop[0] = 1 + iterø1, loop[1] = spreadø1 * 0.5, loop;
+            })() : void 0;
+        } while (iterø1 = loop[0], spreadø1 = loop[1], recur === loop);
+        return recur;
+    }.call(this));
+    return normalize(heightmap);
+};
+var midpointDisplacementFinal = exports.midpointDisplacementFinal = function midpointDisplacementFinal(heightmap) {
+    mpdInitCorners(heightmap);
+    (function loop() {
+        var recur = loop;
+        var iterø1 = 0;
+        var spreadø1 = 0 + $('#input-starting-spread').val();
+        do {
+            recur = iterø1 < heightmap.exponent ? (function () {
+                (function () {
+                    var chunksø1 = Math.pow(2, iterø1);
+                    var chunkWidthø1 = (heightmap.resolution - 1) / chunksø1;
+                    return function () {
+                        var G__8ø1 = chunksø1;
+                        return function () {
+                            var G__9ø1 = G__8ø1;
+                            return function loop() {
+                                var recur = loop;
+                                var xchunkø1 = 0;
+                                do {
+                                    recur = xchunkø1 < G__9ø1 ? (function () {
+                                        (function () {
+                                            var G__10ø1 = G__8ø1;
+                                            return function loop() {
+                                                var recur = loop;
+                                                var ychunkø1 = 0;
+                                                do {
+                                                    recur = ychunkø1 < G__10ø1 ? (function () {
+                                                        (function () {
+                                                            var leftXø1 = chunkWidthø1 * xchunkø1;
+                                                            var rightXø1 = leftXø1 + chunkWidthø1;
+                                                            var bottomYø1 = chunkWidthø1 * ychunkø1;
+                                                            var topYø1 = bottomYø1 + chunkWidthø1;
+                                                            return mpdDisplace(heightmap, leftXø1, rightXø1, bottomYø1, topYø1, spreadø1);
+                                                        }.call(this));
+                                                        return loop[0] = 1 + ychunkø1, loop;
+                                                    })() : void 0;
+                                                } while (ychunkø1 = loop[0], recur === loop);
+                                                return recur;
+                                            }.call(this);
+                                        }.call(this));
+                                        return loop[0] = 1 + xchunkø1, loop;
+                                    })() : void 0;
+                                } while (xchunkø1 = loop[0], recur === loop);
+                                return recur;
+                            }.call(this);
+                        }.call(this);
+                    }.call(this);
+                }.call(this));
+                return loop[0] = 1 + iterø1, loop[1] = spreadø1 * (0 + $('#input-spread-reduction').val()), loop;
+            })() : void 0;
+        } while (iterø1 = loop[0], spreadø1 = loop[1], recur === loop);
+        return recur;
+    }.call(this));
+    return normalize(heightmap);
+};
+var mpdDisplaceD2 = exports.mpdDisplaceD2 = function mpdDisplaceD2(heightmap, lx, rx, by, ty, spread) {
+    return function () {
+        var cxø1 = midpoint(lx, rx);
+        var cyø1 = midpoint(by, ty);
+        var bottomLeftø1 = heightmap[by * heightmap.resolution + lx];
+        var bottomRightø1 = heightmap[by * heightmap.resolution + rx];
+        var topLeftø1 = heightmap[ty * heightmap.resolution + lx];
+        var topRightø1 = heightmap[ty * heightmap.resolution + rx];
+        var topø1 = average2(topLeftø1, topRightø1);
+        var leftø1 = average2(bottomLeftø1, topLeftø1);
+        var bottomø1 = average2(bottomLeftø1, bottomRightø1);
+        var rightø1 = average2(bottomRightø1, topRightø1);
+        heightmap[by * heightmap.resolution + cxø1] = jitter(bottomø1, spread);
+        heightmap[ty * heightmap.resolution + cxø1] = jitter(topø1, spread);
+        heightmap[cyø1 * heightmap.resolution + lx] = jitter(leftø1, spread);
+        return heightmap[cyø1 * heightmap.resolution + rx] = jitter(rightø1, spread);
+    }.call(this);
+};
+var midpointDisplacementD1 = exports.midpointDisplacementD1 = function midpointDisplacementD1(heightmap) {
+    return mpdInitCorners(heightmap);
+};
+var midpointDisplacementD2 = exports.midpointDisplacementD2 = function midpointDisplacementD2(heightmap) {
+    mpdInitCorners(heightmap);
+    return mpdDisplaceD2(heightmap, 0, heightmap.last, 0, heightmap.last, 0.1);
+};
+var midpointDisplacementD3 = exports.midpointDisplacementD3 = function midpointDisplacementD3(heightmap) {
+    mpdInitCorners(heightmap);
+    return mpdDisplace(heightmap, 0, heightmap.last, 0, heightmap.last, 0.1);
+};
+var makeDirectionalLight = exports.makeDirectionalLight = function makeDirectionalLight() {
+    return function () {
+        var lightø1 = new THREE.DirectionalLight(16777215, 1);
+        lightø1.position.set(100, 0, 150);
+        return lightø1;
+    }.call(this);
+};
+var makeCamera = exports.makeCamera = function makeCamera() {
+    return function () {
+        var cameraø1 = new THREE.PerspectiveCamera(55, width / height, 0.1, 1000);
+        cameraø1.position.set(0, -100, 150);
+        return cameraø1;
+    }.call(this);
+};
+var makeRenderer = exports.makeRenderer = function makeRenderer() {
+    return function () {
+        var rendererø1 = new THREE.WebGLRenderer({ 'antialias': false });
+        rendererø1.setClearColor(16777215);
+        rendererø1.setSize(width, height);
+        rendererø1.setPixelRatio(2);
+        return rendererø1;
+    }.call(this);
+};
+var makeGeometry = exports.makeGeometry = function makeGeometry(heightmap) {
+    return function () {
+        var geometryø1 = new THREE.PlaneGeometry(terrainSize, terrainSize, heightmap.resolution - 1, heightmap.resolution - 1);
+        geometryø1.dynamic = true;
+        return geometryø1;
+    }.call(this);
+};
+var makeControls = exports.makeControls = function makeControls(camera, renderer) {
+    return function () {
+        var controlsø1 = new THREE.TrackballControls(camera, renderer.domElement);
+        controlsø1.rotateSpeed = 1.4;
+        controlsø1.zoomSpeed = 0.5;
+        controlsø1.staticMoving = true;
+        controlsø1.dynamicDampingFactor = 0.3;
+        return controlsø1;
+    }.call(this);
+};
+var makePlane = exports.makePlane = function makePlane(geometry) {
+    return function () {
+        var materialø1 = new THREE.MeshLambertMaterial({
+            'wireframe': wireframe,
+            'wireframeLinewidth': wireframeWidth,
+            'color': 47872
+        });
+        return new THREE.Mesh(geometry, materialø1);
+    }.call(this);
+};
+var attachToDom = exports.attachToDom = function attachToDom(renderer, elName, refreshFn) {
+    return function () {
+        var containerø1 = document.getElementById(elName);
+        var settingsø1 = document.createElement('div');
+        var refreshButtonø1 = document.createElement('button');
+        var buttonTextø1 = document.createTextNode('Refresh');
+        var cancelScrollø1 = function (e) {
+            return e.preventDefault();
+        };
+        refreshButtonø1.onclick = refreshFn;
+        renderer.domElement.onmousewheel = cancelScrollø1;
+        renderer.domElement.addEventListener('MozMousePixelScroll', cancelScrollø1, false);
+        refreshButtonø1.appendChild(buttonTextø1);
+        containerø1.appendChild(renderer.domElement);
+        containerø1.appendChild(settingsø1);
+        return settingsø1.appendChild(refreshButtonø1);
+    }.call(this);
+};
+var updateGeometry = exports.updateGeometry = function updateGeometry(geometry, heightmap) {
+    (function () {
+        var G__11ø1 = geometry.vertices.length;
+        return function loop() {
+            var recur = loop;
+            var iø1 = 0;
+            do {
+                recur = iø1 < G__11ø1 ? (function () {
+                    geometry.vertices[iø1].z = terrainHeight * heightmap[iø1];
+                    return loop[0] = 1 + iø1, loop;
+                })() : void 0;
+            } while (iø1 = loop[0], recur === loop);
+            return recur;
+        }.call(this);
+    }.call(this));
+    geometry.verticesNeedUpdate = true;
+    geometry.computeFaceNormals();
+    geometry.computeVertexNormals();
+    geometry.computeMorphNormals();
+    return geometry;
+};
+var makeDemo = exports.makeDemo = function makeDemo(elementId, algorithm, size) {
+    var scene = new THREE.Scene();
+    scene.add(new THREE.AxisHelper(100));
+    var clock = new THREE.Clock();
+    var camera = makeCamera();
+    var renderer = makeRenderer();
+    var geometry = makeGeometry(makeHeightmap(size));
+    scene.add(makeDirectionalLight());
+    scene.add(new THREE.AmbientLight(16777215, 0.05));
+    scene.add(makePlane(geometry));
+    var refresh = function refresh() {
+        l('Refreshing ========================================');
+        return function () {
+            var heightmapø1 = makeHeightmap(size);
+            l('Generating terrain...');
+            (function () {
+                var G__12ø1 = new Date().getTime();
+                var G__14ø1 = (function () {
+                    return algorithm(heightmapø1);
+                })();
+                var G__13ø1 = new Date().getTime();
+                l('Elapsed time: ' + (G__13ø1 - G__12ø1) + 'ms.');
+                return G__14ø1;
+            }.call(this));
+            l('Refreshing geometry...');
+            (function () {
+                var G__15ø1 = new Date().getTime();
+                var G__17ø1 = (function () {
+                    return updateGeometry(geometry, heightmapø1);
+                })();
+                var G__16ø1 = new Date().getTime();
+                l('Elapsed time: ' + (G__16ø1 - G__15ø1) + 'ms.');
+                return G__17ø1;
+            }.call(this));
+            return l('Done!');
+        }.call(this);
+    };
+    attachToDom(renderer, elementId, refresh);
+    var controls = makeControls(camera, renderer);
+    var render = function render() {
+        return function () {
+            var deltaø1 = clock.getDelta();
+            requestAnimationFrame(render);
+            controls.update(deltaø1);
+            return renderer.render(scene, camera);
+        }.call(this);
+    };
+    render();
+    return void 0;
+};
+var makeFinal = exports.makeFinal = function makeFinal(elementId) {
+    var scene = new THREE.Scene();
+    scene.add(new THREE.AxisHelper(100));
+    var clock = new THREE.Clock();
+    var camera = makeCamera();
+    var renderer = makeRenderer();
+    var heightmap = makeHeightmap($('#input-exponent').val());
+    var geometry = makeGeometry(heightmap);
+    var plane = makePlane(geometry);
+    scene.add(makeDirectionalLight());
+    scene.add(new THREE.AmbientLight(16777215, 0.05));
+    scene.add(plane);
+    var refresh = function refresh() {
+        l('Refreshing ========================================');
+        scene.remove(plane);
+        heightmap = makeHeightmap($('#input-exponent').val());
+        geometry = makeGeometry(heightmap);
+        plane = makePlane(geometry);
+        scene.add(plane);
+        l('Generating terrain...');
+        (function () {
+            var G__18ø1 = new Date().getTime();
+            var G__20ø1 = (function () {
+                return midpointDisplacementFinal(heightmap);
+            })();
+            var G__19ø1 = new Date().getTime();
+            l('Elapsed time: ' + (G__19ø1 - G__18ø1) + 'ms.');
+            return G__20ø1;
+        }.call(this));
+        l('Refreshing geometry...');
+        (function () {
+            var G__21ø1 = new Date().getTime();
+            var G__23ø1 = (function () {
+                return updateGeometry(geometry, heightmap);
+            })();
+            var G__22ø1 = new Date().getTime();
+            l('Elapsed time: ' + (G__22ø1 - G__21ø1) + 'ms.');
+            return G__23ø1;
+        }.call(this));
+        return l('Done!');
+    };
+    attachToDom(renderer, elementId, refresh);
+    var controls = makeControls(camera, renderer);
+    var render = function render() {
+        return function () {
+            var deltaø1 = clock.getDelta();
+            requestAnimationFrame(render);
+            controls.update(deltaø1);
+            return renderer.render(scene, camera);
+        }.call(this);
+    };
+    render();
+    return void 0;
+};
+var run = exports.run = function run() {
+    makeDemo('demo-random', randomNoise, 7);
+    makeDemo('demo-mpd-1', midpointDisplacementD1, 2);
+    makeDemo('demo-mpd-2', midpointDisplacementD2, 2);
+    makeDemo('demo-mpd-3', midpointDisplacementD3, 2);
+    makeDemo('demo-mpd-4', midpointDisplacement, 3);
+    return makeFinal('demo-final');
+};
+$(run);
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFub255bW91cy53aXNwIl0sIm5hbWVzIjpbIndpZHRoIiwiZXhwb3J0cyIsImhlaWdodCIsIndpcmVmcmFtZSIsIndpcmVmcmFtZVdpZHRoIiwidGVycmFpbkhlaWdodCIsInRlcnJhaW5TaXplIiwibCIsInYiLCJjb25zb2xlIiwibG9nIiwibWlkcG9pbnQiLCJhIiwiYiIsImF2ZXJhZ2UyIiwiYXZlcmFnZTQiLCJjIiwiZCIsInNhZmVBdmVyYWdlIiwidG90YWzDuDEiLCJjb3VudMO4MSIsInJhbmQiLCJNYXRoIiwicmFuZG9tIiwicmFuZEFyb3VuZFplcm8iLCJzcHJlYWQiLCJqaXR0ZXIiLCJ2YWx1ZSIsImhlaWdodG1hcEdldFNhZmUiLCJobSIsIngiLCJ5IiwibGFzdCIsIm5vcm1hbGl6ZSIsIm1heMO4MSIsIkluZmluaXR5IiwibWluw7gxIiwibGVuZ3RoIiwiacO4MSIsImVsw7gxIiwic3BhbsO4MSIsInplcm9IZWlnaHRtYXAiLCJoZWlnaHRtYXAiLCJtYWtlSGVpZ2h0bWFwIiwiZXhwb25lbnQiLCJyZXNvbHV0aW9uw7gxIiwicG93IiwiQXJyYXkiLCJyZXNvbHV0aW9uIiwicmFuZG9tTm9pc2UiLCJtcGRJbml0Q29ybmVycyIsIm1wZERpc3BsYWNlIiwibHgiLCJyeCIsImJ5IiwidHkiLCJjeMO4MSIsImN5w7gxIiwiYm90dG9tTGVmdMO4MSIsImJvdHRvbVJpZ2h0w7gxIiwidG9wTGVmdMO4MSIsInRvcFJpZ2h0w7gxIiwidG9ww7gxIiwibGVmdMO4MSIsImJvdHRvbcO4MSIsInJpZ2h0w7gxIiwiY2VudGVyw7gxIiwibWlkcG9pbnREaXNwbGFjZW1lbnQiLCJpdGVyw7gxIiwic3ByZWFkw7gxIiwiY2h1bmtzw7gxIiwiY2h1bmtXaWR0aMO4MSIsInhjaHVua8O4MSIsInljaHVua8O4MSIsImxlZnRYw7gxIiwicmlnaHRYw7gxIiwiYm90dG9tWcO4MSIsInRvcFnDuDEiLCJtaWRwb2ludERpc3BsYWNlbWVudEZpbmFsIiwiJCIsInZhbCIsIm1wZERpc3BsYWNlRDIiLCJtaWRwb2ludERpc3BsYWNlbWVudEQxIiwibWlkcG9pbnREaXNwbGFjZW1lbnREMiIsIm1pZHBvaW50RGlzcGxhY2VtZW50RDMiLCJtYWtlRGlyZWN0aW9uYWxMaWdodCIsImxpZ2h0w7gxIiwiVEhSRUUiLCJEaXJlY3Rpb25hbExpZ2h0IiwicG9zaXRpb24uc2V0IiwibWFrZUNhbWVyYSIsImNhbWVyYcO4MSIsIlBlcnNwZWN0aXZlQ2FtZXJhIiwibWFrZVJlbmRlcmVyIiwicmVuZGVyZXLDuDEiLCJXZWJHTFJlbmRlcmVyIiwic2V0Q2xlYXJDb2xvciIsInNldFNpemUiLCJzZXRQaXhlbFJhdGlvIiwibWFrZUdlb21ldHJ5IiwiZ2VvbWV0cnnDuDEiLCJQbGFuZUdlb21ldHJ5IiwiZHluYW1pYyIsIm1ha2VDb250cm9scyIsImNhbWVyYSIsInJlbmRlcmVyIiwiY29udHJvbHPDuDEiLCJUcmFja2JhbGxDb250cm9scyIsImRvbUVsZW1lbnQiLCJyb3RhdGVTcGVlZCIsInpvb21TcGVlZCIsInN0YXRpY01vdmluZyIsImR5bmFtaWNEYW1waW5nRmFjdG9yIiwibWFrZVBsYW5lIiwiZ2VvbWV0cnkiLCJtYXRlcmlhbMO4MSIsIk1lc2hMYW1iZXJ0TWF0ZXJpYWwiLCJNZXNoIiwiYXR0YWNoVG9Eb20iLCJlbE5hbWUiLCJyZWZyZXNoRm4iLCJjb250YWluZXLDuDEiLCJkb2N1bWVudCIsImdldEVsZW1lbnRCeUlkIiwic2V0dGluZ3PDuDEiLCJjcmVhdGVFbGVtZW50IiwicmVmcmVzaEJ1dHRvbsO4MSIsImJ1dHRvblRleHTDuDEiLCJjcmVhdGVUZXh0Tm9kZSIsImNhbmNlbFNjcm9sbMO4MSIsImUiLCJwcmV2ZW50RGVmYXVsdCIsIm9uY2xpY2siLCJkb21FbGVtZW50Lm9ubW91c2V3aGVlbCIsImRvbUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciIsImFwcGVuZENoaWxkIiwidXBkYXRlR2VvbWV0cnkiLCJ2ZXJ0aWNlcy5sZW5ndGgiLCJ2ZXJ0aWNlcyIsInoiLCJ2ZXJ0aWNlc05lZWRVcGRhdGUiLCJjb21wdXRlRmFjZU5vcm1hbHMiLCJjb21wdXRlVmVydGV4Tm9ybWFscyIsImNvbXB1dGVNb3JwaE5vcm1hbHMiLCJtYWtlRGVtbyIsImVsZW1lbnRJZCIsImFsZ29yaXRobSIsInNpemUiLCJzY2VuZSIsIlNjZW5lIiwiYWRkIiwiQXhpc0hlbHBlciIsImNsb2NrIiwiQ2xvY2siLCJBbWJpZW50TGlnaHQiLCJyZWZyZXNoIiwiaGVpZ2h0bWFww7gxIiwiY29udHJvbHMiLCJyZW5kZXIiLCJkZWx0YcO4MSIsImdldERlbHRhIiwicmVxdWVzdEFuaW1hdGlvbkZyYW1lIiwidXBkYXRlIiwibWFrZUZpbmFsIiwicGxhbmUiLCJyZW1vdmUiLCJydW4iXSwibWFwcGluZ3MiOiJBQUNBLElBQUtBLEtBQUEsR0FBQUMsT0FBQSxDQUFBRCxLQUFBLEdBQU0sR0FBWDtBQUNBLElBQUtFLE1BQUEsR0FBQUQsT0FBQSxDQUFBQyxNQUFBLEdBQU8sR0FBWixDQURBO0FBRUEsSUFBS0MsU0FBQSxHQUFBRixPQUFBLENBQUFFLFNBQUEsRyxJQUFMLENBRkE7QUFHQSxJQUFLQyxjQUFBLEdBQUFILE9BQUEsQ0FBQUcsY0FBQSxHQUFnQixHQUFyQixDQUhBO0FBSUEsSUFBS0MsYUFBQSxHQUFBSixPQUFBLENBQUFJLGFBQUEsR0FBZSxFQUFwQixDQUpBO0FBS0EsSUFBS0MsV0FBQSxHQUFBTCxPQUFBLENBQUFLLFdBQUEsR0FBYSxHQUFsQixDQUxBO09BQUE7T0FBQTtPQUFBO09BQUE7T0FBQTtPQUFBO0FBMkNBLElBQU1DLENBQUEsR0FBQU4sT0FBQSxDQUFBTSxDQUFBLEdBQU4sU0FBTUEsQ0FBTixDQUFTQyxDQUFULEVBQ0U7QUFBQSxXQUFDQyxPQUFBLENBQVFDLEdBQVQsQ0FBYUYsQ0FBYjtBQUFBLENBREYsQ0EzQ0E7QUErQ0EsSUFBTUcsUUFBQSxHQUFBVixPQUFBLENBQUFVLFFBQUEsR0FBTixTQUFNQSxRQUFOLENBQWdCQyxDQUFoQixFQUFrQkMsQ0FBbEIsRUFDRTtBQUFBLFdB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QVcsWUFBWCxFQUF3QjdFLG9CQUF4QixFQUE4QyxDQUE5QyxFQUpBO0FBQUEsSUFLQSxPQUFDZ0csU0FBRCxDQUFZLFlBQVosRUFMQTtBQUFBLENBREYsQ0F2WEE7QUFtWUNwRixDQUFELENBQUd1RixHQUFIIiwic291cmNlc0NvbnRlbnQiOlsiOyBDb25zdGFudHMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuKGRlZiB3aWR0aCA2MTApXG4oZGVmIGhlaWdodCA0MDApXG4oZGVmIHdpcmVmcmFtZSB0cnVlKVxuKGRlZiB3aXJlZnJhbWUtd2lkdGggMS4yKVxuKGRlZiB0ZXJyYWluLWhlaWdodCA1MClcbihkZWYgdGVycmFpbi1zaXplIDEwMClcblxuOyBHZW5lcmFsIFV0aWxpdGllcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuKGRlZm1hY3JvIHdoZW4gW2NvbmRpdGlvbiAmIGJvZHldXG4gIGAoaWYgfmNvbmRpdGlvblxuICAgICAoZG8gfkBib2R5KSkpXG5cbihkZWZtYWNybyBkby10aW1lcyBbdmFybmFtZSBsaW1pdCAmIGJvZHldXG4gIChsZXQgW2VuZCAoZ2Vuc3ltKV1cbiAgICBgKGxldCBbfmVuZCB+bGltaXRdXG4gICAgICAgKGxvb3AgW352YXJuYW1lIDBdXG4gICAgICAgICAod2hlbiAoPCB+dmFybmFtZSB+ZW5kKVxuICAgICAgICAgICB+QGJvZHlcbiAgICAgICAgICAgKHJlY3VyICgrIDEgfnZhcm5hbWUpKSkpKSkpXG5cbihkZWZtYWNybyBkby1uZXN0ZWQgW3huYW1lIHluYW1lIHdpZHRoICYgYm9keV1cbiAgKGxldCBbaXRlcmF0aW9ucyAoZ2Vuc3ltKV1cbiAgICBgKGxldCBbfml0ZXJhdGlvbnMgfndpZHRoXVxuICAgICAgIChkby10aW1lcyB+eG5hbWUgfml0ZXJhdGlvbnNcbiAgICAgICAgIChkby10aW1lcyB+eW5hbWUgfml0ZXJhdGlvbnNcbiAgICAgICAgICAgfkBib2R5KSkpKSlcblxuKGRlZm1hY3JvIGluYyEgW3BsYWNlXVxuICBgKHNldCEgfnBsYWNlICgrIH5wbGFjZSAxKSkpXG5cbihkZWZtYWNybyBhZGQhIFtwbGFjZSBhbW91bnRdXG4gIGAoc2V0ISB+cGxhY2UgKCsgfnBsYWNlIH5hbW91bnQpKSlcblxuKGRlZm1hY3JvIHRpbWUgWyYgYm9keV1cbiAgKGxldCBbc3RhcnQgKGdlbnN5bSlcbiAgICAgICAgZW5kIChnZW5zeW0pXG4gICAgICAgIHJlc3VsdCAoZ2Vuc3ltKV1cbiAgICBgKGxldCBbfnN0YXJ0ICguZ2V0VGltZSAobmV3IERhdGUpKVxuICAgICAgICAgICB+cmVzdWx0IChkbyB+QGJvZHkpXG4gICAgICAgICAgIH5lbmQgKC5nZXRUaW1lIChuZXcgRGF0ZSkpXVxuICAgICAgIChsICgrIFwiRWxhcHNlZCB0aW1lOiBcIiAoLSB+ZW5kIH5zdGFydCkgXCJtcy5cIikpXG4gICAgICAgfnJlc3VsdCkpKVxuXG4oZGVmbiBsIFt2XVxuICAoY29uc29sZS5sb2cgdikpXG5cblxuKGRlZm4gbWlkcG9pbnQgW2EgYl1cbiAgKC8gKCsgYSBiKSAyKSlcblxuKGRlZm4gYXZlcmFnZTIgW2EgYl1cbiAgKC8gKCsgYSBiKSAyKSlcblxuKGRlZm4gYXZlcmFnZTQgW2EgYiBjIGRdXG4gICgvICgrIGEgYiBjIGQpIDQpKVxuXG4oZGVmbiBzYWZlLWF2ZXJhZ2UgW2EgYiBjIGRdXG4gIChsZXQgW3RvdGFsIDAgY291bnQgMF1cbiAgICAod2hlbiBhIChhZGQhIHRvdGFsIGEpIChpbmMhIGNvdW50KSlcbiAgICAod2hlbiBiIChhZGQhIHRvdGFsIGIpIChpbmMhIGNvdW50KSlcbiAgICAod2hlbiBjIChhZGQhIHRvdGFsIGMpIChpbmMhIGNvdW50KSlcbiAgICAod2hlbiBkIChhZGQhIHRvdGFsIGQpIChpbmMhIGNvdW50KSlcbiAgICAoLyB0b3RhbCBjb3VudCkpKVxuXG5cbihkZWZuIHJhbmQgW11cbiAgKE1hdGgucmFuZG9tKSlcblxuKGRlZm4gcmFuZC1hcm91bmQtemVybyBbc3ByZWFkXVxuICAoLSAoKiBzcHJlYWQgKHJhbmQpIDIpIHNwcmVhZCkpXG5cblxuKGRlZm4gaml0dGVyIFt2YWx1ZSBzcHJlYWRdXG4gICgrIHZhbHVlIChyYW5kLWFyb3VuZC16ZXJvIHNwcmVhZCkpKVxuXG5cbjsgSGVpZ2h0bWFwIEhlbHBlcnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbihkZWZtYWNybyBoZWlnaHRtYXAtZ2V0IFtobSB4IHldXG4gIGAoYWdldCB+aG0gKCsgKCogfnkgKC4tcmVzb2x1dGlvbiB+aG0pKSB+eCkpKVxuXG4oZGVmbiBoZWlnaHRtYXAtZ2V0LXNhZmUgW2htIHggeV1cbiAgKHdoZW4gKGFuZCAoPD0gMCB4IGhtLmxhc3QpXG4gICAgICAgICAgICAgKDw9IDAgeSBobS5sYXN0KSlcbiAgICAoaGVpZ2h0bWFwLWdldCBobSB4IHkpKSlcblxuKGRlZm1hY3JvIGhlaWdodG1hcC1zZXQhIFtobSB4IHkgdmFsXVxuICBgKHNldCEgKGhlaWdodG1hcC1nZXQgfmhtIH54IH55KSB+dmFsKSlcblxuXG4oZGVmbiBub3JtYWxpemUgW2htXVxuICAobGV0IFttYXggKC0gSW5maW5pdHkpXG4gICAgICAgIG1pbiBJbmZpbml0eV1cbiAgICAoZG8tdGltZXMgaSBobS5sZW5ndGhcbiAgICAgIChsZXQgW2VsIChhZ2V0IGhtIGkpXVxuICAgICAgICAod2hlbiAoPCBtYXggZWwpIChzZXQhIG1heCBlbCkpXG4gICAgICAgICh3aGVuICg+IG1pbiBlbCkgKHNldCEgbWluIGVsKSkpKVxuICAgIChsZXQgW3NwYW4gKC0gbWF4IG1pbildXG4gICAgICAoZG8tdGltZXMgaSBobS5sZW5ndGhcbiAgICAgICAgKHNldCEgKGFnZXQgaG0gaSlcbiAgICAgICAgICAoLyAoLSAoYWdldCBobSBpKSBtaW4pXG4gICAgICAgICAgICAgc3BhbikpKSkpKVxuXG4oZGVmbiB6ZXJvLWhlaWdodG1hcCBbaGVpZ2h0bWFwXVxuICAoZG8tdGltZXMgaSBoZWlnaHRtYXAubGVuZ3RoXG4gICAgKHNldCEgKGFnZXQgaGVpZ2h0bWFwIGkpIDAuMCkpXG4gIGhlaWdodG1hcClcblxuKGRlZm4gbWFrZS1oZWlnaHRtYXAgW2V4cG9uZW50XVxuICAobGV0IFtyZXNvbHV0aW9uICgrIDEgKE1hdGgucG93IDIgZXhwb25lbnQpKV1cbiAgICAobCAoKyBcIkNyZWF0aW5nIFwiIHJlc29sdXRpb24gXCIgYnkgXCIgcmVzb2x1dGlvbiBcIiBoZWlnaHRtYXAuLi5cIikpXG4gICAgKGRlZiBoZWlnaHRtYXBcbiAgICAgIChuZXcgQXJyYXkgKCogcmVzb2x1dGlvbiByZXNvbHV0aW9uKSkpXG4gICAgKHNldCEgaGVpZ2h0bWFwLnJlc29sdXRpb24gcmVzb2x1dGlvbilcbiAgICAoc2V0ISBoZWlnaHRtYXAuZXhwb25lbnQgZXhwb25lbnQpXG4gICAgKHNldCEgaGVpZ2h0bWFwLmxhc3QgKC0gcmVzb2x1dGlvbiAxKSlcbiAgICAoemVyby1oZWlnaHRtYXAgaGVpZ2h0bWFwKSkpXG5cblxuOyBSYW5kb20gTm9pc2UgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuKGRlZm4gcmFuZG9tLW5vaXNlIFtoZWlnaHRtYXBdXG4gIChkby10aW1lcyBpIGhlaWdodG1hcC5sZW5ndGhcbiAgICAoc2V0ISAoYWdldCBoZWlnaHRtYXAgaSkgKHJhbmQpKSkpXG5cblxuOyBNaWRwb2ludCBEaXNwbGFjZW1lbnQgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuKGRlZm4gbXBkLWluaXQtY29ybmVycyBbaGVpZ2h0bWFwXVxuICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIDAgMCAocmFuZCkpXG4gIChoZWlnaHRtYXAtc2V0ISBoZWlnaHRtYXAgMCBoZWlnaHRtYXAubGFzdCAocmFuZCkpXG4gIChoZWlnaHRtYXAtc2V0ISBoZWlnaHRtYXAgaGVpZ2h0bWFwLmxhc3QgMCAocmFuZCkpXG4gIChoZWlnaHRtYXAtc2V0ISBoZWlnaHRtYXAgaGVpZ2h0bWFwLmxhc3QgaGVpZ2h0bWFwLmxhc3QgKHJhbmQpKSlcblxuKGRlZm4gbXBkLWRpc3BsYWNlIFtoZWlnaHRtYXAgbHggcnggYnkgdHkgc3ByZWFkXVxuICAobGV0IFtjeCAobWlkcG9pbnQgbHggcngpXG4gICAgICAgIGN5IChtaWRwb2ludCBieSB0eSlcblxuICAgICAgICBib3R0b20tbGVmdCAoaGVpZ2h0bWFwLWdldCBoZWlnaHRtYXAgbHggYnkpXG4gICAgICAgIGJvdHRvbS1yaWdodCAoaGVpZ2h0bWFwLWdldCBoZWlnaHRtYXAgcnggYnkpXG4gICAgICAgIHRvcC1sZWZ0IChoZWlnaHRtYXAtZ2V0IGhlaWdodG1hcCBseCB0eSlcbiAgICAgICAgdG9wLXJpZ2h0IChoZWlnaHRtYXAtZ2V0IGhlaWdodG1hcCByeCB0eSlcblxuICAgICAgICB0b3AgKGF2ZXJhZ2UyIHRvcC1sZWZ0IHRvcC1yaWdodClcbiAgICAgICAgbGVmdCAoYXZlcmFnZTIgYm90dG9tLWxlZnQgdG9wLWxlZnQpXG4gICAgICAgIGJvdHRvbSAoYXZlcmFnZTIgYm90dG9tLWxlZnQgYm90dG9tLXJpZ2h0KVxuICAgICAgICByaWdodCAoYXZlcmFnZTIgYm90dG9tLXJpZ2h0IHRvcC1yaWdodClcbiAgICAgICAgY2VudGVyIChhdmVyYWdlNCB0b3AgbGVmdCBib3R0b20gcmlnaHQpXVxuICAgIChoZWlnaHRtYXAtc2V0ISBoZWlnaHRtYXAgY3ggYnkgKGppdHRlciBib3R0b20gc3ByZWFkKSlcbiAgICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIGN4IHR5IChqaXR0ZXIgdG9wIHNwcmVhZCkpXG4gICAgKGhlaWdodG1hcC1zZXQhIGhlaWdodG1hcCBseCBjeSAoaml0dGVyIGxlZnQgc3ByZWFkKSlcbiAgICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIHJ4IGN5IChqaXR0ZXIgcmlnaHQgc3ByZWFkKSlcbiAgICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIGN4IGN5IChqaXR0ZXIgY2VudGVyIHNwcmVhZCkpKSlcblxuKGRlZm4gbWlkcG9pbnQtZGlzcGxhY2VtZW50IFtoZWlnaHRtYXBdXG4gIChtcGQtaW5pdC1jb3JuZXJzIGhlaWdodG1hcClcbiAgOyAobXBkLWRpc3BsYWNlIGhlaWdodG1hcCAwIGhlaWdodG1hcC5sYXN0IDAgaGVpZ2h0bWFwLmxhc3QgMC4xKVxuICAobG9vcCBbaXRlciAwXG4gICAgICAgICBzcHJlYWQgMC4zXVxuICAgICh3aGVuICg8IGl0ZXIgaGVpZ2h0bWFwLmV4cG9uZW50KVxuICAgICAgKGxldCBbY2h1bmtzIChNYXRoLnBvdyAyIGl0ZXIpXG4gICAgICAgICAgICBjaHVuay13aWR0aCAoLyAoLSBoZWlnaHRtYXAucmVzb2x1dGlvbiAxKSBjaHVua3MpXVxuICAgICAgICAoZG8tbmVzdGVkIHhjaHVuayB5Y2h1bmsgY2h1bmtzXG4gICAgICAgICAgKGxldCBbbGVmdC14ICgqIGNodW5rLXdpZHRoIHhjaHVuaylcbiAgICAgICAgICAgICAgICByaWdodC14ICgrIGxlZnQteCBjaHVuay13aWR0aClcbiAgICAgICAgICAgICAgICBib3R0b20teSAoKiBjaHVuay13aWR0aCB5Y2h1bmspXG4gICAgICAgICAgICAgICAgdG9wLXkgKCsgYm90dG9tLXkgY2h1bmstd2lkdGgpXVxuICAgICAgICAgICAgKG1wZC1kaXNwbGFjZSBoZWlnaHRtYXAgbGVmdC14IHJpZ2h0LXggYm90dG9tLXkgdG9wLXkgc3ByZWFkKSkpKVxuICAgICAgKHJlY3VyICgrIDEgaXRlcikgKCogc3ByZWFkIDAuNSkpKSlcbiAgKG5vcm1hbGl6ZSBoZWlnaHRtYXApKVxuXG5cbihkZWZuIG1pZHBvaW50LWRpc3BsYWNlbWVudC1maW5hbCBbaGVpZ2h0bWFwXVxuICAobXBkLWluaXQtY29ybmVycyBoZWlnaHRtYXApXG4gIDsgKGxldCBbc3ByZWFkIF0pXG4gIChsb29wIFtpdGVyIDBcbiAgICAgICAgIHNwcmVhZCAoKyAwICgudmFsICgkIFwiI2lucHV0LXN0YXJ0aW5nLXNwcmVhZFwiKSkpXVxuICAgICh3aGVuICg8IGl0ZXIgaGVpZ2h0bWFwLmV4cG9uZW50KVxuICAgICAgKGxldCBbY2h1bmtzIChNYXRoLnBvdyAyIGl0ZXIpXG4gICAgICAgICAgICBjaHVuay13aWR0aCAoLyAoLSBoZWlnaHRtYXAucmVzb2x1dGlvbiAxKSBjaHVua3MpXVxuICAgICAgICAoZG8tbmVzdGVkIHhjaHVuayB5Y2h1bmsgY2h1bmtzXG4gICAgICAgICAgKGxldCBbbGVmdC14ICgqIGNodW5rLXdpZHRoIHhjaHVuaylcbiAgICAgICAgICAgICAgICByaWdodC14ICgrIGxlZnQteCBjaHVuay13aWR0aClcbiAgICAgICAgICAgICAgICBib3R0b20teSAoKiBjaHVuay13aWR0aCB5Y2h1bmspXG4gICAgICAgICAgICAgICAgdG9wLXkgKCsgYm90dG9tLXkgY2h1bmstd2lkdGgpXVxuICAgICAgICAgICAgKG1wZC1kaXNwbGFjZSBoZWlnaHRtYXAgbGVmdC14IHJpZ2h0LXggYm90dG9tLXkgdG9wLXkgc3ByZWFkKSkpKVxuICAgICAgKHJlY3VyICgrIDEgaXRlcikgKCogc3ByZWFkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAoKyAwICgudmFsICgkIFwiI2lucHV0LXNwcmVhZC1yZWR1Y3Rpb25cIikpKSkpKSlcbiAgKG5vcm1hbGl6ZSBoZWlnaHRtYXApKVxuXG5cbihkZWZuIG1wZC1kaXNwbGFjZS1kMiBbaGVpZ2h0bWFwIGx4IHJ4IGJ5IHR5IHNwcmVhZF1cbiAgKGxldCBbY3ggKG1pZHBvaW50IGx4IHJ4KVxuICAgICAgICBjeSAobWlkcG9pbnQgYnkgdHkpXG5cbiAgICAgICAgYm90dG9tLWxlZnQgKGhlaWdodG1hcC1nZXQgaGVpZ2h0bWFwIGx4IGJ5KVxuICAgICAgICBib3R0b20tcmlnaHQgKGhlaWdodG1hcC1nZXQgaGVpZ2h0bWFwIHJ4IGJ5KVxuICAgICAgICB0b3AtbGVmdCAoaGVpZ2h0bWFwLWdldCBoZWlnaHRtYXAgbHggdHkpXG4gICAgICAgIHRvcC1yaWdodCAoaGVpZ2h0bWFwLWdldCBoZWlnaHRtYXAgcnggdHkpXG5cbiAgICAgICAgdG9wIChhdmVyYWdlMiB0b3AtbGVmdCB0b3AtcmlnaHQpXG4gICAgICAgIGxlZnQgKGF2ZXJhZ2UyIGJvdHRvbS1sZWZ0IHRvcC1sZWZ0KVxuICAgICAgICBib3R0b20gKGF2ZXJhZ2UyIGJvdHRvbS1sZWZ0IGJvdHRvbS1yaWdodClcbiAgICAgICAgcmlnaHQgKGF2ZXJhZ2UyIGJvdHRvbS1yaWdodCB0b3AtcmlnaHQpXVxuICAgIChoZWlnaHRtYXAtc2V0ISBoZWlnaHRtYXAgY3ggYnkgKGppdHRlciBib3R0b20gc3ByZWFkKSlcbiAgICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIGN4IHR5IChqaXR0ZXIgdG9wIHNwcmVhZCkpXG4gICAgKGhlaWdodG1hcC1zZXQhIGhlaWdodG1hcCBseCBjeSAoaml0dGVyIGxlZnQgc3ByZWFkKSlcbiAgICAoaGVpZ2h0bWFwLXNldCEgaGVpZ2h0bWFwIHJ4IGN5IChqaXR0ZXIgcmlnaHQgc3ByZWFkKSkpKVxuXG4oZGVmbiBtaWRwb2ludC1kaXNwbGFjZW1lbnQtZDEgW2hlaWdodG1hcF1cbiAgKG1wZC1pbml0LWNvcm5lcnMgaGVpZ2h0bWFwKSlcblxuKGRlZm4gbWlkcG9pbnQtZGlzcGxhY2VtZW50LWQyIFtoZWlnaHRtYXBdXG4gIChtcGQtaW5pdC1jb3JuZXJzIGhlaWdodG1hcClcbiAgKG1wZC1kaXNwbGFjZS1kMiBoZWlnaHRtYXBcbiAgICAgICAgICAgICAgICAgICAwIGhlaWdodG1hcC5sYXN0XG4gICAgICAgICAgICAgICAgICAgMCBoZWlnaHRtYXAubGFzdFxuICAgICAgICAgICAgICAgICAgIDAuMSkpXG5cbihkZWZuIG1pZHBvaW50LWRpc3BsYWNlbWVudC1kMyBbaGVpZ2h0bWFwXVxuICAobXBkLWluaXQtY29ybmVycyBoZWlnaHRtYXApXG4gIChtcGQtZGlzcGxhY2UgaGVpZ2h0bWFwXG4gICAgICAgICAgICAgICAgMCBoZWlnaHRtYXAubGFzdFxuICAgICAgICAgICAgICAgIDAgaGVpZ2h0bWFwLmxhc3RcbiAgICAgICAgICAgICAgICAwLjEpKVxuXG5cblxuOyBUaHJlZS5qcyBIZWxwZXJzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuKGRlZm4gbWFrZS1kaXJlY3Rpb25hbC1saWdodCBbXVxuICAobGV0IFtsaWdodCAobmV3IFRIUkVFLkRpcmVjdGlvbmFsTGlnaHQgMHhmZmZmZmYgMSldXG4gICAgKGxpZ2h0LnBvc2l0aW9uLnNldCAxMDAgMCAxNTApXG4gICAgbGlnaHQpKVxuXG4oZGVmbiBtYWtlLWNhbWVyYSBbXVxuICAobGV0IFtjYW1lcmEgKG5ldyBUSFJFRS5QZXJzcGVjdGl2ZUNhbWVyYVxuICAgICAgICAgICAgICAgICAgICA1NSxcbiAgICAgICAgICAgICAgICAgICAgKC8gd2lkdGggaGVpZ2h0KVxuICAgICAgICAgICAgICAgICAgICAwLjEsXG4gICAgICAgICAgICAgICAgICAgIDEwMDApXVxuICAgIChjYW1lcmEucG9zaXRpb24uc2V0IDAgLTEwMCAxNTApXG4gICAgY2FtZXJhKSlcblxuKGRlZm4gbWFrZS1yZW5kZXJlciBbXVxuICAobGV0IFtyZW5kZXJlciAobmV3IFRIUkVFLldlYkdMUmVuZGVyZXIgezphbnRpYWxpYXMgZmFsc2V9KV1cbiAgICAocmVuZGVyZXIuc2V0Q2xlYXJDb2xvciAweGZmZmZmZilcbiAgICAocmVuZGVyZXIuc2V0U2l6ZSB3aWR0aCBoZWlnaHQpXG4gICAgKHJlbmRlcmVyLnNldFBpeGVsUmF0aW8gMilcbiAgICByZW5kZXJlcikpXG5cbihkZWZuIG1ha2UtZ2VvbWV0cnkgW2hlaWdodG1hcF1cbiAgKGxldCBbZ2VvbWV0cnkgKG5ldyBUSFJFRS5QbGFuZUdlb21ldHJ5XG4gICAgICAgICAgICAgICAgICAgICAgdGVycmFpbi1zaXplXG4gICAgICAgICAgICAgICAgICAgICAgdGVycmFpbi1zaXplXG4gICAgICAgICAgICAgICAgICAgICAgKC0gaGVpZ2h0bWFwLnJlc29sdXRpb24gMSlcbiAgICAgICAgICAgICAgICAgICAgICAoLSBoZWlnaHRtYXAucmVzb2x1dGlvbiAxKSldXG4gICAgKHNldCEgZ2VvbWV0cnkuZHluYW1pYyB0cnVlKVxuICAgIGdlb21ldHJ5KSlcblxuKGRlZm4gbWFrZS1jb250cm9scyBbY2FtZXJhIHJlbmRlcmVyXVxuICAobGV0IFtjb250cm9scyAobmV3IFRIUkVFLlRyYWNrYmFsbENvbnRyb2xzIGNhbWVyYSByZW5kZXJlci5kb21FbGVtZW50KV1cbiAgICAoc2V0ISBjb250cm9scy5yb3RhdGVTcGVlZCAxLjQpXG4gICAgKHNldCEgY29udHJvbHMuem9vbVNwZWVkIDAuNSlcbiAgICAoc2V0ISBjb250cm9scy5zdGF0aWNNb3ZpbmcgdHJ1ZSlcbiAgICAoc2V0ISBjb250cm9scy5keW5hbWljRGFtcGluZ0ZhY3RvciAwLjMpXG4gICAgY29udHJvbHMpKVxuXG4oZGVmbiBtYWtlLXBsYW5lIFtnZW9tZXRyeV1cbiAgKGxldCBbbWF0ZXJpYWwgKG5ldyBUSFJFRS5NZXNoTGFtYmVydE1hdGVyaWFsXG4gICAgICAgICAgICAgICAgICAgICAgezp3aXJlZnJhbWUgd2lyZWZyYW1lXG4gICAgICAgICAgICAgICAgICAgICAgIDp3aXJlZnJhbWVMaW5ld2lkdGggd2lyZWZyYW1lLXdpZHRoXG4gICAgICAgICAgICAgICAgICAgICAgIDpjb2xvciAweDAwYmIwMH0pXVxuICAgIChuZXcgVEhSRUUuTWVzaCBnZW9tZXRyeSBtYXRlcmlhbCkpKVxuXG5cbihkZWZuIGF0dGFjaC10by1kb20gW3JlbmRlcmVyIGVsLW5hbWUgcmVmcmVzaC1mbl1cbiAgKGxldCBbY29udGFpbmVyIChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCBlbC1uYW1lKVxuICAgICAgICBzZXR0aW5ncyAoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCBcImRpdlwiKVxuICAgICAgICByZWZyZXNoLWJ1dHRvbiAoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCBcImJ1dHRvblwiKVxuICAgICAgICBidXR0b24tdGV4dCAoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUgXCJSZWZyZXNoXCIpXG4gICAgICAgIGNhbmNlbC1zY3JvbGwgKGZuIFtlXSAoLnByZXZlbnREZWZhdWx0IGUpKV1cbiAgICAoc2V0ISByZWZyZXNoLWJ1dHRvbi5vbmNsaWNrIHJlZnJlc2gtZm4pXG4gICAgKHNldCEgcmVuZGVyZXIuZG9tRWxlbWVudC5vbm1vdXNld2hlZWwgY2FuY2VsLXNjcm9sbClcbiAgICAocmVuZGVyZXIuZG9tRWxlbWVudC5hZGRFdmVudExpc3RlbmVyIFwiTW96TW91c2VQaXhlbFNjcm9sbFwiIGNhbmNlbC1zY3JvbGwgZmFsc2UpXG4gICAgKC5hcHBlbmRDaGlsZCByZWZyZXNoLWJ1dHRvbiBidXR0b24tdGV4dClcbiAgICAoLmFwcGVuZENoaWxkIGNvbnRhaW5lciByZW5kZXJlci5kb21FbGVtZW50KVxuICAgICguYXBwZW5kQ2hpbGQgY29udGFpbmVyIHNldHRpbmdzKVxuICAgICguYXBwZW5kQ2hpbGQgc2V0dGluZ3MgcmVmcmVzaC1idXR0b24pKSlcblxuKGRlZm4gdXBkYXRlLWdlb21ldHJ5IFtnZW9tZXRyeSBoZWlnaHRtYXBdXG4gIChkby10aW1lcyBpIGdlb21ldHJ5LnZlcnRpY2VzLmxlbmd0aFxuICAgIChzZXQhICguLXogKGFnZXQgZ2VvbWV0cnkudmVydGljZXMgaSkpXG4gICAgICAoKiB0ZXJyYWluLWhlaWdodCAoYWdldCBoZWlnaHRtYXAgaSkpKSlcbiAgKHNldCEgZ2VvbWV0cnkudmVydGljZXNOZWVkVXBkYXRlIHRydWUpXG4gIChnZW9tZXRyeS5jb21wdXRlRmFjZU5vcm1hbHMpXG4gIChnZW9tZXRyeS5jb21wdXRlVmVydGV4Tm9ybWFscylcbiAgKGdlb21ldHJ5LmNvbXB1dGVNb3JwaE5vcm1hbHMpXG4gIGdlb21ldHJ5KVxuXG5cbjsgTWFpbiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbihkZWZuIG1ha2UtZGVtbyBbZWxlbWVudC1pZCBhbGdvcml0aG0gc2l6ZV1cbiAgKGRlZiBzY2VuZSAobmV3IFRIUkVFLlNjZW5lKSlcbiAgKHNjZW5lLmFkZCAobmV3IFRIUkVFLkF4aXNIZWxwZXIgMTAwKSlcblxuICAoZGVmIGNsb2NrIChuZXcgVEhSRUUuQ2xvY2spKVxuICAoZGVmIGNhbWVyYSAobWFrZS1jYW1lcmEpKVxuICAoZGVmIHJlbmRlcmVyIChtYWtlLXJlbmRlcmVyKSlcbiAgKGRlZiBnZW9tZXRyeSAobWFrZS1nZW9tZXRyeSAobWFrZS1oZWlnaHRtYXAgc2l6ZSkpKVxuXG4gIChzY2VuZS5hZGQgKG1ha2UtZGlyZWN0aW9uYWwtbGlnaHQpKVxuICAoc2NlbmUuYWRkIChuZXcgVEhSRUUuQW1iaWVudExpZ2h0IDB4ZmZmZmZmIDAuMDUpKVxuICAoc2NlbmUuYWRkIChtYWtlLXBsYW5lIGdlb21ldHJ5KSlcblxuICAoZGVmbiByZWZyZXNoIFtdXG4gICAgKGwgXCJSZWZyZXNoaW5nID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cIilcbiAgICAobGV0IFtoZWlnaHRtYXAgKG1ha2UtaGVpZ2h0bWFwIHNpemUpXVxuICAgICAgKGwgXCJHZW5lcmF0aW5nIHRlcnJhaW4uLi5cIilcbiAgICAgICh0aW1lIChhbGdvcml0aG0gaGVpZ2h0bWFwKSlcbiAgICAgIChsIFwiUmVmcmVzaGluZyBnZW9tZXRyeS4uLlwiKVxuICAgICAgKHRpbWUgKHVwZGF0ZS1nZW9tZXRyeSBnZW9tZXRyeSBoZWlnaHRtYXApKVxuICAgICAgKGwgXCJEb25lIVwiKSkpXG5cbiAgKGF0dGFjaC10by1kb20gcmVuZGVyZXIgZWxlbWVudC1pZCByZWZyZXNoKVxuICAoZGVmIGNvbnRyb2xzIChtYWtlLWNvbnRyb2xzIGNhbWVyYSByZW5kZXJlcikpXG5cbiAgKGRlZm4gcmVuZGVyIFtdXG4gICAgKGxldCBbZGVsdGEgKGNsb2NrLmdldERlbHRhKV1cbiAgICAgIChyZXF1ZXN0QW5pbWF0aW9uRnJhbWUgcmVuZGVyKVxuICAgICAgKC51cGRhdGUgY29udHJvbHMgZGVsdGEpXG4gICAgICAocmVuZGVyZXIucmVuZGVyIHNjZW5lIGNhbWVyYSkpKVxuXG4gIChyZW5kZXIpXG5cbiAgbmlsKVxuXG4oZGVmbiBtYWtlLWZpbmFsIFtlbGVtZW50LWlkXVxuICAoZGVmIHNjZW5lIChuZXcgVEhSRUUuU2NlbmUpKVxuICAoc2NlbmUuYWRkIChuZXcgVEhSRUUuQXhpc0hlbHBlciAxMDApKVxuXG4gIChkZWYgY2xvY2sgKG5ldyBUSFJFRS5DbG9jaykpXG4gIChkZWYgY2FtZXJhIChtYWtlLWNhbWVyYSkpXG4gIChkZWYgcmVuZGVyZXIgKG1ha2UtcmVuZGVyZXIpKVxuICAoZGVmIGhlaWdodG1hcCAobWFrZS1oZWlnaHRtYXAgKC52YWwgKCQgXCIjaW5wdXQtZXhwb25lbnRcIikpKSlcbiAgKGRlZiBnZW9tZXRyeSAobWFrZS1nZW9tZXRyeSBoZWlnaHRtYXApKVxuICAoZGVmIHBsYW5lIChtYWtlLXBsYW5lIGdlb21ldHJ5KSlcblxuICAoc2NlbmUuYWRkIChtYWtlLWRpcmVjdGlvbmFsLWxpZ2h0KSlcbiAgKHNjZW5lLmFkZCAobmV3IFRIUkVFLkFtYmllbnRMaWdodCAweGZmZmZmZiAwLjA1KSlcbiAgKHNjZW5lLmFkZCBwbGFuZSlcblxuICAoZGVmbiByZWZyZXNoIFtdXG4gICAgKGwgXCJSZWZyZXNoaW5nID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cIilcbiAgICAoc2NlbmUucmVtb3ZlIHBsYW5lKVxuICAgIChzZXQhIGhlaWdodG1hcCAobWFrZS1oZWlnaHRtYXAgKC52YWwgKCQgXCIjaW5wdXQtZXhwb25lbnRcIikpKSlcbiAgICAoc2V0ISBnZW9tZXRyeSAobWFrZS1nZW9tZXRyeSBoZWlnaHRtYXApKVxuICAgIChzZXQhIHBsYW5lIChtYWtlLXBsYW5lIGdlb21ldHJ5KSlcbiAgICAoc2NlbmUuYWRkIHBsYW5lKVxuICAgIChsIFwiR2VuZXJhdGluZyB0ZXJyYWluLi4uXCIpXG4gICAgKHRpbWUgKG1pZHBvaW50LWRpc3BsYWNlbWVudC1maW5hbCBoZWlnaHRtYXApKVxuICAgIChsIFwiUmVmcmVzaGluZyBnZW9tZXRyeS4uLlwiKVxuICAgICh0aW1lICh1cGRhdGUtZ2VvbWV0cnkgZ2VvbWV0cnkgaGVpZ2h0bWFwKSlcbiAgICAobCBcIkRvbmUhXCIpKVxuXG4gIChhdHRhY2gtdG8tZG9tIHJlbmRlcmVyIGVsZW1lbnQtaWQgcmVmcmVzaClcbiAgKGRlZiBjb250cm9scyAobWFrZS1jb250cm9scyBjYW1lcmEgcmVuZGVyZXIpKVxuXG4gIChkZWZuIHJlbmRlciBbXVxuICAgIChsZXQgW2RlbHRhIChjbG9jay5nZXREZWx0YSldXG4gICAgICAocmVxdWVzdEFuaW1hdGlvbkZyYW1lIHJlbmRlcilcbiAgICAgICgudXBkYXRlIGNvbnRyb2xzIGRlbHRhKVxuICAgICAgKHJlbmRlcmVyLnJlbmRlciBzY2VuZSBjYW1lcmEpKSlcblxuICAocmVuZGVyKVxuXG4gIG5pbClcblxuXG4oZGVmbiBydW4gW11cbiAgKG1ha2UtZGVtbyBcImRlbW8tcmFuZG9tXCIgcmFuZG9tLW5vaXNlIDcpXG4gIChtYWtlLWRlbW8gXCJkZW1vLW1wZC0xXCIgbWlkcG9pbnQtZGlzcGxhY2VtZW50LWQxIDIpXG4gIChtYWtlLWRlbW8gXCJkZW1vLW1wZC0yXCIgbWlkcG9pbnQtZGlzcGxhY2VtZW50LWQyIDIpXG4gIChtYWtlLWRlbW8gXCJkZW1vLW1wZC0zXCIgbWlkcG9pbnQtZGlzcGxhY2VtZW50LWQzIDIpXG4gIChtYWtlLWRlbW8gXCJkZW1vLW1wZC00XCIgbWlkcG9pbnQtZGlzcGxhY2VtZW50IDMpXG4gIChtYWtlLWZpbmFsIFwiZGVtby1maW5hbFwiKVxuICA7IChtYWtlLWRlbW8gXCJkZW1vLW1pZHBvaW50XCIgbWlkcG9pbnQtZGlzcGxhY2VtZW50KVxuICA7IChtYWtlLWRlbW8gXCJkZW1vLWRpYW1vbmRcIiBkaWFtb25kLXNxdWFyZSlcblxuICApXG5cbigkIHJ1bilcblxuXG47IHZpbTogbHcrPWRvLXRpbWVzIGx3Kz1kby1uZXN0ZWQgOlxuIl19
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/media/js/wisp/terrain1.wisp	Sun Feb 28 11:51:50 2016 +0000
@@ -0,0 +1,392 @@
+; Constants -------------------------------------------------------------------
+(def width 610)
+(def height 400)
+(def wireframe true)
+(def wireframe-width 1.2)
+(def terrain-height 50)
+(def terrain-size 100)
+
+; General Utilities -----------------------------------------------------------
+(defmacro when [condition & body]
+  `(if ~condition
+     (do ~@body)))
+
+(defmacro do-times [varname limit & body]
+  (let [end (gensym)]
+    `(let [~end ~limit]
+       (loop [~varname 0]
+         (when (< ~varname ~end)
+           ~@body
+           (recur (+ 1 ~varname)))))))
+
+(defmacro do-nested [xname yname width & body]
+  (let [iterations (gensym)]
+    `(let [~iterations ~width]
+       (do-times ~xname ~iterations
+         (do-times ~yname ~iterations
+           ~@body)))))
+
+(defmacro inc! [place]
+  `(set! ~place (+ ~place 1)))
+
+(defmacro add! [place amount]
+  `(set! ~place (+ ~place ~amount)))
+
+(defmacro time [& body]
+  (let [start (gensym)
+        end (gensym)
+        result (gensym)]
+    `(let [~start (.getTime (new Date))
+           ~result (do ~@body)
+           ~end (.getTime (new Date))]
+       (l (+ "Elapsed time: " (- ~end ~start) "ms."))
+       ~result)))
+
+(defn l [v]
+  (console.log v))
+
+
+(defn midpoint [a b]
+  (/ (+ a b) 2))
+
+(defn average2 [a b]
+  (/ (+ a b) 2))
+
+(defn average4 [a b c d]
+  (/ (+ a b c d) 4))
+
+(defn safe-average [a b c d]
+  (let [total 0 count 0]
+    (when a (add! total a) (inc! count))
+    (when b (add! total b) (inc! count))
+    (when c (add! total c) (inc! count))
+    (when d (add! total d) (inc! count))
+    (/ total count)))
+
+
+(defn rand []
+  (Math.random))
+
+(defn rand-around-zero [spread]
+  (- (* spread (rand) 2) spread))
+
+
+(defn jitter [value spread]
+  (+ value (rand-around-zero spread)))
+
+
+; Heightmap Helpers -----------------------------------------------------------
+(defmacro heightmap-get [hm x y]
+  `(aget ~hm (+ (* ~y (.-resolution ~hm)) ~x)))
+
+(defn heightmap-get-safe [hm x y]
+  (when (and (<= 0 x hm.last)
+             (<= 0 y hm.last))
+    (heightmap-get hm x y)))
+
+(defmacro heightmap-set! [hm x y val]
+  `(set! (heightmap-get ~hm ~x ~y) ~val))
+
+
+(defn normalize [hm]
+  (let [max (- Infinity)
+        min Infinity]
+    (do-times i hm.length
+      (let [el (aget hm i)]
+        (when (< max el) (set! max el))
+        (when (> min el) (set! min el))))
+    (let [span (- max min)]
+      (do-times i hm.length
+        (set! (aget hm i)
+          (/ (- (aget hm i) min)
+             span))))))
+
+(defn zero-heightmap [heightmap]
+  (do-times i heightmap.length
+    (set! (aget heightmap i) 0.0))
+  heightmap)
+
+(defn make-heightmap [exponent]
+  (let [resolution (+ 1 (Math.pow 2 exponent))]
+    (l (+ "Creating " resolution " by " resolution " heightmap..."))
+    (def heightmap
+      (new Array (* resolution resolution)))
+    (set! heightmap.resolution resolution)
+    (set! heightmap.exponent exponent)
+    (set! heightmap.last (- resolution 1))
+    (zero-heightmap heightmap)))
+
+
+; Random Noise ----------------------------------------------------------------
+(defn random-noise [heightmap]
+  (do-times i heightmap.length
+    (set! (aget heightmap i) (rand))))
+
+
+; Midpoint Displacement -------------------------------------------------------
+(defn mpd-init-corners [heightmap]
+  (heightmap-set! heightmap 0 0 (rand))
+  (heightmap-set! heightmap 0 heightmap.last (rand))
+  (heightmap-set! heightmap heightmap.last 0 (rand))
+  (heightmap-set! heightmap heightmap.last heightmap.last (rand)))
+
+(defn mpd-displace [heightmap lx rx by ty spread]
+  (let [cx (midpoint lx rx)
+        cy (midpoint by ty)
+
+        bottom-left (heightmap-get heightmap lx by)
+        bottom-right (heightmap-get heightmap rx by)
+        top-left (heightmap-get heightmap lx ty)
+        top-right (heightmap-get heightmap rx ty)
+
+        top (average2 top-left top-right)
+        left (average2 bottom-left top-left)
+        bottom (average2 bottom-left bottom-right)
+        right (average2 bottom-right top-right)
+        center (average4 top left bottom right)]
+    (heightmap-set! heightmap cx by (jitter bottom spread))
+    (heightmap-set! heightmap cx ty (jitter top spread))
+    (heightmap-set! heightmap lx cy (jitter left spread))
+    (heightmap-set! heightmap rx cy (jitter right spread))
+    (heightmap-set! heightmap cx cy (jitter center spread))))
+
+(defn midpoint-displacement [heightmap]
+  (mpd-init-corners heightmap)
+  ; (mpd-displace heightmap 0 heightmap.last 0 heightmap.last 0.1)
+  (loop [iter 0
+         spread 0.3]
+    (when (< iter heightmap.exponent)
+      (let [chunks (Math.pow 2 iter)
+            chunk-width (/ (- heightmap.resolution 1) chunks)]
+        (do-nested xchunk ychunk chunks
+          (let [left-x (* chunk-width xchunk)
+                right-x (+ left-x chunk-width)
+                bottom-y (* chunk-width ychunk)
+                top-y (+ bottom-y chunk-width)]
+            (mpd-displace heightmap left-x right-x bottom-y top-y spread))))
+      (recur (+ 1 iter) (* spread 0.5))))
+  (normalize heightmap))
+
+
+(defn midpoint-displacement-final [heightmap]
+  (mpd-init-corners heightmap)
+  ; (let [spread ])
+  (loop [iter 0
+         spread (+ 0 (.val ($ "#input-starting-spread")))]
+    (when (< iter heightmap.exponent)
+      (let [chunks (Math.pow 2 iter)
+            chunk-width (/ (- heightmap.resolution 1) chunks)]
+        (do-nested xchunk ychunk chunks
+          (let [left-x (* chunk-width xchunk)
+                right-x (+ left-x chunk-width)
+                bottom-y (* chunk-width ychunk)
+                top-y (+ bottom-y chunk-width)]
+            (mpd-displace heightmap left-x right-x bottom-y top-y spread))))
+      (recur (+ 1 iter) (* spread
+                           (+ 0 (.val ($ "#input-spread-reduction")))))))
+  (normalize heightmap))
+
+
+(defn mpd-displace-d2 [heightmap lx rx by ty spread]
+  (let [cx (midpoint lx rx)
+        cy (midpoint by ty)
+
+        bottom-left (heightmap-get heightmap lx by)
+        bottom-right (heightmap-get heightmap rx by)
+        top-left (heightmap-get heightmap lx ty)
+        top-right (heightmap-get heightmap rx ty)
+
+        top (average2 top-left top-right)
+        left (average2 bottom-left top-left)
+        bottom (average2 bottom-left bottom-right)
+        right (average2 bottom-right top-right)]
+    (heightmap-set! heightmap cx by (jitter bottom spread))
+    (heightmap-set! heightmap cx ty (jitter top spread))
+    (heightmap-set! heightmap lx cy (jitter left spread))
+    (heightmap-set! heightmap rx cy (jitter right spread))))
+
+(defn midpoint-displacement-d1 [heightmap]
+  (mpd-init-corners heightmap))
+
+(defn midpoint-displacement-d2 [heightmap]
+  (mpd-init-corners heightmap)
+  (mpd-displace-d2 heightmap
+                   0 heightmap.last
+                   0 heightmap.last
+                   0.1))
+
+(defn midpoint-displacement-d3 [heightmap]
+  (mpd-init-corners heightmap)
+  (mpd-displace heightmap
+                0 heightmap.last
+                0 heightmap.last
+                0.1))
+
+
+
+; Three.js Helpers ------------------------------------------------------------
+(defn make-directional-light []
+  (let [light (new THREE.DirectionalLight 0xffffff 1)]
+    (light.position.set 100 0 150)
+    light))
+
+(defn make-camera []
+  (let [camera (new THREE.PerspectiveCamera
+                    55,
+                    (/ width height)
+                    0.1,
+                    1000)]
+    (camera.position.set 0 -100 150)
+    camera))
+
+(defn make-renderer []
+  (let [renderer (new THREE.WebGLRenderer {:antialias false})]
+    (renderer.setClearColor 0xffffff)
+    (renderer.setSize width height)
+    (renderer.setPixelRatio 2)
+    renderer))
+
+(defn make-geometry [heightmap]
+  (let [geometry (new THREE.PlaneGeometry
+                      terrain-size
+                      terrain-size
+                      (- heightmap.resolution 1)
+                      (- heightmap.resolution 1))]
+    (set! geometry.dynamic true)
+    geometry))
+
+(defn make-controls [camera renderer]
+  (let [controls (new THREE.TrackballControls camera renderer.domElement)]
+    (set! controls.rotateSpeed 1.4)
+    (set! controls.zoomSpeed 0.5)
+    (set! controls.staticMoving true)
+    (set! controls.dynamicDampingFactor 0.3)
+    controls))
+
+(defn make-plane [geometry]
+  (let [material (new THREE.MeshLambertMaterial
+                      {:wireframe wireframe
+                       :wireframeLinewidth wireframe-width
+                       :color 0x00bb00})]
+    (new THREE.Mesh geometry material)))
+
+
+(defn attach-to-dom [renderer el-name refresh-fn]
+  (let [container (document.getElementById el-name)
+        settings (document.createElement "div")
+        refresh-button (document.createElement "button")
+        button-text (document.createTextNode "Refresh")
+        cancel-scroll (fn [e] (.preventDefault e))]
+    (set! refresh-button.onclick refresh-fn)
+    (set! renderer.domElement.onmousewheel cancel-scroll)
+    (renderer.domElement.addEventListener "MozMousePixelScroll" cancel-scroll false)
+    (.appendChild refresh-button button-text)
+    (.appendChild container renderer.domElement)
+    (.appendChild container settings)
+    (.appendChild settings refresh-button)))
+
+(defn update-geometry [geometry heightmap]
+  (do-times i geometry.vertices.length
+    (set! (.-z (aget geometry.vertices i))
+      (* terrain-height (aget heightmap i))))
+  (set! geometry.verticesNeedUpdate true)
+  (geometry.computeFaceNormals)
+  (geometry.computeVertexNormals)
+  (geometry.computeMorphNormals)
+  geometry)
+
+
+; Main ------------------------------------------------------------------------
+(defn make-demo [element-id algorithm size]
+  (def scene (new THREE.Scene))
+  (scene.add (new THREE.AxisHelper 100))
+
+  (def clock (new THREE.Clock))
+  (def camera (make-camera))
+  (def renderer (make-renderer))
+  (def geometry (make-geometry (make-heightmap size)))
+
+  (scene.add (make-directional-light))
+  (scene.add (new THREE.AmbientLight 0xffffff 0.05))
+  (scene.add (make-plane geometry))
+
+  (defn refresh []
+    (l "Refreshing ========================================")
+    (let [heightmap (make-heightmap size)]
+      (l "Generating terrain...")
+      (time (algorithm heightmap))
+      (l "Refreshing geometry...")
+      (time (update-geometry geometry heightmap))
+      (l "Done!")))
+
+  (attach-to-dom renderer element-id refresh)
+  (def controls (make-controls camera renderer))
+
+  (defn render []
+    (let [delta (clock.getDelta)]
+      (requestAnimationFrame render)
+      (.update controls delta)
+      (renderer.render scene camera)))
+
+  (render)
+
+  nil)
+
+(defn make-final [element-id]
+  (def scene (new THREE.Scene))
+  (scene.add (new THREE.AxisHelper 100))
+
+  (def clock (new THREE.Clock))
+  (def camera (make-camera))
+  (def renderer (make-renderer))
+  (def heightmap (make-heightmap (.val ($ "#input-exponent"))))
+  (def geometry (make-geometry heightmap))
+  (def plane (make-plane geometry))
+
+  (scene.add (make-directional-light))
+  (scene.add (new THREE.AmbientLight 0xffffff 0.05))
+  (scene.add plane)
+
+  (defn refresh []
+    (l "Refreshing ========================================")
+    (scene.remove plane)
+    (set! heightmap (make-heightmap (.val ($ "#input-exponent"))))
+    (set! geometry (make-geometry heightmap))
+    (set! plane (make-plane geometry))
+    (scene.add plane)
+    (l "Generating terrain...")
+    (time (midpoint-displacement-final heightmap))
+    (l "Refreshing geometry...")
+    (time (update-geometry geometry heightmap))
+    (l "Done!"))
+
+  (attach-to-dom renderer element-id refresh)
+  (def controls (make-controls camera renderer))
+
+  (defn render []
+    (let [delta (clock.getDelta)]
+      (requestAnimationFrame render)
+      (.update controls delta)
+      (renderer.render scene camera)))
+
+  (render)
+
+  nil)
+
+
+(defn run []
+  (make-demo "demo-random" random-noise 7)
+  (make-demo "demo-mpd-1" midpoint-displacement-d1 2)
+  (make-demo "demo-mpd-2" midpoint-displacement-d2 2)
+  (make-demo "demo-mpd-3" midpoint-displacement-d3 2)
+  (make-demo "demo-mpd-4" midpoint-displacement 3)
+  (make-final "demo-final")
+  ; (make-demo "demo-midpoint" midpoint-displacement)
+  ; (make-demo "demo-diamond" diamond-square)
+
+  )
+
+($ run)
+
+
+; vim: lw+=do-times lw+=do-nested :
--- a/requirements.txt	Fri Feb 19 19:48:12 2016 +0000
+++ b/requirements.txt	Sun Feb 28 11:51:50 2016 +0000
@@ -1,5 +1,4 @@
 -e git://github.com/django/django.git@stable/1.1.x#egg=django
--e git://github.com/fabric/fabric.git@0.9rc2#egg=fabric
 -e svn+http://typogrify.googlecode.com/svn/trunk/#egg=typogrify
 -e hg+http://bitbucket.org/cherrypy/cherrypy@cherrypy-3.2.0rc1#egg=cherrypy
 -e git://github.com/waylan/python-markdown.git#egg=markdown
--- a/settings.py	Fri Feb 19 19:48:12 2016 +0000
+++ b/settings.py	Sun Feb 28 11:51:50 2016 +0000
@@ -46,9 +46,6 @@
         '.png': ('hydeengine.media_processors.Thumbnail',),
         '.jpg': ('hydeengine.media_processors.Thumbnail',),
     },
-    'js/': {
-        '.wisp': ('custom.processors.Wisp',),
-    },
 }
 
 CONTENT_PROCESSORS = {}