Skip to content

Instantly share code, notes, and snippets.

@Mocker
Forked from KdotJPG/OpenSimplex2S.java
Last active May 31, 2020 01:37
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Mocker/787fbc4f8d49dab88259 to your computer and use it in GitHub Desktop.
Save Mocker/787fbc4f8d49dab88259 to your computer and use it in GitHub Desktop.
OpenSimplexNoise ported to Javascript
/*
* OpenSimplex (Simplectic) Noise in Javascript.
* original by Kurt Spencer (https://gist.github.com/KdotJPG/b1270127455a94ac5d19)
* ported to Javascript (ASM) by Ryan Guthrie
*
*/
function OpenSimplexASM(stdlib, foreign, heap ) {
"use asm";
STRETCH_CONSTANT_2D = -0.211324865405187; //(1/Math.sqrt(2+1)-1)/2;
SQUISH_CONSTANT_2D = +0.366025403784439; //(Math.sqrt(2+1)-1)/2;
STRETCH_CONSTANT_3D = -1.0 / 6; //(1/Math.sqrt(3+1)-1)/3;
SQUISH_CONSTANT_3D = +1.0 / 3; //(Math.sqrt(3+1)-1)/3;
STRETCH_CONSTANT_4D = -0.138196601125011; //(1/Math.sqrt(4+1)-1)/4;
SQUISH_CONSTANT_4D = +0.309016994374947; //(Math.sqrt(4+1)-1)/4;
NORM_CONSTANT_2D = +47;
NORM_CONSTANT_3D = +103;
NORM_CONSTANT_4D = +30;
DEFAULT_SEED = 0|0;
perm = new stdlib.Int16Array();
permGradIndex3D = new stdlib.Int16Array();
//gradients2D = new Int8Array(16);
gradients2D = new Int8Array([
5, 2, 2, 5,
-5, 2, -2, 5,
5, -2, 2, -5,
-5, -2, -2, -5,
]);
//gradients3D = new Int8Array(72);
gradients3D = new Int8Array([
-11, 4, 4, -4, 11, 4, -4, 4, 11,
11, 4, 4, 4, 11, 4, 4, 4, 11,
-11, -4, 4, -4, -11, 4, -4, -4, 11,
11, -4, 4, 4, -11, 4, 4, -4, 11,
-11, 4, -4, -4, 11, -4, -4, 4, -11,
11, 4, -4, 4, 11, -4, 4, 4, -11,
-11, -4, -4, -4, -11, -4, -4, -4, -11,
11, -4, -4, 4, -11, -4, 4, -4, -11,
]);
function fastFloor(x) {
x = +x;
var xi = x|0;
var r = 0|0;
r = x < xi ? xi - 1 :xi;
return r;
}
function extrapolate2d(xsb, ysb, dx, dy) {
xsb = xsb|0;
ysb = ysb|0;
dx = +dx;
dy = +dy;
var index = 0|0;
index = index = perm[(perm[xsb & 0xFF] + ysb) & 0xFF] & 0x0E;
var ret = +0.0;
ret = gradients3D[index] * dx
+ gradients3D[index + 1|0] * dy;
return ret;
}
function extrapolate3d(xsb, ysb, zsb, dx, dy, dz) {
xsb = xsb|0;
ysb = ysb|0;
zsb = zsb|0;
dx = +dx;
dy = +dy;
dz = +dz;
var index = 0|0;
index = permGradIndex3D[(perm[(perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF];
var ret = +0.0;
ret = gradients3D[index] * dx
+ gradients3D[index + 1|0] * dy
+ gradients3D[index + 2|0] * dz;
return +(xsb * dx);
}
function init(seed) {
seed = seed? seed|0 : DEFAULT_SEED;
console.log("Seed! "+seed);
perm = new stdlib.Int16Array(256);
permGradIndex3D = new stdlib.Int16Array(256);
var source = new stdlib.Int16Array(256);
var i = 0|0;
for( i = 0|0; i < 256; i++) {
source[i] = i;
}
seed = seed * 6364136223846793005|0 + 1442695040888963407|0;
seed = seed * 6364136223846793005|0 + 1442695040888963407|0;
seed = seed * 6364136223846793005|0 + 1442695040888963407|0;
for (i = 255|0; i >= 0; i--) {
seed = seed * 6364136223846793005|0 + 1442695040888963407|0;
var r = 0|0;
r = ((seed + 31|0) % (i + 1|0));
if (r < 0)
r += (i + 1);
perm[i] = source[r];
//console.log(i+" : "+source[r]);
permGradIndex3D[i] = ((perm[i] % (gradients3D.length / 3|0)) * 3|0);
source[r] = source[i];
}
}
function eval2d(x, y) {
x = +x;
y = +y;
//Place input coordinates onto grid.
/**double**/ stretchOffset = (x + y) * STRETCH_CONSTANT_2D;
/**double**/ xs = x + stretchOffset;
/**double**/ ys = y + stretchOffset;
//Floor to get grid coordinates of rhombus (stretched square) super-cell origin.
/**int**/ xsb = fastFloor(xs);
/**int**/ ysb = fastFloor(ys);
//Skew out to get actual coordinates of rhombus origin. We'll need these later.
/**double**/ squishOffset = (xsb + ysb) * SQUISH_CONSTANT_2D;
/**double**/ xb = xsb + squishOffset;
/**double**/ yb = ysb + squishOffset;
//Compute grid coordinates relative to rhombus origin.
/**double**/ xins = xs - xsb;
/**double**/ yins = ys - ysb;
//Sum those together to get a value that determines which region we're in.
/**double**/ inSum = xins + yins;
//Positions relative to origin point.
/**double**/ dx0 = x - xb;
/**double**/ dy0 = y - yb;
//We'll be defining these inside the next block and using them afterwards.
/**double**/ var dx_ext = +0.0; var dy_ext = +0.0;
/**int**/ var xsv_ext = 0|0; var ysv_ext = +0.0;
/**double**/ value = 0;
//Contribution (1,0)
/**double**/ dx1 = dx0 - 1 - SQUISH_CONSTANT_2D;
/**double**/ dy1 = dy0 - 0 - SQUISH_CONSTANT_2D;
/**double**/ attn1 = 2 - dx1 * dx1 - dy1 * dy1;
if (attn1 > 0) {
attn1 *= attn1;
value += attn1 * attn1 * extrapolate2d(xsb + 1, ysb + 0, dx1, dy1);
}
//Contribution (0,1)
/**double**/ dx2 = dx0 - 0 - SQUISH_CONSTANT_2D;
/**double**/ dy2 = dy0 - 1 - SQUISH_CONSTANT_2D;
/**double**/ attn2 = 2 - dx2 * dx2 - dy2 * dy2;
if (attn2 > 0) {
attn2 *= attn2;
value += attn2 * attn2 * extrapolate2d(xsb + 0, ysb + 1, dx2, dy2);
}
if (inSum <= 1) { //We're inside the triangle (2-Simplex) at (0,0)
/**double**/ zins = 1 - inSum;
if (zins > xins || zins > yins) { //(0,0) is one of the closest two triangular vertices
if (xins > yins) {
xsv_ext = xsb + 1;
ysv_ext = ysb - 1;
dx_ext = dx0 - 1;
dy_ext = dy0 + 1;
} else {
xsv_ext = xsb - 1;
ysv_ext = ysb + 1;
dx_ext = dx0 + 1;
dy_ext = dy0 - 1;
}
} else { //(1,0) and (0,1) are the closest two vertices.
xsv_ext = xsb + 1;
ysv_ext = ysb + 1;
dx_ext = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
dy_ext = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
}
} else { //We're inside the triangle (2-Simplex) at (1,1)
/**double**/ zins = 2 - inSum;
if (zins < xins || zins < yins) { //(0,0) is one of the closest two triangular vertices
if (xins > yins) {
xsv_ext = xsb + 2;
ysv_ext = ysb + 0;
dx_ext = dx0 - 2 - 2 * SQUISH_CONSTANT_2D;
dy_ext = dy0 + 0 - 2 * SQUISH_CONSTANT_2D;
} else {
xsv_ext = xsb + 0;
ysv_ext = ysb + 2;
dx_ext = dx0 + 0 - 2 * SQUISH_CONSTANT_2D;
dy_ext = dy0 - 2 - 2 * SQUISH_CONSTANT_2D;
}
} else { //(1,0) and (0,1) are the closest two vertices.
dx_ext = dx0;
dy_ext = dy0;
xsv_ext = xsb;
ysv_ext = ysb;
}
xsb += 1;
ysb += 1;
dx0 = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
dy0 = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
}
//Contribution (0,0) or (1,1)
/**double**/ attn0 = 2 - dx0 * dx0 - dy0 * dy0;
if (attn0 > 0) {
attn0 *= attn0;
value += attn0 * attn0 * extrapolate2d(xsb, ysb, dx0, dy0);
}
//Extra Vertex
/**double**/ attn_ext = 2 - dx_ext * dx_ext - dy_ext * dy_ext;
if (attn_ext > 0) {
attn_ext *= attn_ext;
value += attn_ext * attn_ext * extrapolate2d(xsv_ext, ysv_ext, dx_ext, dy_ext);
}
return value / NORM_CONSTANT_2D;
}
function eval3d(x, y, z) {
x = +x;
y = +y;
z = +z;
return +0.0;
}
function getPerm() {
return perm;
}
return {
init : init,
eval2d : eval2d,
eval3d : eval3d,
permGradIndex3D : permGradIndex3D,
getPerm : getPerm,
fastFloor : fastFloor,
extrapolate2d : extrapolate2d,
extrapolate3d : extrapolate3d
};
}
/*
* OpenSimplex (Simplectic) Noise in Javascript.
* original by Kurt Spencer (https://gist.github.com/KdotJPG/b1270127455a94ac5d19)
* ported to Javascript by Ryan Guthrie
*
*/
//function OpenSimplexNoise(seed){
var OpenSimplexNoise = function(seed) {
STRETCH_CONSTANT_2D = -0.211324865405187; //(1/Math.sqrt(2+1)-1)/2;
SQUISH_CONSTANT_2D = 0.366025403784439; //(Math.sqrt(2+1)-1)/2;
STRETCH_CONSTANT_3D = -1.0 / 6; //(1/Math.sqrt(3+1)-1)/3;
SQUISH_CONSTANT_3D = 1.0 / 3; //(Math.sqrt(3+1)-1)/3;
STRETCH_CONSTANT_4D = -0.138196601125011; //(1/Math.sqrt(4+1)-1)/4;
SQUISH_CONSTANT_4D = 0.309016994374947; //(Math.sqrt(4+1)-1)/4;
NORM_CONSTANT_2D = 47;
NORM_CONSTANT_3D = 103;
NORM_CONSTANT_4D = 30;
DEFAULT_SEED = 0;
perm = [];
permGradIndex3D = [];
//Gradients for 2D. They approximate the directions to the
//vertices of an octagon from the center.
var gradients2D = [
5, 2, 2, 5,
-5, 2, -2, 5,
5, -2, 2, -5,
-5, -2, -2, -5,
];
//Gradients for 3D. They approximate the directions to the
//vertices of a rhombicuboctahedron from the center, skewed so
//that the triangular and square facets can be inscribed inside
//circles of the same radius.
var gradients3D = [
-11, 4, 4, -4, 11, 4, -4, 4, 11,
11, 4, 4, 4, 11, 4, 4, 4, 11,
-11, -4, 4, -4, -11, 4, -4, -4, 11,
11, -4, 4, 4, -11, 4, 4, -4, 11,
-11, 4, -4, -4, 11, -4, -4, 4, -11,
11, 4, -4, 4, 11, -4, 4, 4, -11,
-11, -4, -4, -4, -11, -4, -4, -4, -11,
11, -4, -4, 4, -11, -4, 4, -4, -11,
];
//Gradients for 4D. They approximate the directions to the
//vertices of a disprismatotesseractihexadecachoron from the center,
//skewed so that the tetrahedral and cubic facets can be inscribed inside
//spheres of the same radius.
var gradients4D = [
3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3,
-3, 1, 1, 1, -1, 3, 1, 1, -1, 1, 3, 1, -1, 1, 1, 3,
3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3, 1, 1, -1, 1, 3,
-3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3,
3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3,
-3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3,
3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3,
-3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3,
3, 1, 1, -1, 1, 3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3,
-3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3, -1, -1, 1, 1, -3,
3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3,
-3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3,
3, 1, -1, -1, 1, 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3,
-3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3,
3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3,
-3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3,
];
seed = (seed) ? seed : DEFAULT_SEED;
if( Array.isArray(seed) ) {
perm = seed;
var permGradIndex3d = [];
for(var i=0; i<256; i++) {
//Since 3D has 24 gradients, simple bitmask won't work, so precompute modulo array.
permGradIndex3D[i] = (parseInt(seed[i] % (gradients3D.length / 3)) * 3);
}
} else {
//Initializes the class using a permutation array generated from a 64-bit seed.
//Generates a proper permutation (i.e. doesn't merely perform N successive pair swaps on a base array)
//Uses a simple 64-bit LCG.
seed = parseFloat(seed);
if(!seed || isNaN(seed) ) seed = DEFAULT_SEED;
console.log("initializing seed "+seed);
perm = [];
permGradIndex3D = [];
var source = [];
var i = 0;
for(i=0; i<256; i++) {
source[i] = i;
}
seed = seed * 6364136223846793005 + 1442695040888963407;
seed = seed * 6364136223846793005 + 1442695040888963407;
seed = seed * 6364136223846793005 + 1442695040888963407;
for(i=255; i>=0; i--) {
seed = seed * 6364136223846793005 + 1442695040888963407;
var r = parseInt( (seed+31) % (i+1) );
if(r < 0) {
r += (i+1);
}
perm[i] = source[r];
permGradIndex3D[i] = (parseInt(perm[i] % gradients3D.length / 3)*3);
source[r] = source[i];
}
console.log(perm);
}
//
var extrapolate2d = function(xsb, ysb, dx, dy) {
var index = perm[(perm[xsb & 0xFF] + ysb) & 0xFF] & 0x0E;
return gradients2D[index] * dx
+ gradients2D[index + 1] * dy;
};
var extrapolate3d = function(xsb, ysb, zsb, dx, dy, dz){
var index = permGradIndex3D[(perm[(perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF];
return gradients3D[index] * dx
+ gradients3D[index + 1] * dy
+ gradients3D[index + 2] * dz;
};
var extrapolate4d = function(xsb, ysb, zsb, wsb, dx, dy, dz, dw){
var index = perm[(perm[(perm[(perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF] + wsb) & 0xFF] & 0xFC;
return gradients4D[index] * dx
+ gradients4D[index + 1] * dy
+ gradients4D[index + 2] * dz
+ gradients4D[index + 3] * dw;
};
var fastFloor = function(x) {
return Math.floor(x);
//var xi = parseInt(x);
//return x < xi ? xi - 1 : xi;
}
var eval2d = function(x, y) {
//Place input coordinates onto grid.
var stretchOffset = (x + y) * STRETCH_CONSTANT_2D;
var xs = x + stretchOffset;
var ys = y + stretchOffset;
//Floor to get grid coordinates of rhombus (stretched square) super-cell origin.
var xsb = fastFloor(xs);
var ysb = fastFloor(ys);
//Skew out to get actual coordinates of rhombus origin. We'll need these later.
var squishOffset = (xsb + ysb) * SQUISH_CONSTANT_2D;
var xb = xsb + squishOffset;
var yb = ysb + squishOffset;
//Compute grid coordinates relative to rhombus origin.
var xins = xs - xsb;
var yins = ys - ysb;
//Sum those together to get a value that determines which region we're in.
var inSum = xins + yins;
//Positions relative to origin point.
var dx0 = x - xb;
var dy0 = y - yb;
//We'll be defining these inside the next block and using them afterwards.
var dx_ext, dy_ext;
var xsv_ext, ysv_ext;
var value = 0;
//Contribution (1,0)
var dx1 = dx0 - 1 - SQUISH_CONSTANT_2D;
var dy1 = dy0 - 0 - SQUISH_CONSTANT_2D;
var attn1 = 2 - dx1 * dx1 - dy1 * dy1;
if (attn1 > 0) {
attn1 *= attn1;
value += attn1 * attn1 * extrapolate2d(xsb + 1, ysb + 0, dx1, dy1);
}
//Contribution (0,1)
var dx2 = dx0 - 0 - SQUISH_CONSTANT_2D;
var dy2 = dy0 - 1 - SQUISH_CONSTANT_2D;
var attn2 = 2 - dx2 * dx2 - dy2 * dy2;
if (attn2 > 0) {
attn2 *= attn2;
value += attn2 * attn2 * extrapolate2d(xsb + 0, ysb + 1, dx2, dy2);
}
if (inSum <= 1) { //We're inside the triangle (2-Simplex) at (0,0)
var zins = 1 - inSum;
if (zins > xins || zins > yins) { //(0,0) is one of the closest two triangular vertices
if (xins > yins) {
xsv_ext = xsb + 1;
ysv_ext = ysb - 1;
dx_ext = dx0 - 1;
dy_ext = dy0 + 1;
} else {
xsv_ext = xsb - 1;
ysv_ext = ysb + 1;
dx_ext = dx0 + 1;
dy_ext = dy0 - 1;
}
} else { //(1,0) and (0,1) are the closest two vertices.
xsv_ext = xsb + 1;
ysv_ext = ysb + 1;
dx_ext = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
dy_ext = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
}
} else { //We're inside the triangle (2-Simplex) at (1,1)
var zins = 2 - inSum;
if (zins < xins || zins < yins) { //(0,0) is one of the closest two triangular vertices
if (xins > yins) {
xsv_ext = xsb + 2;
ysv_ext = ysb + 0;
dx_ext = dx0 - 2 - 2 * SQUISH_CONSTANT_2D;
dy_ext = dy0 + 0 - 2 * SQUISH_CONSTANT_2D;
} else {
xsv_ext = xsb + 0;
ysv_ext = ysb + 2;
dx_ext = dx0 + 0 - 2 * SQUISH_CONSTANT_2D;
dy_ext = dy0 - 2 - 2 * SQUISH_CONSTANT_2D;
}
} else { //(1,0) and (0,1) are the closest two vertices.
dx_ext = dx0;
dy_ext = dy0;
xsv_ext = xsb;
ysv_ext = ysb;
}
xsb += 1;
ysb += 1;
dx0 = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
dy0 = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
}
//Contribution (0,0) or (1,1)
var attn0 = 2 - dx0 * dx0 - dy0 * dy0;
if (attn0 > 0) {
attn0 *= attn0;
value += attn0 * attn0 * extrapolate2d(xsb, ysb, dx0, dy0);
}
//Extra Vertex
var attn_ext = 2 - dx_ext * dx_ext - dy_ext * dy_ext;
if (attn_ext > 0) {
attn_ext *= attn_ext;
value += attn_ext * attn_ext * extrapolate2d(xsv_ext, ysv_ext, dx_ext, dy_ext);
}
return value / NORM_CONSTANT_2D;
};
var eval3d = function(x, y, z) {
//TODO::
console.log("3d not implemented!");
return null;
};
var eval4d = function(x,y,z,w) {
//TODO::
console.log("4d Not implemented!");
return null;
}
return {
eval : function(x, y, z, w) {
if(x && y ) {
if(z) {
if(w) return eval4d(x,y,z,w);
else return eval3d(x,y,z);
} else {
return eval2d(x,y);
}
} else {
//error!
return null;
}
}
};
};
//optional require.js export
if(typeof(module)!=="undefined") module.exports = OpenSimplexNoise;
<html>
<head>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<title>OpenSimplex</title>
</head>
<body>
<script src="OpenSimplexASM.js" type="text/javascript"></script>
<h2>Testing OpenSimplex</h2>
<hr>
<h4>2D Canvas Test</h4>
<form>
<p>
Seed (optional): <input type="text" name="seed" size="4" style="margin-right:15px;">
</p>
<p>
Canvas Width: <input type="text" name="cWidth" size="4" style="margin-right:15px;" value="256">
Canvas Height: <input ty=e"text" name="cHeight" size="4" value="256">
<br>
Feature Size: <input type="text" name="feature" size="4" value="24">
</p>
<p><input type="button" onClick="run2D(this.parentNode.parentNode);" value="Generate"></p>
</form>
<canvas id="c2d" width="512" height="512"></canvas>
<script type="text/javascript">
var px = [];
var os;
var min = 0;
var max = 0;
function run2D(frm) {
var noise = null;
//initialize asm objects
var heap = new ArrayBuffer(0x10000); // 64k heap
os = OpenSimplexASM(window, null, heap); // produce exports object linked to AOT-compiled code
if(frm.seed && frm.seed.value && !isNaN(frm.seed.value) ) {
console.log("seeded with "+frm.seed.value);
//noise = OpenSimplexNoise(frm.seed.value);
os.init(parseInt(frm.seed.value) );
} else {
//noise = OpenSimplexNoise();
os.init(false);
}
var maxWidth = 512;
var maxHeight = 512;
var feature = (frm.feature && frm.feature.value && !isNaN(frm.feature.value) ) ? parseInt(frm.feature.value) : 24;
var cW = (frm.cWidth && frm.cWidth.value && !isNaN(frm.cWidth.value) && parseInt(frm.cWidth.value) < maxWidth )? parseInt(frm.cWidth.value) : maxWidth;
var cH = (frm.cHeight && frm.cHeight.value && !isNaN(frm.cHeight.value) && parseInt(frm.cHeight.value) < maxHeight )? parseInt(frm.cHeight.value) : maxHeight;
var c = document.getElementById('c2d');
var ctx = c.getContext('2d');
ctx.clearRect(0,0,512,512);
px = [];
for(var y=0;y<cH;y++) {
px[y] = [];
for(var x=0; x<cW; x++) {
var val = os.eval2d(x/feature, y/feature);
if(val<min) min=val;
if(val>max) max=val;
px[y][x] = val;
var rgb = parseInt(255 * ((val+2)/6) );
ctx.fillStyle = 'rgba(0,'+rgb+',0,1)';
ctx.fillRect(x, y,1,1);
}
}
return false;
}
</script>
</body>
</html>
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
@Mocker
Copy link
Author

Mocker commented Oct 6, 2014

Planning to rewrite this for Javascript

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment