Skip to content

Instantly share code, notes, and snippets.

@Pencroff
Last active August 22, 2016 20:50
Show Gist options
  • Save Pencroff/33575c9492e0c212b1c29cfc3be79eae to your computer and use it in GitHub Desktop.
Save Pencroff/33575c9492e0c212b1c29cfc3be79eae to your computer and use it in GitHub Desktop.
Random.js
var HAS_UINT32_ARRAY = !(typeof Uint32Array === 'undefined')
var USE_UINT32_ARRAY = false // Benchmarks show this to be slower than Array's. Hrmph.
var bits_per_word = 32
, address_shift = 5 // log2(bits_per_word)
/**
* Create a new bit set. If a size is provided an array will be allocated
* upfront, which speeds up writes and test operations since bitwise operations
* against undefined require a cast. Providing a size will fix the bitset to
* exactly that size, whereas unsized bitsets grow automatically.
*
* The size of the BitSet is rounded up to the next multiple of 32
* automatically.
*
* If the Typed Uint32Array is available it is used for fixed size sets.
**/
var BitSet = function BitSet(size, words) {
if (!(this instanceof BitSet)) {
return new BitSet()
}
var fixed = (size ? true : false)
size = (fixed ? (Math.ceil(size / bits_per_word) * bits_per_word) : void 0)
if (!(typeof words === 'undefined')) {
this.words = words
} else if (fixed) {
var word_length = size / bits_per_word;
if (USE_UINT32_ARRAY) {
var buffer = new Buffer(word_length * 4)
buffer.fill(0)
this.words = new Uint32Array(buffer)
} else {
this.words = new Array(word_length)
for (var i = 0; i < word_length; i++) {
this.words[i] = 0
}
}
} else {
this.words = []
}
var index = function(position) {
if (fixed && position >= size) {
throw new Error('position ' + position + ' exceeds size ' + size)
}
return position >> address_shift
}
this.word_length = function() {
if (fixed) {
return this.words.length
} else {
var length = this.words.length
for (var i = this.words.length - 1; i >= 0; i--) {
if (this.words[i] !== 0) {
break
}
length -= 1
}
return length
}
}
this.set = function BitSet_set(position) {
return this.words[index(position)] |= 1 << position
}
this.clear = function BitSet_clear(position) {
return this.words[index(position)] &= ~(1 << position)
}
this.get = function BitSet_get(position) {
return (this.words[index(position)] & (1 << position)) !== 0
}
this.flip = function BitSet_flip(position) {
return this.words[index(position)] ^= (1 << position);
}
this.fixed = function BitSet_fixed() {
return fixed
}
this.size = function BitSet_size() {
return size
}
this.is_empty = function BitSet__is_empty() {
for (var i = 0, ii = this.word_length(); i < ii; i++) {
if (this.words[i]) {
return 0
}
}
return 1
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
html, body {
background: #FFF;
margin: 0;
}
#canvas {
position: fixed;
background: #FFF
}
#stats {
position: absolute;
bottom: 10px;
right: 10px;
z-index: 10;
width: 400px;
height: 2em;
vertical-align: middle;
line-height: 2em;
margin: 0px 10px;
font-family: helvetica, serif;
font-size: 14px;
text-align: center;
opacity: 0.4;
color: white;
background-color: black;
}
#stats:hover {
opacity: 1;
}
#controls {
position: absolute;
right: 10px;
top: 5px;
cursor: pointer;
}
</style>
</head>
<canvas id="canvas"></canvas>
<div id="stats"><span id="info"></span><button id="controls">&#10073;&#10073;</button></div>
<script src="./bitset.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.0/lib/xor4096.min.js"></script>
<script src="./Random.js"></script>
<script>
var rnd = new xor4096(Date.now().toString());
var rndMt = new Random(Random.engines.mt19937().autoSeed());
Number.prototype.prettyString = function() {
return (((this / 1e3) | 0) * 1e3).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
window.onload = function() {
//Math.random = crypto_random;
// A place to show some statisitics
var stats = document.getElementById('info')
, ctrl = document.getElementById('controls');
ctrl.style.display = 'none';
/*
var generation_paused = false;
ctrl.onclick = function() {
generation_paused = !generation_paused;
if (generation_paused) {
ctrl.innerHTML = '&#9658;';
} else {
ctrl.innerHTML = '&#10073;&#10073;';
}
}
*/
// The canvas element
var canvas = document.getElementById('canvas')
, ctx = canvas.getContext('2d');
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';
}
resize();
window.onresize = resize;
// The number of segments we're cutting our [0,1)^2 hypercube into.
var segments = Math.pow(2, 15);
// Record of the number of collisions that have occurred at each hypercube % 2.
var collisions = new BitSet(segments * segments);
// How many random numbers, and how many points we've generated so far.
var numbers = 0
, points = 0;
// The current time, when we're starting generation (used to generate some stats).
var gen_start = new Date().getTime();
// Some parameters on how much time to spend generating random numbers and how
// often to check our time usage. We set these by sampling the speed of our
// animation over time, but these are static starting values.
var gen_time_slice = 5
, gen_check_period = 1000;
// Some stats to help adjust parameters and whatnot.
var target_hz = 10
, frame_interval_ms = Math.floor(1000/target_hz)
, date_checks = 0
, frames = 0
, time_per_frame = 0
, blocks = 0
, time_per_block = 0
, total_pixels = 0
, black_pixels = 0;
function noise(ctx) {
// Re-draw our viewport of the collisions, with a black pixel designating an odd
// number of collisions and a white pixel designating an even number (or 0).
var start = new Date().getTime();
var w = ctx.canvas.width
, h = ctx.canvas.height;
var data = ctx.createImageData(w, h)
, buf = new Uint32Array(data.data.buffer);
black_pixels = 0;
total_pixels = 0;
for (var c = 0; c < w; c++) {
for (var r = 0; r < h; r++) {
var c_p = (r * segments) + c // The collision position in the collisions data structure
, b_p = (r * w) + c; // The pixel position in the image buffer
if (collisions.get(c_p)) {
buf[b_p] = 0xff000000;
black_pixels += 1;
}
total_pixels += 1;
}
}
ctx.putImageData(data, 0, 0);
frames += 1;
time_per_frame = (0.9 * time_per_frame) + (0.1 * (new Date().getTime() - start));
}
(function generate_collisions() {
// Generate a bit more random noise. We'll do as much as we can in some fixed
// time period. Refresh rate is 60FPS so we only have ~16ms between frames. We'll
// try to keep this function from blocking for more than a subset of that time. We
// don't want to waste too much time futzing with Date objects either, so we only
// check how much time we've spent working periodically.
var start = new Date().getTime()
, checks = 0;
while ((new Date().getTime() - start) <= gen_time_slice) {
checks += 1;
for (var i = gen_check_period; i > 0; --i) {
var x = Math.floor(rndMt.real(0, 1, true) * segments) //rnd() Math.random()
, y = Math.floor(rndMt.real(0, 1, true) * segments)
, p = (x * segments) + y;
collisions.flip(p);
numbers += 2;
points += 1;
}
}
date_checks = (0.9 * date_checks) + (0.1 * checks);
blocks += 1;
time_per_block = (0.9 * time_per_block) + (0.1 * (new Date().getTime() - start));
setTimeout(generate_collisions, 0);
})();
var update_stats = function update_stats() {
var secs = (new Date().getTime() - gen_start) / 1000
, rate = points / secs;
stats.innerHTML = points.prettyString() + ' points (' + rate.prettyString() + '/s). ' + (100*black_pixels/total_pixels).toPrecision(5) + '% black.';
console.log('Stats at: ' + new Date().toString());
console.log(' ' + date_checks + ' date checks.');
console.log(' ' + frames + ' frames (' + (frames / secs) + '/s).');
console.log(' ' + time_per_frame + 'ms / frame');
console.log(' ' + blocks + ' blocks (' + (blocks / secs) + '/s).');
console.log(' ' + time_per_block + 'ms / block');
// Update how many numbers per refresh we generate and how often we check up on
// the amount of time we've spent generating. The goal is to pause our random
// number generation at about 4x the framerate (to make sure we don't block too
// long) and to check how much time we've spent generating about twice per block
// of RNGs generated (so we've got good bounds on expected time spent generating,
// but we're not wasting too much time looking at the clock).
gen_time_slice = ((frame_interval_ms - time_per_frame) / 4) | 0;
gen_check_period = Math.max(((gen_check_period * (date_checks / 2)) | 0), 2);
console.log(' New time slice: ' + gen_time_slice);
console.log(' New check period: ' + gen_check_period);
}
setInterval(update_stats, 1000);
(function loop() {
var start = new Date().getTime();
noise(ctx);
var next = Math.max(0, frame_interval_ms - (new Date().getTime() - start))
setTimeout(loop, next);
})();
}
</script>
</html>
/*jshint eqnull:true*/
(function (root) {
"use strict";
var GLOBAL_KEY = "Random";
var imul = (typeof Math.imul !== "function" || Math.imul(0xffffffff, 5) !== -5 ?
function (a, b) {
var ah = (a >>> 16) & 0xffff;
var al = a & 0xffff;
var bh = (b >>> 16) & 0xffff;
var bl = b & 0xffff;
// the shift by 0 fixes the sign on the high part
// the final |0 converts the unsigned value into a signed value
return (al * bl) + (((ah * bl + al * bh) << 16) >>> 0) | 0;
} :
Math.imul);
var stringRepeat = (typeof String.prototype.repeat === "function" && "x".repeat(3) === "xxx" ?
function (x, y) {
return x.repeat(y);
} : function (pattern, count) {
var result = "";
while (count > 0) {
if (count & 1) {
result += pattern;
}
count >>= 1;
pattern += pattern;
}
return result;
});
function Random(engine) {
if (!(this instanceof Random)) {
return new Random(engine);
}
if (engine == null) {
engine = Random.engines.nativeMath;
} else if (typeof engine !== "function") {
throw new TypeError("Expected engine to be a function, got " + typeof engine);
}
this.engine = engine;
}
var proto = Random.prototype;
Random.engines = {
nativeMath: function () {
return (Math.random() * 0x100000000) | 0;
},
mt19937: (function (Int32Array) {
// http://en.wikipedia.org/wiki/Mersenne_twister
function refreshData(data) {
var k = 0;
var tmp = 0;
for (;
(k | 0) < 227; k = (k + 1) | 0) {
tmp = (data[k] & 0x80000000) | (data[(k + 1) | 0] & 0x7fffffff);
data[k] = data[(k + 397) | 0] ^ (tmp >>> 1) ^ ((tmp & 0x1) ? 0x9908b0df : 0);
}
for (;
(k | 0) < 623; k = (k + 1) | 0) {
tmp = (data[k] & 0x80000000) | (data[(k + 1) | 0] & 0x7fffffff);
data[k] = data[(k - 227) | 0] ^ (tmp >>> 1) ^ ((tmp & 0x1) ? 0x9908b0df : 0);
}
tmp = (data[623] & 0x80000000) | (data[0] & 0x7fffffff);
data[623] = data[396] ^ (tmp >>> 1) ^ ((tmp & 0x1) ? 0x9908b0df : 0);
}
function temper(value) {
value ^= value >>> 11;
value ^= (value << 7) & 0x9d2c5680;
value ^= (value << 15) & 0xefc60000;
return value ^ (value >>> 18);
}
function seedWithArray(data, source) {
var i = 1;
var j = 0;
var sourceLength = source.length;
var k = Math.max(sourceLength, 624) | 0;
var previous = data[0] | 0;
for (;
(k | 0) > 0; --k) {
data[i] = previous = ((data[i] ^ imul((previous ^ (previous >>> 30)), 0x0019660d)) + (source[j] | 0) + (j | 0)) | 0;
i = (i + 1) | 0;
++j;
if ((i | 0) > 623) {
data[0] = data[623];
i = 1;
}
if (j >= sourceLength) {
j = 0;
}
}
for (k = 623;
(k | 0) > 0; --k) {
data[i] = previous = ((data[i] ^ imul((previous ^ (previous >>> 30)), 0x5d588b65)) - i) | 0;
i = (i + 1) | 0;
if ((i | 0) > 623) {
data[0] = data[623];
i = 1;
}
}
data[0] = 0x80000000;
}
function mt19937() {
var data = new Int32Array(624);
var index = 0;
var uses = 0;
function next() {
if ((index | 0) >= 624) {
refreshData(data);
index = 0;
}
var value = data[index];
index = (index + 1) | 0;
uses += 1;
return temper(value) | 0;
}
next.getUseCount = function() {
return uses;
};
next.discard = function (count) {
uses += count;
if ((index | 0) >= 624) {
refreshData(data);
index = 0;
}
while ((count - index) > 624) {
count -= 624 - index;
refreshData(data);
index = 0;
}
index = (index + count) | 0;
return next;
};
next.seed = function (initial) {
var previous = 0;
data[0] = previous = initial | 0;
for (var i = 1; i < 624; i = (i + 1) | 0) {
data[i] = previous = (imul((previous ^ (previous >>> 30)), 0x6c078965) + i) | 0;
}
index = 624;
uses = 0;
return next;
};
next.seedWithArray = function (source) {
next.seed(0x012bd6aa);
seedWithArray(data, source);
return next;
};
next.autoSeed = function () {
return next.seedWithArray(Random.generateEntropyArray());
};
return next;
}
return mt19937;
}(typeof Int32Array === "function" ? Int32Array : Array)),
browserCrypto: (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function" && typeof Int32Array === "function") ? (function () {
var data = null;
var index = 128;
return function () {
if (index >= 128) {
if (data === null) {
data = new Int32Array(128);
}
crypto.getRandomValues(data);
index = 0;
}
return data[index++] | 0;
};
}()) : null
};
Random.generateEntropyArray = function () {
var array = [];
var engine = Random.engines.nativeMath;
for (var i = 0; i < 16; ++i) {
array[i] = engine() | 0;
}
array.push(new Date().getTime() | 0);
return array;
};
function returnValue(value) {
return function () {
return value;
};
}
// [-0x80000000, 0x7fffffff]
Random.int32 = function (engine) {
return engine() | 0;
};
proto.int32 = function () {
return Random.int32(this.engine);
};
// [0, 0xffffffff]
Random.uint32 = function (engine) {
return engine() >>> 0;
};
proto.uint32 = function () {
return Random.uint32(this.engine);
};
// [0, 0x1fffffffffffff]
Random.uint53 = function (engine) {
var high = engine() & 0x1fffff;
var low = engine() >>> 0;
return (high * 0x100000000) + low;
};
proto.uint53 = function () {
return Random.uint53(this.engine);
};
// [0, 0x20000000000000]
Random.uint53Full = function (engine) {
while (true) {
var high = engine() | 0;
if (high & 0x200000) {
if ((high & 0x3fffff) === 0x200000 && (engine() | 0) === 0) {
return 0x20000000000000;
}
} else {
var low = engine() >>> 0;
return ((high & 0x1fffff) * 0x100000000) + low;
}
}
};
proto.uint53Full = function () {
return Random.uint53Full(this.engine);
};
// [-0x20000000000000, 0x1fffffffffffff]
Random.int53 = function (engine) {
var high = engine() | 0;
var low = engine() >>> 0;
return ((high & 0x1fffff) * 0x100000000) + low + (high & 0x200000 ? -0x20000000000000 : 0);
};
proto.int53 = function () {
return Random.int53(this.engine);
};
// [-0x20000000000000, 0x20000000000000]
Random.int53Full = function (engine) {
while (true) {
var high = engine() | 0;
if (high & 0x400000) {
if ((high & 0x7fffff) === 0x400000 && (engine() | 0) === 0) {
return 0x20000000000000;
}
} else {
var low = engine() >>> 0;
return ((high & 0x1fffff) * 0x100000000) + low + (high & 0x200000 ? -0x20000000000000 : 0);
}
}
};
proto.int53Full = function () {
return Random.int53Full(this.engine);
};
function add(generate, addend) {
if (addend === 0) {
return generate;
} else {
return function (engine) {
return generate(engine) + addend;
};
}
}
Random.integer = (function () {
function isPowerOfTwoMinusOne(value) {
return ((value + 1) & value) === 0;
}
function bitmask(masking) {
return function (engine) {
return engine() & masking;
};
}
function downscaleToLoopCheckedRange(range) {
var extendedRange = range + 1;
var maximum = extendedRange * Math.floor(0x100000000 / extendedRange);
return function (engine) {
var value = 0;
do {
value = engine() >>> 0;
} while (value >= maximum);
return value % extendedRange;
};
}
function downscaleToRange(range) {
if (isPowerOfTwoMinusOne(range)) {
return bitmask(range);
} else {
return downscaleToLoopCheckedRange(range);
}
}
function isEvenlyDivisibleByMaxInt32(value) {
return (value | 0) === 0;
}
function upscaleWithHighMasking(masking) {
return function (engine) {
var high = engine() & masking;
var low = engine() >>> 0;
return (high * 0x100000000) + low;
};
}
function upscaleToLoopCheckedRange(extendedRange) {
var maximum = extendedRange * Math.floor(0x20000000000000 / extendedRange);
return function (engine) {
var ret = 0;
do {
var high = engine() & 0x1fffff;
var low = engine() >>> 0;
ret = (high * 0x100000000) + low;
} while (ret >= maximum);
return ret % extendedRange;
};
}
function upscaleWithinU53(range) {
var extendedRange = range + 1;
if (isEvenlyDivisibleByMaxInt32(extendedRange)) {
var highRange = ((extendedRange / 0x100000000) | 0) - 1;
if (isPowerOfTwoMinusOne(highRange)) {
return upscaleWithHighMasking(highRange);
}
}
return upscaleToLoopCheckedRange(extendedRange);
}
function upscaleWithinI53AndLoopCheck(min, max) {
return function (engine) {
var ret = 0;
do {
var high = engine() | 0;
var low = engine() >>> 0;
ret = ((high & 0x1fffff) * 0x100000000) + low + (high & 0x200000 ? -0x20000000000000 : 0);
} while (ret < min || ret > max);
return ret;
};
}
return function (min, max) {
min = Math.floor(min);
max = Math.floor(max);
if (min < -0x20000000000000 || !isFinite(min)) {
throw new RangeError("Expected min to be at least " + (-0x20000000000000));
} else if (max > 0x20000000000000 || !isFinite(max)) {
throw new RangeError("Expected max to be at most " + 0x20000000000000);
}
var range = max - min;
if (range <= 0 || !isFinite(range)) {
return returnValue(min);
} else if (range === 0xffffffff) {
if (min === 0) {
return Random.uint32;
} else {
return add(Random.int32, min + 0x80000000);
}
} else if (range < 0xffffffff) {
return add(downscaleToRange(range), min);
} else if (range === 0x1fffffffffffff) {
return add(Random.uint53, min);
} else if (range < 0x1fffffffffffff) {
return add(upscaleWithinU53(range), min);
} else if (max - 1 - min === 0x1fffffffffffff) {
return add(Random.uint53Full, min);
} else if (min === -0x20000000000000 && max === 0x20000000000000) {
return Random.int53Full;
} else if (min === -0x20000000000000 && max === 0x1fffffffffffff) {
return Random.int53;
} else if (min === -0x1fffffffffffff && max === 0x20000000000000) {
return add(Random.int53, 1);
} else if (max === 0x20000000000000) {
return add(upscaleWithinI53AndLoopCheck(min - 1, max - 1), 1);
} else {
return upscaleWithinI53AndLoopCheck(min, max);
}
};
}());
proto.integer = function (min, max) {
return Random.integer(min, max)(this.engine);
};
// [0, 1] (floating point)
Random.realZeroToOneInclusive = function (engine) {
return Random.uint53Full(engine) / 0x20000000000000;
};
proto.realZeroToOneInclusive = function () {
return Random.realZeroToOneInclusive(this.engine);
};
// [0, 1) (floating point)
Random.realZeroToOneExclusive = function (engine) {
return Random.uint53(engine) / 0x20000000000000;
};
proto.realZeroToOneExclusive = function () {
return Random.realZeroToOneExclusive(this.engine);
};
Random.real = (function () {
function multiply(generate, multiplier) {
if (multiplier === 1) {
return generate;
} else if (multiplier === 0) {
return function () {
return 0;
};
} else {
return function (engine) {
return generate(engine) * multiplier;
};
}
}
return function (left, right, inclusive) {
if (!isFinite(left)) {
throw new RangeError("Expected left to be a finite number");
} else if (!isFinite(right)) {
throw new RangeError("Expected right to be a finite number");
}
return add(
multiply(
inclusive ? Random.realZeroToOneInclusive : Random.realZeroToOneExclusive,
right - left),
left);
};
}());
proto.real = function (min, max, inclusive) {
return Random.real(min, max, inclusive)(this.engine);
};
Random.bool = (function () {
function isLeastBitTrue(engine) {
return (engine() & 1) === 1;
}
function lessThan(generate, value) {
return function (engine) {
return generate(engine) < value;
};
}
function probability(percentage) {
if (percentage <= 0) {
return returnValue(false);
} else if (percentage >= 1) {
return returnValue(true);
} else {
var scaled = percentage * 0x100000000;
if (scaled % 1 === 0) {
return lessThan(Random.int32, (scaled - 0x80000000) | 0);
} else {
return lessThan(Random.uint53, Math.round(percentage * 0x20000000000000));
}
}
}
return function (numerator, denominator) {
if (denominator == null) {
if (numerator == null) {
return isLeastBitTrue;
}
return probability(numerator);
} else {
if (numerator <= 0) {
return returnValue(false);
} else if (numerator >= denominator) {
return returnValue(true);
}
return lessThan(Random.integer(0, denominator - 1), numerator);
}
};
}());
proto.bool = function (numerator, denominator) {
return Random.bool(numerator, denominator)(this.engine);
};
function toInteger(value) {
var number = +value;
if (number < 0) {
return Math.ceil(number);
} else {
return Math.floor(number);
}
}
function convertSliceArgument(value, length) {
if (value < 0) {
return Math.max(value + length, 0);
} else {
return Math.min(value, length);
}
}
Random.pick = function (engine, array, begin, end) {
var length = array.length;
var start = begin == null ? 0 : convertSliceArgument(toInteger(begin), length);
var finish = end === void 0 ? length : convertSliceArgument(toInteger(end), length);
if (start >= finish) {
return void 0;
}
var distribution = Random.integer(start, finish - 1);
return array[distribution(engine)];
};
proto.pick = function (array, begin, end) {
return Random.pick(this.engine, array, begin, end);
};
function returnUndefined() {
return void 0;
}
var slice = Array.prototype.slice;
Random.picker = function (array, begin, end) {
var clone = slice.call(array, begin, end);
if (!clone.length) {
return returnUndefined;
}
var distribution = Random.integer(0, clone.length - 1);
return function (engine) {
return clone[distribution(engine)];
};
};
Random.shuffle = function (engine, array, downTo) {
var length = array.length;
if (length) {
if (downTo == null) {
downTo = 0;
}
for (var i = (length - 1) >>> 0; i > downTo; --i) {
var distribution = Random.integer(0, i);
var j = distribution(engine);
if (i !== j) {
var tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
}
return array;
};
proto.shuffle = function (array) {
return Random.shuffle(this.engine, array);
};
Random.sample = function (engine, population, sampleSize) {
if (sampleSize < 0 || sampleSize > population.length || !isFinite(sampleSize)) {
throw new RangeError("Expected sampleSize to be within 0 and the length of the population");
}
if (sampleSize === 0) {
return [];
}
var clone = slice.call(population);
var length = clone.length;
if (length === sampleSize) {
return Random.shuffle(engine, clone, 0);
}
var tailLength = length - sampleSize;
return Random.shuffle(engine, clone, tailLength - 1).slice(tailLength);
};
proto.sample = function (population, sampleSize) {
return Random.sample(this.engine, population, sampleSize);
};
Random.die = function (sideCount) {
return Random.integer(1, sideCount);
};
proto.die = function (sideCount) {
return Random.die(sideCount)(this.engine);
};
Random.dice = function (sideCount, dieCount) {
var distribution = Random.die(sideCount);
return function (engine) {
var result = [];
result.length = dieCount;
for (var i = 0; i < dieCount; ++i) {
result[i] = distribution(engine);
}
return result;
};
};
proto.dice = function (sideCount, dieCount) {
return Random.dice(sideCount, dieCount)(this.engine);
};
// http://en.wikipedia.org/wiki/Universally_unique_identifier
Random.uuid4 = (function () {
function zeroPad(string, zeroCount) {
return stringRepeat("0", zeroCount - string.length) + string;
}
return function (engine) {
var a = engine() >>> 0;
var b = engine() | 0;
var c = engine() | 0;
var d = engine() >>> 0;
return (
zeroPad(a.toString(16), 8) +
"-" +
zeroPad((b & 0xffff).toString(16), 4) +
"-" +
zeroPad((((b >> 4) & 0x0fff) | 0x4000).toString(16), 4) +
"-" +
zeroPad(((c & 0x3fff) | 0x8000).toString(16), 4) +
"-" +
zeroPad(((c >> 4) & 0xffff).toString(16), 4) +
zeroPad(d.toString(16), 8));
};
}());
proto.uuid4 = function () {
return Random.uuid4(this.engine);
};
Random.string = (function () {
// has 2**x chars, for faster uniform distribution
var DEFAULT_STRING_POOL = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
return function (pool) {
if (pool == null) {
pool = DEFAULT_STRING_POOL;
}
var length = pool.length;
if (!length) {
throw new Error("Expected pool not to be an empty string");
}
var distribution = Random.integer(0, length - 1);
return function (engine, length) {
var result = "";
for (var i = 0; i < length; ++i) {
var j = distribution(engine);
result += pool.charAt(j);
}
return result;
};
};
}());
proto.string = function (length, pool) {
return Random.string(pool)(this.engine, length);
};
Random.hex = (function () {
var LOWER_HEX_POOL = "0123456789abcdef";
var lowerHex = Random.string(LOWER_HEX_POOL);
var upperHex = Random.string(LOWER_HEX_POOL.toUpperCase());
return function (upper) {
if (upper) {
return upperHex;
} else {
return lowerHex;
}
};
}());
proto.hex = function (length, upper) {
return Random.hex(upper)(this.engine, length);
};
Random.date = function (start, end) {
if (!(start instanceof Date)) {
throw new TypeError("Expected start to be a Date, got " + typeof start);
} else if (!(end instanceof Date)) {
throw new TypeError("Expected end to be a Date, got " + typeof end);
}
var distribution = Random.integer(start.getTime(), end.getTime());
return function (engine) {
return new Date(distribution(engine));
};
};
proto.date = function (start, end) {
return Random.date(start, end)(this.engine);
};
if (typeof define === "function" && define.amd) {
define(function () {
return Random;
});
} else if (typeof module !== "undefined" && typeof require === "function") {
module.exports = Random;
} else {
(function () {
var oldGlobal = root[GLOBAL_KEY];
Random.noConflict = function () {
root[GLOBAL_KEY] = oldGlobal;
return this;
};
}());
root[GLOBAL_KEY] = Random;
}
}(this));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment