chance
Version:
Chance - Utility library to generate anything random
1,469 lines (1,262 loc) • 472 kB
JavaScript
// Chance.js 1.1.12
// https://chancejs.com
// (c) 2013 Victor Quinn
// Chance may be freely distributed or modified under the MIT license.
(function () {
// Constants
var MAX_INT = 9007199254740992;
var MIN_INT = -MAX_INT;
var NUMBERS = '0123456789';
var CHARS_LOWER = 'abcdefghijklmnopqrstuvwxyz';
var CHARS_UPPER = CHARS_LOWER.toUpperCase();
var HEX_POOL = NUMBERS + "abcdef";
// Errors
function UnsupportedError(message) {
this.name = 'UnsupportedError';
this.message = message || 'This feature is not supported on this platform';
}
UnsupportedError.prototype = new Error();
UnsupportedError.prototype.constructor = UnsupportedError;
// Cached array helpers
var slice = Array.prototype.slice;
// Constructor
function Chance (seed) {
if (!(this instanceof Chance)) {
if (!seed) { seed = null; } // handle other non-truthy seeds, as described in issue #322
return seed === null ? new Chance() : new Chance(seed);
}
// if user has provided a function, use that as the generator
if (typeof seed === 'function') {
this.random = seed;
return this;
}
if (arguments.length) {
// set a starting value of zero so we can add to it
this.seed = 0;
}
// otherwise, leave this.seed blank so that MT will receive a blank
for (var i = 0; i < arguments.length; i++) {
var seedling = 0;
if (Object.prototype.toString.call(arguments[i]) === '[object String]') {
for (var j = 0; j < arguments[i].length; j++) {
// create a numeric hash for each argument, add to seedling
var hash = 0;
for (var k = 0; k < arguments[i].length; k++) {
hash = arguments[i].charCodeAt(k) + (hash << 6) + (hash << 16) - hash;
}
seedling += hash;
}
} else {
seedling = arguments[i];
}
this.seed += (arguments.length - i) * seedling;
}
// If no generator function was provided, use our MT
this.mt = this.mersenne_twister(this.seed);
this.bimd5 = this.blueimp_md5();
this.random = function () {
return this.mt.random(this.seed);
};
return this;
}
Chance.prototype.VERSION = "1.1.12";
// Random helper functions
function initOptions(options, defaults) {
options = options || {};
if (defaults) {
for (var i in defaults) {
if (typeof options[i] === 'undefined') {
options[i] = defaults[i];
}
}
}
return options;
}
function range(size) {
return Array.apply(null, Array(size)).map(function (_, i) {return i;});
}
function testRange(test, errorMessage) {
if (test) {
throw new RangeError(errorMessage);
}
}
/**
* Encode the input string with Base64.
*/
var base64 = function() {
throw new Error('No Base64 encoder available.');
};
// Select proper Base64 encoder.
(function determineBase64Encoder() {
if (typeof btoa === 'function') {
base64 = btoa;
} else if (typeof Buffer === 'function') {
base64 = function(input) {
return new Buffer(input).toString('base64');
};
}
})();
// -- Basics --
/**
* Return a random bool, either true or false
*
* @param {Object} [options={ likelihood: 50 }] alter the likelihood of
* receiving a true or false value back.
* @throws {RangeError} if the likelihood is out of bounds
* @returns {Bool} either true or false
*/
Chance.prototype.bool = function (options) {
// likelihood of success (true)
options = initOptions(options, {likelihood : 50});
// Note, we could get some minor perf optimizations by checking range
// prior to initializing defaults, but that makes code a bit messier
// and the check more complicated as we have to check existence of
// the object then existence of the key before checking constraints.
// Since the options initialization should be minor computationally,
// decision made for code cleanliness intentionally. This is mentioned
// here as it's the first occurrence, will not be mentioned again.
testRange(
options.likelihood < 0 || options.likelihood > 100,
"Chance: Likelihood accepts values from 0 to 100."
);
return this.random() * 100 < options.likelihood;
};
Chance.prototype.falsy = function (options) {
// return a random falsy value
options = initOptions(options, {pool: [false, null, 0, NaN, '', undefined]})
var pool = options.pool,
index = this.integer({min: 0, max: pool.length - 1}),
value = pool[index];
return value;
}
Chance.prototype.animal = function (options){
//returns a random animal
options = initOptions(options);
if(typeof options.type !== 'undefined'){
//if user does not put in a valid animal type, user will get an error
testRange(
!this.get("animals")[options.type.toLowerCase()],
"Please pick from desert, ocean, grassland, forest, zoo, pets, farm."
);
//if user does put in valid animal type, will return a random animal of that type
return this.pick(this.get("animals")[options.type.toLowerCase()]);
}
//if user does not put in any animal type, will return a random animal regardless
var animalTypeArray = ["desert","forest","ocean","zoo","farm","pet","grassland"];
return this.pick(this.get("animals")[this.pick(animalTypeArray)]);
};
/**
* Return a random character.
*
* @param {Object} [options={}] can specify a character pool or alpha,
* numeric, symbols and casing (lower or upper)
* @returns {String} a single random character
*/
Chance.prototype.character = function (options) {
options = initOptions(options);
var symbols = "!@#$%^&*()[]",
letters, pool;
if (options.casing === 'lower') {
letters = CHARS_LOWER;
} else if (options.casing === 'upper') {
letters = CHARS_UPPER;
} else {
letters = CHARS_LOWER + CHARS_UPPER;
}
if (options.pool) {
pool = options.pool;
} else {
pool = '';
if (options.alpha) {
pool += letters;
}
if (options.numeric) {
pool += NUMBERS;
}
if (options.symbols) {
pool += symbols;
}
if (!pool) {
pool = letters + NUMBERS + symbols;
}
}
return pool.charAt(this.natural({max: (pool.length - 1)}));
};
// Note, wanted to use "float" or "double" but those are both JS reserved words.
// Note, fixed means N OR LESS digits after the decimal. This because
// It could be 14.9000 but in JavaScript, when this is cast as a number,
// the trailing zeroes are dropped. Left to the consumer if trailing zeroes are
// needed
/**
* Return a random floating point number
*
* @param {Object} [options={}] can specify a fixed precision, min, max
* @returns {Number} a single floating point number
* @throws {RangeError} Can only specify fixed or precision, not both. Also
* min cannot be greater than max
*/
Chance.prototype.floating = function (options) {
options = initOptions(options, {fixed : 4});
testRange(
options.fixed && options.precision,
"Chance: Cannot specify both fixed and precision."
);
var num;
var fixed = Math.pow(10, options.fixed);
var max = MAX_INT / fixed;
var min = -max;
testRange(
options.min && options.fixed && options.min < min,
"Chance: Min specified is out of range with fixed. Min should be, at least, " + min
);
testRange(
options.max && options.fixed && options.max > max,
"Chance: Max specified is out of range with fixed. Max should be, at most, " + max
);
options = initOptions(options, { min : min, max : max });
// Todo - Make this work!
// options.precision = (typeof options.precision !== "undefined") ? options.precision : false;
num = this.integer({min: options.min * fixed, max: options.max * fixed});
var num_fixed = (num / fixed).toFixed(options.fixed);
return parseFloat(num_fixed);
};
/**
* Return a random integer
*
* NOTE the max and min are INCLUDED in the range. So:
* chance.integer({min: 1, max: 3});
* would return either 1, 2, or 3.
*
* @param {Object} [options={}] can specify a min and/or max
* @returns {Number} a single random integer number
* @throws {RangeError} min cannot be greater than max
*/
Chance.prototype.integer = function (options) {
// 9007199254740992 (2^53) is the max integer number in JavaScript
// See: http://vq.io/132sa2j
options = initOptions(options, {min: MIN_INT, max: MAX_INT});
testRange(options.min > options.max, "Chance: Min cannot be greater than Max.");
return Math.floor(this.random() * (options.max - options.min + 1) + options.min);
};
/**
* Return a random natural
*
* NOTE the max and min are INCLUDED in the range. So:
* chance.natural({min: 1, max: 3});
* would return either 1, 2, or 3.
*
* @param {Object} [options={}] can specify a min and/or max or a numerals count.
* @returns {Number} a single random integer number
* @throws {RangeError} min cannot be greater than max
*/
Chance.prototype.natural = function (options) {
options = initOptions(options, {min: 0, max: MAX_INT});
if (typeof options.numerals === 'number'){
testRange(options.numerals < 1, "Chance: Numerals cannot be less than one.");
options.min = Math.pow(10, options.numerals - 1);
options.max = Math.pow(10, options.numerals) - 1;
}
testRange(options.min < 0, "Chance: Min cannot be less than zero.");
if (options.exclude) {
testRange(!Array.isArray(options.exclude), "Chance: exclude must be an array.")
for (var exclusionIndex in options.exclude) {
testRange(!Number.isInteger(options.exclude[exclusionIndex]), "Chance: exclude must be numbers.")
}
var random = options.min + this.natural({max: options.max - options.min - options.exclude.length})
var sortedExclusions = options.exclude.sort();
for (var sortedExclusionIndex in sortedExclusions) {
if (random < sortedExclusions[sortedExclusionIndex]) {
break
}
random++
}
return random
}
return this.integer(options);
};
/**
* Return a random prime number
*
* NOTE the max and min are INCLUDED in the range.
*
* @param {Object} [options={}] can specify a min and/or max
* @returns {Number} a single random prime number
* @throws {RangeError} min cannot be greater than max nor negative
*/
Chance.prototype.prime = function (options) {
options = initOptions(options, {min: 0, max: 10000});
testRange(options.min < 0, "Chance: Min cannot be less than zero.");
testRange(options.min > options.max, "Chance: Min cannot be greater than Max.");
var lastPrime = data.primes[data.primes.length - 1];
if (options.max > lastPrime) {
for (var i = lastPrime + 2; i <= options.max; ++i) {
if (this.is_prime(i)) {
data.primes.push(i);
}
}
}
var targetPrimes = data.primes.filter(function (prime) {
return prime >= options.min && prime <= options.max;
});
return this.pick(targetPrimes);
};
/**
* Determine whether a given number is prime or not.
*/
Chance.prototype.is_prime = function (n) {
if (n % 1 || n < 2) {
return false;
}
if (n % 2 === 0) {
return n === 2;
}
if (n % 3 === 0) {
return n === 3;
}
var m = Math.sqrt(n);
for (var i = 5; i <= m; i += 6) {
if (n % i === 0 || n % (i + 2) === 0) {
return false;
}
}
return true;
};
/**
* Return a random hex number as string
*
* NOTE the max and min are INCLUDED in the range. So:
* chance.hex({min: '9', max: 'B'});
* would return either '9', 'A' or 'B'.
*
* @param {Object} [options={}] can specify a min and/or max and/or casing
* @returns {String} a single random string hex number
* @throws {RangeError} min cannot be greater than max
*/
Chance.prototype.hex = function (options) {
options = initOptions(options, {min: 0, max: MAX_INT, casing: 'lower'});
testRange(options.min < 0, "Chance: Min cannot be less than zero.");
var integer = this.natural({min: options.min, max: options.max});
if (options.casing === 'upper') {
return integer.toString(16).toUpperCase();
}
return integer.toString(16);
};
Chance.prototype.letter = function(options) {
options = initOptions(options, {casing: 'lower'});
var pool = "abcdefghijklmnopqrstuvwxyz";
var letter = this.character({pool: pool});
if (options.casing === 'upper') {
letter = letter.toUpperCase();
}
return letter;
}
/**
* Return a random string
*
* @param {Object} [options={}] can specify a length or min and max
* @returns {String} a string of random length
* @throws {RangeError} length cannot be less than zero
*/
Chance.prototype.string = function (options) {
options = initOptions(options, { min: 5, max: 20 });
if (options.length !== 0 && !options.length) {
options.length = this.natural({ min: options.min, max: options.max })
}
testRange(options.length < 0, "Chance: Length cannot be less than zero.");
var length = options.length,
text = this.n(this.character, length, options);
return text.join("");
};
function CopyToken(c) {
this.c = c
}
CopyToken.prototype = {
substitute: function () {
return this.c
}
}
function EscapeToken(c) {
this.c = c
}
EscapeToken.prototype = {
substitute: function () {
if (!/[{}\\]/.test(this.c)) {
throw new Error('Invalid escape sequence: "\\' + this.c + '".')
}
return this.c
}
}
function ReplaceToken(c) {
this.c = c
}
ReplaceToken.prototype = {
replacers: {
'#': function (chance) { return chance.character({ pool: NUMBERS }) },
'A': function (chance) { return chance.character({ pool: CHARS_UPPER }) },
'a': function (chance) { return chance.character({ pool: CHARS_LOWER }) },
},
substitute: function (chance) {
var replacer = this.replacers[this.c]
if (!replacer) {
throw new Error('Invalid replacement character: "' + this.c + '".')
}
return replacer(chance)
}
}
function parseTemplate(template) {
var tokens = []
var mode = 'identity'
for (var i = 0; i<template.length; i++) {
var c = template[i]
switch (mode) {
case 'escape':
tokens.push(new EscapeToken(c))
mode = 'identity'
break
case 'identity':
if (c === '{') {
mode = 'replace'
} else if (c === '\\') {
mode = 'escape'
} else {
tokens.push(new CopyToken(c))
}
break
case 'replace':
if (c === '}') {
mode = 'identity'
} else {
tokens.push(new ReplaceToken(c))
}
break
}
}
return tokens
}
/**
* Return a random string matching the given template.
*
* The template consists of any number of "character replacement" and
* "character literal" sequences. A "character replacement" sequence
* starts with a left brace, has any number of special replacement
* characters, and ends with a right brace. A character literal can be any
* character except a brace or a backslash. A literal brace or backslash
* character can be included in the output by escaping with a backslash.
*
* The following replacement characters can be used in a replacement
* sequence:
*
* "#": a random digit
* "a": a random lower case letter
* "A": a random upper case letter
*
* Example: chance.template('{AA###}-{##}')
*
* @param {String} template string.
* @returns {String} a random string matching the template.
*/
Chance.prototype.template = function (template) {
if (!template) {
throw new Error('Template string is required')
}
var self = this
return parseTemplate(template)
.map(function (token) { return token.substitute(self) })
.join('');
};
/**
* Return a random buffer
*
* @param {Object} [options={}] can specify a length
* @returns {Buffer} a buffer of random length
* @throws {RangeError} length cannot be less than zero
*/
Chance.prototype.buffer = function (options) {
if (typeof Buffer === 'undefined') {
throw new UnsupportedError('Sorry, the buffer() function is not supported on your platform');
}
options = initOptions(options, { length: this.natural({min: 5, max: 20}) });
testRange(options.length < 0, "Chance: Length cannot be less than zero.");
var length = options.length;
var content = this.n(this.character, length, options);
return Buffer.from(content);
};
// -- End Basics --
// -- Helpers --
Chance.prototype.capitalize = function (word) {
return word.charAt(0).toUpperCase() + word.substr(1);
};
Chance.prototype.mixin = function (obj) {
for (var func_name in obj) {
this[func_name] = obj[func_name];
}
return this;
};
/**
* Given a function that generates something random and a number of items to generate,
* return an array of items where none repeat.
*
* @param {Function} fn the function that generates something random
* @param {Number} num number of terms to generate
* @param {Object} options any options to pass on to the generator function
* @returns {Array} an array of length `num` with every item generated by `fn` and unique
*
* There can be more parameters after these. All additional parameters are provided to the given function
*/
Chance.prototype.unique = function(fn, num, options) {
testRange(
typeof fn !== "function",
"Chance: The first argument must be a function."
);
var comparator = function(arr, val) { return arr.indexOf(val) !== -1; };
if (options) {
comparator = options.comparator || comparator;
}
var arr = [], count = 0, result, MAX_DUPLICATES = num * 50, params = slice.call(arguments, 2);
while (arr.length < num) {
var clonedParams = JSON.parse(JSON.stringify(params));
result = fn.apply(this, clonedParams);
if (!comparator(arr, result)) {
arr.push(result);
// reset count when unique found
count = 0;
}
if (++count > MAX_DUPLICATES) {
throw new RangeError("Chance: num is likely too large for sample set");
}
}
return arr;
};
/**
* Gives an array of n random terms
*
* @param {Function} fn the function that generates something random
* @param {Number} n number of terms to generate
* @returns {Array} an array of length `n` with items generated by `fn`
*
* There can be more parameters after these. All additional parameters are provided to the given function
*/
Chance.prototype.n = function(fn, n) {
testRange(
typeof fn !== "function",
"Chance: The first argument must be a function."
);
if (typeof n === 'undefined') {
n = 1;
}
var i = n, arr = [], params = slice.call(arguments, 2);
// Providing a negative count should result in a noop.
i = Math.max( 0, i );
for (null; i--; null) {
arr.push(fn.apply(this, params));
}
return arr;
};
// H/T to SO for this one: http://vq.io/OtUrZ5
Chance.prototype.pad = function (number, width, pad) {
// Default pad to 0 if none provided
pad = pad || '0';
// Convert number to a string
number = number + '';
return number.length >= width ? number : new Array(width - number.length + 1).join(pad) + number;
};
// DEPRECATED on 2015-10-01
Chance.prototype.pick = function (arr, count) {
if (arr.length === 0) {
throw new RangeError("Chance: Cannot pick() from an empty array");
}
if (!count || count === 1) {
return arr[this.natural({max: arr.length - 1})];
} else {
return this.shuffle(arr).slice(0, count);
}
};
// Given an array, returns a single random element
Chance.prototype.pickone = function (arr) {
if (arr.length === 0) {
throw new RangeError("Chance: Cannot pickone() from an empty array");
}
return arr[this.natural({max: arr.length - 1})];
};
// Given an array, returns a random set with 'count' elements
Chance.prototype.pickset = function (arr, count) {
if (count === 0) {
return [];
}
if (arr.length === 0) {
throw new RangeError("Chance: Cannot pickset() from an empty array");
}
if (count < 0) {
throw new RangeError("Chance: Count must be a positive number");
}
if (!count || count === 1) {
return [ this.pickone(arr) ];
} else {
var array = arr.slice(0);
var end = array.length;
return this.n(function () {
var index = this.natural({max: --end});
var value = array[index];
array[index] = array[end];
return value;
}, Math.min(end, count));
}
};
Chance.prototype.shuffle = function (arr) {
var new_array = [],
j = 0,
length = Number(arr.length),
source_indexes = range(length),
last_source_index = length - 1,
selected_source_index;
for (var i = 0; i < length; i++) {
// Pick a random index from the array
selected_source_index = this.natural({max: last_source_index});
j = source_indexes[selected_source_index];
// Add it to the new array
new_array[i] = arr[j];
// Mark the source index as used
source_indexes[selected_source_index] = source_indexes[last_source_index];
last_source_index -= 1;
}
return new_array;
};
// Returns a single item from an array with relative weighting of odds
Chance.prototype.weighted = function (arr, weights, trim) {
if (arr.length !== weights.length) {
throw new RangeError("Chance: Length of array and weights must match");
}
// scan weights array and sum valid entries
var sum = 0;
var val;
for (var weightIndex = 0; weightIndex < weights.length; ++weightIndex) {
val = weights[weightIndex];
if (isNaN(val)) {
throw new RangeError("Chance: All weights must be numbers");
}
if (val > 0) {
sum += val;
}
}
if (sum === 0) {
throw new RangeError("Chance: No valid entries in array weights");
}
// select a value within range
var selected = this.random() * sum;
// find array entry corresponding to selected value
var total = 0;
var lastGoodIdx = -1;
var chosenIdx;
for (weightIndex = 0; weightIndex < weights.length; ++weightIndex) {
val = weights[weightIndex];
total += val;
if (val > 0) {
if (selected <= total) {
chosenIdx = weightIndex;
break;
}
lastGoodIdx = weightIndex;
}
// handle any possible rounding error comparison to ensure something is picked
if (weightIndex === (weights.length - 1)) {
chosenIdx = lastGoodIdx;
}
}
var chosen = arr[chosenIdx];
trim = (typeof trim === 'undefined') ? false : trim;
if (trim) {
arr.splice(chosenIdx, 1);
weights.splice(chosenIdx, 1);
}
return chosen;
};
// -- End Helpers --
// -- Text --
Chance.prototype.paragraph = function (options) {
options = initOptions(options);
var sentences = options.sentences || this.natural({min: 3, max: 7}),
sentence_array = this.n(this.sentence, sentences),
separator = options.linebreak === true ? '\n' : ' ';
return sentence_array.join(separator);
};
// Could get smarter about this than generating random words and
// chaining them together. Such as: http://vq.io/1a5ceOh
Chance.prototype.sentence = function (options) {
options = initOptions(options);
var words = options.words || this.natural({min: 12, max: 18}),
punctuation = options.punctuation,
text, word_array = this.n(this.word, words);
text = word_array.join(' ');
// Capitalize first letter of sentence
text = this.capitalize(text);
// Make sure punctuation has a usable value
if (punctuation !== false && !/^[.?;!:]$/.test(punctuation)) {
punctuation = '.';
}
// Add punctuation mark
if (punctuation) {
text += punctuation;
}
return text;
};
Chance.prototype.syllable = function (options) {
options = initOptions(options);
var length = options.length || this.natural({min: 2, max: 3}),
consonants = 'bcdfghjklmnprstvwz', // consonants except hard to speak ones
vowels = 'aeiou', // vowels
all = consonants + vowels, // all
text = '',
chr;
// I'm sure there's a more elegant way to do this, but this works
// decently well.
for (var i = 0; i < length; i++) {
if (i === 0) {
// First character can be anything
chr = this.character({pool: all});
} else if (consonants.indexOf(chr) === -1) {
// Last character was a vowel, now we want a consonant
chr = this.character({pool: consonants});
} else {
// Last character was a consonant, now we want a vowel
chr = this.character({pool: vowels});
}
text += chr;
}
if (options.capitalize) {
text = this.capitalize(text);
}
return text;
};
Chance.prototype.word = function (options) {
options = initOptions(options);
testRange(
options.syllables && options.length,
"Chance: Cannot specify both syllables AND length."
);
var syllables = options.syllables || this.natural({min: 1, max: 3}),
text = '';
if (options.length) {
// Either bound word by length
do {
text += this.syllable();
} while (text.length < options.length);
text = text.substring(0, options.length);
} else {
// Or by number of syllables
for (var i = 0; i < syllables; i++) {
text += this.syllable();
}
}
if (options.capitalize) {
text = this.capitalize(text);
}
return text;
};
Chance.prototype.emoji = function (options) {
options = initOptions(options, { category: "all", length: 1 });
testRange(
options.length < 1 || BigInt(options.length) > BigInt(MAX_INT),
"Chance: length must be between 1 and " + String(MAX_INT)
);
var emojis = this.get("emojis");
if (options.category === "all") {
options.category = this.pickone(Object.keys(emojis));
}
var emojisForCategory = emojis[options.category];
testRange(
emojisForCategory === undefined,
"Chance: Unrecognised emoji category: [" + options.category + "]."
);
return this.pickset(emojisForCategory, options.length)
.map(function (codePoint) {
return String.fromCodePoint(codePoint);
}).join("");
};
// -- End Text --
// -- Person --
Chance.prototype.age = function (options) {
options = initOptions(options);
var ageRange;
switch (options.type) {
case 'child':
ageRange = {min: 0, max: 12};
break;
case 'teen':
ageRange = {min: 13, max: 19};
break;
case 'adult':
ageRange = {min: 18, max: 65};
break;
case 'senior':
ageRange = {min: 65, max: 100};
break;
case 'all':
ageRange = {min: 0, max: 100};
break;
default:
ageRange = {min: 18, max: 65};
break;
}
return this.natural(ageRange);
};
Chance.prototype.birthday = function (options) {
var age = this.age(options);
var now = new Date()
var currentYear = now.getFullYear();
if (options && options.type) {
var min = new Date();
var max = new Date();
min.setFullYear(currentYear - age - 1);
max.setFullYear(currentYear - age);
options = initOptions(options, {
min: min,
max: max
});
} else if (options && ((options.minAge !== undefined) || (options.maxAge !== undefined))) {
testRange(options.minAge < 0, "Chance: MinAge cannot be less than zero.");
testRange(options.minAge > options.maxAge, "Chance: MinAge cannot be greater than MaxAge.");
var minAge = options.minAge !== undefined ? options.minAge : 0;
var maxAge = options.maxAge !== undefined ? options.maxAge : 100;
var minDate = new Date(currentYear - maxAge - 1, now.getMonth(), now.getDate());
var maxDate = new Date(currentYear - minAge, now.getMonth(), now.getDate());
minDate.setDate(minDate.getDate() +1);
maxDate.setDate(maxDate.getDate() +1);
maxDate.setMilliseconds(maxDate.getMilliseconds() -1);
options = initOptions(options, {
min: minDate,
max: maxDate
});
} else {
options = initOptions(options, {
year: currentYear - age
});
}
return this.date(options);
};
// CPF; ID to identify taxpayers in Brazil
Chance.prototype.cpf = function (options) {
options = initOptions(options, {
formatted: true
});
var n = this.n(this.natural, 9, { max: 9 });
var d1 = n[8]*2+n[7]*3+n[6]*4+n[5]*5+n[4]*6+n[3]*7+n[2]*8+n[1]*9+n[0]*10;
d1 = 11 - (d1 % 11);
if (d1>=10) {
d1 = 0;
}
var d2 = d1*2+n[8]*3+n[7]*4+n[6]*5+n[5]*6+n[4]*7+n[3]*8+n[2]*9+n[1]*10+n[0]*11;
d2 = 11 - (d2 % 11);
if (d2>=10) {
d2 = 0;
}
var cpf = ''+n[0]+n[1]+n[2]+'.'+n[3]+n[4]+n[5]+'.'+n[6]+n[7]+n[8]+'-'+d1+d2;
return options.formatted ? cpf : cpf.replace(/\D/g,'');
};
// CNPJ: ID to identify companies in Brazil
Chance.prototype.cnpj = function (options) {
options = initOptions(options, {
formatted: true
});
var n = this.n(this.natural, 12, { max: 12 });
var d1 = n[11]*2+n[10]*3+n[9]*4+n[8]*5+n[7]*6+n[6]*7+n[5]*8+n[4]*9+n[3]*2+n[2]*3+n[1]*4+n[0]*5;
d1 = 11 - (d1 % 11);
if (d1<2) {
d1 = 0;
}
var d2 = d1*2+n[11]*3+n[10]*4+n[9]*5+n[8]*6+n[7]*7+n[6]*8+n[5]*9+n[4]*2+n[3]*3+n[2]*4+n[1]*5+n[0]*6;
d2 = 11 - (d2 % 11);
if (d2<2) {
d2 = 0;
}
var cnpj = ''+n[0]+n[1]+'.'+n[2]+n[3]+n[4]+'.'+n[5]+n[6]+n[7]+'/'+n[8]+n[9]+n[10]+n[11]+'-'+d1+d2;
return options.formatted ? cnpj : cnpj.replace(/\D/g,'');
};
Chance.prototype.first = function (options) {
options = initOptions(options, {gender: this.gender(), nationality: 'en'});
return this.pick(this.get("firstNames")[options.gender.toLowerCase()][options.nationality.toLowerCase()]);
};
Chance.prototype.profession = function (options) {
options = initOptions(options);
if(options.rank){
return this.pick(['Apprentice ', 'Junior ', 'Senior ', 'Lead ']) + this.pick(this.get("profession"));
} else{
return this.pick(this.get("profession"));
}
};
Chance.prototype.company = function (){
return this.pick(this.get("company"));
};
Chance.prototype.gender = function (options) {
options = initOptions(options, {extraGenders: []});
return this.pick(['Male', 'Female'].concat(options.extraGenders));
};
Chance.prototype.last = function (options) {
options = initOptions(options, {nationality: '*'});
if (options.nationality === "*") {
var allLastNames = []
var lastNames = this.get("lastNames")
Object.keys(lastNames).forEach(function(key){
allLastNames = allLastNames.concat(lastNames[key])
})
return this.pick(allLastNames)
}
else {
return this.pick(this.get("lastNames")[options.nationality.toLowerCase()]);
}
};
Chance.prototype.israelId=function(){
var x=this.string({pool: '0123456789',length:8});
var y=0;
for (var i=0;i<x.length;i++){
var thisDigit= x[i] * (i/2===parseInt(i/2) ? 1 : 2);
thisDigit=this.pad(thisDigit,2).toString();
thisDigit=parseInt(thisDigit[0]) + parseInt(thisDigit[1]);
y=y+thisDigit;
}
x=x+(10-parseInt(y.toString().slice(-1))).toString().slice(-1);
return x;
};
Chance.prototype.mrz = function (options) {
var checkDigit = function (input) {
var alpha = "<ABCDEFGHIJKLMNOPQRSTUVWXYXZ".split(''),
multipliers = [ 7, 3, 1 ],
runningTotal = 0;
if (typeof input !== 'string') {
input = input.toString();
}
input.split('').forEach(function(character, idx) {
var pos = alpha.indexOf(character);
if(pos !== -1) {
character = pos === 0 ? 0 : pos + 9;
} else {
character = parseInt(character, 10);
}
character *= multipliers[idx % multipliers.length];
runningTotal += character;
});
return runningTotal % 10;
};
var generate = function (opts) {
var pad = function (length) {
return new Array(length + 1).join('<');
};
var number = [ 'P<',
opts.issuer,
opts.last.toUpperCase(),
'<<',
opts.first.toUpperCase(),
pad(39 - (opts.last.length + opts.first.length + 2)),
opts.passportNumber,
checkDigit(opts.passportNumber),
opts.nationality,
opts.dob,
checkDigit(opts.dob),
opts.gender,
opts.expiry,
checkDigit(opts.expiry),
pad(14),
checkDigit(pad(14)) ].join('');
return number +
(checkDigit(number.substr(44, 10) +
number.substr(57, 7) +
number.substr(65, 7)));
};
var that = this;
options = initOptions(options, {
first: this.first(),
last: this.last(),
passportNumber: this.integer({min: 100000000, max: 999999999}),
dob: (function () {
var date = that.birthday({type: 'adult'});
return [date.getFullYear().toString().substr(2),
that.pad(date.getMonth() + 1, 2),
that.pad(date.getDate(), 2)].join('');
}()),
expiry: (function () {
var date = new Date();
return [(date.getFullYear() + 5).toString().substr(2),
that.pad(date.getMonth() + 1, 2),
that.pad(date.getDate(), 2)].join('');
}()),
gender: this.gender() === 'Female' ? 'F': 'M',
issuer: 'GBR',
nationality: 'GBR'
});
return generate (options);
};
Chance.prototype.name = function (options) {
options = initOptions(options);
var first = this.first(options),
last = this.last(options),
name;
if (options.middle) {
name = first + ' ' + this.first(options) + ' ' + last;
} else if (options.middle_initial) {
name = first + ' ' + this.character({alpha: true, casing: 'upper'}) + '. ' + last;
} else {
name = first + ' ' + last;
}
if (options.prefix) {
name = this.prefix(options) + ' ' + name;
}
if (options.suffix) {
name = name + ' ' + this.suffix(options);
}
return name;
};
// Return the list of available name prefixes based on supplied gender.
// @todo introduce internationalization
Chance.prototype.name_prefixes = function (gender) {
gender = gender || "all";
gender = gender.toLowerCase();
var prefixes = [
{ name: 'Doctor', abbreviation: 'Dr.' }
];
if (gender === "male" || gender === "all") {
prefixes.push({ name: 'Mister', abbreviation: 'Mr.' });
}
if (gender === "female" || gender === "all") {
prefixes.push({ name: 'Miss', abbreviation: 'Miss' });
prefixes.push({ name: 'Misses', abbreviation: 'Mrs.' });
}
return prefixes;
};
// Alias for name_prefix
Chance.prototype.prefix = function (options) {
return this.name_prefix(options);
};
Chance.prototype.name_prefix = function (options) {
options = initOptions(options, { gender: "all" });
return options.full ?
this.pick(this.name_prefixes(options.gender)).name :
this.pick(this.name_prefixes(options.gender)).abbreviation;
};
//Hungarian ID number
Chance.prototype.HIDN= function(){
//Hungarian ID nuber structure: XXXXXXYY (X=number,Y=Capital Latin letter)
var idn_pool="0123456789";
var idn_chrs="ABCDEFGHIJKLMNOPQRSTUVWXYXZ";
var idn="";
idn+=this.string({pool:idn_pool,length:6});
idn+=this.string({pool:idn_chrs,length:2});
return idn;
};
Chance.prototype.ssn = function (options) {
options = initOptions(options, {ssnFour: false, dashes: true});
var ssn_pool = "1234567890",
ssn,
dash = options.dashes ? '-' : '';
if(!options.ssnFour) {
ssn = this.string({pool: ssn_pool, length: 3}) + dash +
this.string({pool: ssn_pool, length: 2}) + dash +
this.string({pool: ssn_pool, length: 4});
} else {
ssn = this.string({pool: ssn_pool, length: 4});
}
return ssn;
};
// Aadhar is similar to ssn, used in India to uniquely identify a person
Chance.prototype.aadhar = function (options) {
options = initOptions(options, {onlyLastFour: false, separatedByWhiteSpace: true});
var aadhar_pool = "1234567890",
aadhar,
whiteSpace = options.separatedByWhiteSpace ? ' ' : '';
if(!options.onlyLastFour) {
aadhar = this.string({pool: aadhar_pool, length: 4}) + whiteSpace +
this.string({pool: aadhar_pool, length: 4}) + whiteSpace +
this.string({pool: aadhar_pool, length: 4});
} else {
aadhar = this.string({pool: aadhar_pool, length: 4});
}
return aadhar;
};
// Return the list of available name suffixes
// @todo introduce internationalization
Chance.prototype.name_suffixes = function () {
var suffixes = [
{ name: 'Doctor of Osteopathic Medicine', abbreviation: 'D.O.' },
{ name: 'Doctor of Philosophy', abbreviation: 'Ph.D.' },
{ name: 'Esquire', abbreviation: 'Esq.' },
{ name: 'Junior', abbreviation: 'Jr.' },
{ name: 'Juris Doctor', abbreviation: 'J.D.' },
{ name: 'Master of Arts', abbreviation: 'M.A.' },
{ name: 'Master of Business Administration', abbreviation: 'M.B.A.' },
{ name: 'Master of Science', abbreviation: 'M.S.' },
{ name: 'Medical Doctor', abbreviation: 'M.D.' },
{ name: 'Senior', abbreviation: 'Sr.' },
{ name: 'The Third', abbreviation: 'III' },
{ name: 'The Fourth', abbreviation: 'IV' },
{ name: 'Bachelor of Engineering', abbreviation: 'B.E' },
{ name: 'Bachelor of Technology', abbreviation: 'B.TECH' }
];
return suffixes;
};
// Alias for name_suffix
Chance.prototype.suffix = function (options) {
return this.name_suffix(options);
};
Chance.prototype.name_suffix = function (options) {
options = initOptions(options);
return options.full ?
this.pick(this.name_suffixes()).name :
this.pick(this.name_suffixes()).abbreviation;
};
Chance.prototype.nationalities = function () {
return this.get("nationalities");
};
// Generate random nationality based on json list
Chance.prototype.nationality = function () {
var nationality = this.pick(this.nationalities());
return nationality.name;
};
// Generate random zodiac sign
Chance.prototype.zodiac = function () {
const zodiacSymbols = ["Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra","Scorpio","Sagittarius","Capricorn","Aquarius","Pisces"];
return this.pickone(zodiacSymbols);
};
// -- End Person --
// -- Mobile --
// Android GCM Registration ID
Chance.prototype.android_id = function () {
return "APA91" + this.string({ pool: "0123456789abcefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_", length: 178 });
};
// Apple Push Token
Chance.prototype.apple_token = function () {
return this.string({ pool: "abcdef1234567890", length: 64 });
};
// Windows Phone 8 ANID2
Chance.prototype.wp8_anid2 = function () {
return base64( this.hash( { length : 32 } ) );
};
// Windows Phone 7 ANID
Chance.prototype.wp7_anid = function () {
return 'A=' + this.guid().replace(/-/g, '').toUpperCase() + '&E=' + this.hash({ length:3 }) + '&W=' + this.integer({ min:0, max:9 });
};
// BlackBerry Device PIN
Chance.prototype.bb_pin = function () {
return this.hash({ length: 8 });
};
// -- End Mobile --
// -- Web --
Chance.prototype.avatar = function (options) {
var url = null;
var URL_BASE = '//www.gravatar.com/avatar/';
var PROTOCOLS = {
http: 'http',
https: 'https'
};
var FILE_TYPES = {
bmp: 'bmp',
gif: 'gif',
jpg: 'jpg',
png: 'png'
};
var FALLBACKS = {
'404': '404', // Return 404 if not found
mm: 'mm', // Mystery man
identicon: 'identicon', // Geometric pattern based on hash
monsterid: 'monsterid', // A generated monster icon
wavatar: 'wavatar', // A generated face
retro: 'retro', // 8-bit icon
blank: 'blank' // A transparent png
};
var RATINGS = {
g: 'g',
pg: 'pg',
r: 'r',
x: 'x'
};
var opts = {
protocol: null,
email: null,
fileExtension: null,
size: null,
fallback: null,
rating: null
};
if (!options) {
// Set to a random email
opts.email = this.email();
options = {};
}
else if (typeof options === 'string') {
opts.email = options;
options = {};
}
else if (typeof options !== 'object') {
return null;
}
else if (options.constructor === 'Array') {
return null;
}
opts = initOptions(options, opts);
if (!opts.email) {
// Set to a random email
opts.email = this.email();
}
// Safe checking for params
opts.protocol = PROTOCOLS[opts.protocol] ? opts.protocol + ':' : '';
opts.size = parseInt(opts.size, 0) ? opts.size : '';
opts.rating = RATINGS[opts.rating] ? opts.rating : '';
opts.fallback = FALLBACKS[opts.fallback] ? opts.fallback : '';
opts.fileExtension = FILE_TYPES[opts.fileExtension] ? opts.fileExtension : '';
url =
opts.protocol +
URL_BASE +
this.bimd5.md5(opts.email) +
(opts.fileExtension ? '.' + opts.fileExtension : '') +
(opts.size || opts.rating || opts.fallback ? '?' : '') +
(opts.size ? '&s=' + opts.size.toString() : '') +
(opts.rating ? '&r=' + opts.rating : '') +
(opts.fallback ? '&d=' + opts.fallback : '')
;
return url;
};
/**
* #Description:
* ===============================================
* Generate random color value base on color type:
* -> hex
* -> rgb
* -> rgba
* -> 0x
* -> named color
*
* #Examples:
* ===============================================
* * Geerate random hex color
* chance.color() => '#79c157' / 'rgb(110,52,164)' / '0x67ae0b' / '#e2e2e2' / '#29CFA7'
*
* * Generate Hex based color value
* chance.color({format: 'hex'}) => '#d67118'
*
* * Generate simple rgb value
* chance.color({format: 'rgb'}) => 'rgb(110,52,164)'
*
* * Generate Ox based color value
* chance.color({format: '0x'}) => '0x67ae0b'
*
* * Generate graiscale based value
* chance.color({grayscale: true}) => '#e2e2e2'
*
* * Return valide color name
* chance.color({format: 'name'}) => 'red'
*
* * Make color uppercase
* chance.color({casing: 'upper'}) => '#29CFA7'
*
* * Min Max values for RGBA
* var light_red = chance.color({format: 'hex', min_red: 200, max_red: 255, max_green: 0, max_blue: 0, min_alpha: .2, max_alpha: .3});
*
* @param [object] options
* @return [string] color value
*/
Chance.prototype.color = function (options) {
function gray(value, delimiter) {
return [value, value, value].join(delimiter || '');
}
function rgb(hasAlpha) {
var rgbValue = (hasAlpha) ? 'rgba' : 'rgb';
var alphaChannel = (hasAlpha) ? (',' + this.floating({min:min_alpha, max:max_alpha})) : "";
var colorValue = (isGrayscale) ? (gray(this.natural({min: min_rgb, max: max_rgb}), ',')) : (this.natural({min: min_green, max: max_green}) + ',' + this.natural({min: min_blue, max: max_blue}) + ',' + this.natural({max: 255}));
return rgbValue + '(' + colorValue + alphaChannel + ')