aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShinigami <[email protected]>2022-01-24 19:30:46 +0100
committerGitHub <[email protected]>2022-01-24 19:30:46 +0100
commita3792251766ed9a87a59c760ea87f64792e54caa (patch)
tree9a9dc7ee3b67bf08f9db7b14326385f118d39ca0 /src
parentbe6ea47ffab857e3328bc620502b31732d53d82d (diff)
downloadfaker-a3792251766ed9a87a59c760ea87f64792e54caa.tar.xz
faker-a3792251766ed9a87a59c760ea87f64792e54caa.zip
chore: migrate vendor (#254)
Diffstat (limited to 'src')
-rw-r--r--src/internet.ts2
-rw-r--r--src/mersenne.ts2
-rw-r--r--src/unique.ts13
-rw-r--r--src/vendor/mersenne.ts292
-rw-r--r--src/vendor/unique.ts121
-rw-r--r--src/vendor/user-agent.ts389
6 files changed, 811 insertions, 8 deletions
diff --git a/src/internet.ts b/src/internet.ts
index 6384b155..3b7f0291 100644
--- a/src/internet.ts
+++ b/src/internet.ts
@@ -1,6 +1,6 @@
import type { Faker } from '.';
-const random_ua = require('../vendor/user-agent');
+import * as random_ua from './vendor/user-agent';
export class Internet {
constructor(private readonly faker: Faker) {
diff --git a/src/mersenne.ts b/src/mersenne.ts
index fe7fbb44..7f42501e 100644
--- a/src/mersenne.ts
+++ b/src/mersenne.ts
@@ -1,4 +1,4 @@
-const Gen = require('../vendor/mersenne').MersenneTwister19937;
+import Gen from './vendor/mersenne';
export class Mersenne {
private gen = new Gen();
diff --git a/src/unique.ts b/src/unique.ts
index c077ea58..382d2e2d 100644
--- a/src/unique.ts
+++ b/src/unique.ts
@@ -1,4 +1,4 @@
-const uniqueExec = require('../vendor/unique');
+import * as uniqueExec from './vendor/unique';
export class Unique {
// maximum time unique.exec will attempt to run before aborting
@@ -25,17 +25,18 @@ export class Unique {
*
* @method unique
*/
- unique(
- method: any,
- args: any,
+ unique<Method extends (args: Args) => string, Args extends any[]>(
+ method: Method,
+ args: Args,
opts?: {
startTime?: number;
maxTime?: number;
maxRetries?: number;
currentIterations?: number;
- [key: string]: any;
+ exclude?: string | string[];
+ compare?: (obj: Record<string, string>, key: string) => 0 | -1;
}
- ): any {
+ ): string {
opts ||= {};
opts.startTime = new Date().getTime();
if (typeof opts.maxTime !== 'number') {
diff --git a/src/vendor/mersenne.ts b/src/vendor/mersenne.ts
new file mode 100644
index 00000000..6a94522b
--- /dev/null
+++ b/src/vendor/mersenne.ts
@@ -0,0 +1,292 @@
+// this program is a JavaScript version of Mersenne Twister, with concealment and encapsulation in class,
+// an almost straight conversion from the original program, mt19937ar.c,
+// translated by y. okada on July 17, 2006.
+// and modified a little at july 20, 2006, but there are not any substantial differences.
+// in this program, procedure descriptions and comments of original source code were not removed.
+// lines commented with //c// were originally descriptions of c procedure. and a few following lines are appropriate JavaScript descriptions.
+// lines commented with /* and */ are original comments.
+// lines commented with // are additional comments in this JavaScript version.
+// before using this version, create at least one instance of MersenneTwister19937 class, and initialize the each state, given below in c comments, of all the instances.
+
+/*
+ * A C-program for MT19937, with initialization improved 2002/1/26.
+ * Coded by Takuji Nishimura and Makoto Matsumoto.
+ *
+ * Before using, initialize the state by using init_genrand(seed)
+ * or init_by_array(init_key, key_length).
+ *
+ * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. The names of its contributors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Any feedback is very welcome.
+ * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ * email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+ */
+
+let dbg: number;
+
+function MersenneTwister19937(): void {
+ /* constants should be scoped inside the class */
+ /* Period parameters */
+ //c//#define N 624
+ //c//#define M 397
+ //c//#define MATRIX_A 0x9908b0dfUL /* constant vector a */
+ //c//#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
+ //c//#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
+ const N = 624;
+ const M = 397;
+ const MATRIX_A = 0x9908b0df; /* constant vector a */
+ const UPPER_MASK = 0x80000000; /* most significant w-r bits */
+ const LOWER_MASK = 0x7fffffff; /* least significant r bits */
+ //c//static unsigned long mt[N]; /* the array for the state vector */
+ //c//static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
+ const mt: number[] = new Array(N); /* the array for the state vector */
+ let mti = N + 1; /* mti==N+1 means mt[N] is not initialized */
+
+ function unsigned32(n1: number): number {
+ // returns a 32-bits unsiged integer from an operand to which applied a bit operator.
+ return n1 < 0 ? (n1 ^ UPPER_MASK) + UPPER_MASK : n1;
+ }
+
+ function subtraction32(n1: number, n2: number): number {
+ // emulates lowerflow of a c 32-bits unsiged integer variable, instead of the operator -. these both arguments must be non-negative integers expressible using unsigned 32 bits.
+ return n1 < n2
+ ? unsigned32((0x100000000 - (n2 - n1)) & 0xffffffff)
+ : n1 - n2;
+ }
+
+ function addition32(n1: number, n2: number): number {
+ // emulates overflow of a c 32-bits unsiged integer variable, instead of the operator +. these both arguments must be non-negative integers expressible using unsigned 32 bits.
+ return unsigned32((n1 + n2) & 0xffffffff);
+ }
+
+ function multiplication32(n1: number, n2: number): number {
+ // emulates overflow of a c 32-bits unsiged integer variable, instead of the operator *. these both arguments must be non-negative integers expressible using unsigned 32 bits.
+ let sum = 0;
+ for (let i = 0; i < 32; ++i) {
+ if ((n1 >>> i) & 0x1) {
+ sum = addition32(sum, unsigned32(n2 << i));
+ }
+ }
+ return sum;
+ }
+
+ /* initializes mt[N] with a seed */
+ //c//void init_genrand(unsigned long s)
+ this.init_genrand = function (s: number) {
+ //c//mt[0]= s & 0xffffffff;
+ mt[0] = unsigned32(s & 0xffffffff);
+ for (mti = 1; mti < N; mti++) {
+ mt[mti] =
+ //c//(1812433253 * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
+ addition32(
+ multiplication32(
+ 1812433253,
+ unsigned32(mt[mti - 1] ^ (mt[mti - 1] >>> 30))
+ ),
+ mti
+ );
+ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+ /* In the previous versions, MSBs of the seed affect */
+ /* only MSBs of the array mt[]. */
+ /* 2002/01/09 modified by Makoto Matsumoto */
+ //c//mt[mti] &= 0xffffffff;
+ mt[mti] = unsigned32(mt[mti] & 0xffffffff);
+ /* for >32 bit machines */
+ }
+ };
+
+ /* initialize by an array with array-length */
+ /* init_key is the array for initializing keys */
+ /* key_length is its length */
+ /* slight change for C++, 2004/2/26 */
+ //c//void init_by_array(unsigned long init_key[], int key_length)
+ this.init_by_array = function (init_key, key_length) {
+ //c//init_genrand(19650218);
+ this.init_genrand(19650218);
+ let i = 1;
+ let j = 0;
+ let k = N > key_length ? N : key_length;
+ for (; k; k--) {
+ //c//mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525))
+ //c// + init_key[j] + j; /* non linear */
+ mt[i] = addition32(
+ addition32(
+ unsigned32(
+ mt[i] ^
+ multiplication32(
+ unsigned32(mt[i - 1] ^ (mt[i - 1] >>> 30)),
+ 1664525
+ )
+ ),
+ init_key[j]
+ ),
+ j
+ );
+ mt[i] =
+ //c//mt[i] &= 0xffffffff; /* for WORDSIZE > 32 machines */
+ unsigned32(mt[i] & 0xffffffff);
+ i++;
+ j++;
+ if (i >= N) {
+ mt[0] = mt[N - 1];
+ i = 1;
+ }
+ if (j >= key_length) {
+ j = 0;
+ }
+ }
+ for (k = N - 1; k; k--) {
+ //c//mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941))
+ //c//- i; /* non linear */
+ mt[i] = subtraction32(
+ unsigned32(
+ (dbg = mt[i]) ^
+ multiplication32(
+ unsigned32(mt[i - 1] ^ (mt[i - 1] >>> 30)),
+ 1566083941
+ )
+ ),
+ i
+ );
+ //c//mt[i] &= 0xffffffff; /* for WORDSIZE > 32 machines */
+ mt[i] = unsigned32(mt[i] & 0xffffffff);
+ i++;
+ if (i >= N) {
+ mt[0] = mt[N - 1];
+ i = 1;
+ }
+ }
+ mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */
+ };
+
+ /* moved outside of genrand_int32() by jwatte 2010-11-17; generate less garbage */
+ const mag01 = [0x0, MATRIX_A];
+
+ /* generates a random number on [0,0xffffffff]-interval */
+ //c//unsigned long genrand_int32(void)
+ this.genrand_int32 = function () {
+ //c//unsigned long y;
+ //c//static unsigned long mag01[2]={0x0UL, MATRIX_A};
+ let y: number;
+ /* mag01[x] = x * MATRIX_A for x=0,1 */
+
+ if (mti >= N) {
+ /* generate N words at one time */
+ //c//int kk;
+ let kk: number;
+
+ if (mti == N + 1) {
+ /* if init_genrand() has not been called, */
+ //c//init_genrand(5489); /* a default initial seed is used */
+ this.init_genrand(5489);
+ } /* a default initial seed is used */
+
+ for (kk = 0; kk < N - M; kk++) {
+ //c//y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+ //c//mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1];
+ y = unsigned32((mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK));
+ mt[kk] = unsigned32(mt[kk + M] ^ (y >>> 1) ^ mag01[y & 0x1]);
+ }
+ for (; kk < N - 1; kk++) {
+ //c//y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+ //c//mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1];
+ y = unsigned32((mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK));
+ mt[kk] = unsigned32(mt[kk + (M - N)] ^ (y >>> 1) ^ mag01[y & 0x1]);
+ }
+ //c//y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
+ //c//mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1];
+ y = unsigned32((mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK));
+ mt[N - 1] = unsigned32(mt[M - 1] ^ (y >>> 1) ^ mag01[y & 0x1]);
+ mti = 0;
+ }
+
+ y = mt[mti++];
+
+ /* Tempering */
+ //c//y ^= (y >> 11);
+ //c//y ^= (y << 7) & 0x9d2c5680;
+ //c//y ^= (y << 15) & 0xefc60000;
+ //c//y ^= (y >> 18);
+ y = unsigned32(y ^ (y >>> 11));
+ y = unsigned32(y ^ ((y << 7) & 0x9d2c5680));
+ y = unsigned32(y ^ ((y << 15) & 0xefc60000));
+ y = unsigned32(y ^ (y >>> 18));
+
+ return y;
+ };
+
+ /* generates a random number on [0,0x7fffffff]-interval */
+ //c//long genrand_int31(void)
+ this.genrand_int31 = function (): number {
+ //c//return (genrand_int32()>>1);
+ return this.genrand_int32() >>> 1;
+ };
+
+ /* generates a random number on [0,1]-real-interval */
+ //c//double genrand_real1(void)
+ this.genrand_real1 = function (): number {
+ //c//return genrand_int32()*(1.0/4294967295.0);
+ return this.genrand_int32() * (1.0 / 4294967295.0);
+ /* divided by 2^32-1 */
+ };
+
+ /* generates a random number on [0,1)-real-interval */
+ //c//double genrand_real2(void)
+ this.genrand_real2 = function (): number {
+ //c//return genrand_int32()*(1.0/4294967296.0);
+ return this.genrand_int32() * (1.0 / 4294967296.0);
+ /* divided by 2^32 */
+ };
+
+ /* generates a random number on (0,1)-real-interval */
+ //c//double genrand_real3(void)
+ this.genrand_real3 = function (): number {
+ //c//return ((genrand_int32()) + 0.5)*(1.0/4294967296.0);
+ return (this.genrand_int32() + 0.5) * (1.0 / 4294967296.0);
+ /* divided by 2^32 */
+ };
+
+ /* generates a random number on [0,1) with 53-bit resolution*/
+ //c//double genrand_res53(void)
+ this.genrand_res53 = function (): number {
+ //c//unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
+ const a = this.genrand_int32() >>> 5,
+ b = this.genrand_int32() >>> 6;
+ return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
+ };
+ /* These real versions are due to Isaku Wada, 2002/01/09 added */
+}
+
+// Exports: Public API
+
+// Export the twister class
+export default MersenneTwister19937;
diff --git a/src/vendor/unique.ts b/src/vendor/unique.ts
new file mode 100644
index 00000000..1fc80d5f
--- /dev/null
+++ b/src/vendor/unique.ts
@@ -0,0 +1,121 @@
+// global results store
+// currently uniqueness is global to entire faker instance
+// this means that faker should currently *never* return duplicate values across all API methods when using `Faker.unique`
+// it's possible in the future that some users may want to scope found per function call instead of faker instance
+const found: Record<string, string> = {};
+
+// global exclude list of results
+// defaults to nothing excluded
+const exclude: string[] = [];
+
+// current iteration or retries of unique.exec ( current loop depth )
+let currentIterations = 0;
+
+// uniqueness compare function
+// default behavior is to check value as key against object hash
+function defaultCompare<T, Key extends keyof T>(obj: T, key: Key): 0 | -1 {
+ if (typeof obj[key] === 'undefined') {
+ return -1;
+ }
+ return 0;
+}
+
+// common error handler for messages
+function errorMessage(
+ now: number,
+ code: string,
+ opts: { startTime: number }
+): never {
+ console.error('error', code);
+ console.log(
+ 'found',
+ Object.keys(found).length,
+ 'unique entries before throwing error. \nretried:',
+ currentIterations,
+ '\ntotal time:',
+ now - opts.startTime,
+ 'ms'
+ );
+ throw new Error(
+ code +
+ ' for uniqueness check \n\nMay not be able to generate any more unique values with current settings. \nTry adjusting maxTime or maxRetries parameters for faker.unique()'
+ );
+}
+
+// TODO @Shinigami92 2022-01-24: We should investigate deeper into the types
+// Especially the `opts.compare` parameter and `Result` type
+export function exec<Method extends (args: Args) => string, Args extends any[]>(
+ method: Method,
+ args: Args,
+ opts: {
+ maxTime?: number;
+ maxRetries?: number;
+ exclude?: string | string[];
+ compare?: (obj: Record<string, string>, key: string) => 0 | -1;
+ currentIterations?: number;
+ startTime?: number;
+ }
+): string {
+ const now = new Date().getTime();
+
+ opts = opts || {};
+ opts.maxTime = opts.maxTime || 3;
+ opts.maxRetries = opts.maxRetries || 50;
+ opts.exclude = opts.exclude || exclude;
+ opts.compare = opts.compare || defaultCompare;
+
+ if (typeof opts.currentIterations !== 'number') {
+ opts.currentIterations = 0;
+ }
+
+ if (typeof opts.startTime === 'undefined') {
+ opts.startTime = new Date().getTime();
+ }
+
+ const startTime = opts.startTime;
+
+ // support single exclude argument as string
+ if (typeof opts.exclude === 'string') {
+ opts.exclude = [opts.exclude];
+ }
+
+ if (opts.currentIterations > 0) {
+ // console.log('iterating', currentIterations)
+ }
+
+ // console.log(now - startTime)
+ if (now - startTime >= opts.maxTime) {
+ return errorMessage(
+ now,
+ 'Exceeded maxTime:' + opts.maxTime,
+ // @ts-expect-error: we know that opts.startTime is defined
+ opts
+ );
+ }
+
+ if (opts.currentIterations >= opts.maxRetries) {
+ return errorMessage(
+ now,
+ 'Exceeded maxRetries:' + opts.maxRetries,
+ // @ts-expect-error: we know that opts.startTime is defined
+ opts
+ );
+ }
+
+ // execute the provided method to find a potential satisfied value
+ const result: string = method.apply(this, args);
+
+ // if the result has not been previously found, add it to the found array and return the value as it's unique
+ if (
+ opts.compare(found, result) === -1 &&
+ opts.exclude.indexOf(result) === -1
+ ) {
+ found[result] = result;
+ opts.currentIterations = 0;
+ return result;
+ } else {
+ // console.log('conflict', result);
+ opts.currentIterations++;
+ return exec(method, args, opts);
+ }
+}
diff --git a/src/vendor/user-agent.ts b/src/vendor/user-agent.ts
new file mode 100644
index 00000000..4aef3381
--- /dev/null
+++ b/src/vendor/user-agent.ts
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2012-2014 Jeffrey Mealo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * 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 OR
+ * COPYRIGHT HOLDERS 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.
+ *
+ * ------------------------------------------------------------------------------------------------------------------------
+ *
+ * Based loosely on Luka Pusic's PHP Script: http://360percents.com/posts/php-random-user-agent-generator/
+ *
+ * The license for that script is as follows:
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ *
+ * <[email protected]> wrote this file. As long as you retain this notice you can do whatever you want with this stuff.
+ * If we meet some day, and you think this stuff is worth it, you can buy me a beer in return. Luka Pusic
+ */
+
+import type { Faker } from '..';
+
+export type Arch = 'lin' | 'mac' | 'win';
+
+export function generate(faker: Faker) {
+ function rnd(
+ a?: string[] | number | Record<string, number>,
+ b?: number
+ ): string | number {
+ //calling rnd() with no arguments is identical to rnd(0, 100)
+ a = a || 0;
+ b = b || 100;
+
+ if (typeof b === 'number' && typeof a === 'number') {
+ // 9/2018 - Added faker random to ensure mersenne and seed
+ return faker.datatype.number({ min: a, max: b });
+ }
+
+ if (Array.isArray(a)) {
+ //returns a random element from array (a), even weighting
+ return faker.random.arrayElement(a);
+ }
+
+ if (a && typeof a === 'object') {
+ //returns a random key from the passed object; keys are weighted by the decimal probability in their value
+ return ((obj) => {
+ const rand = (rnd(0, 100) as number) / 100;
+ let min = 0;
+ let max = 0;
+ let return_val: string;
+
+ for (let key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ max = obj[key] + min;
+ return_val = key;
+ if (rand >= min && rand <= max) {
+ break;
+ }
+ min = min + obj[key];
+ }
+ }
+
+ return return_val;
+ })(a);
+ }
+
+ throw new TypeError(
+ 'Invalid arguments passed to rnd. (' + (b ? a + ', ' + b : a) + ')'
+ );
+ }
+
+ function randomLang(): string | number {
+ return rnd([
+ 'AB',
+ 'AF',
+ 'AN',
+ 'AR',
+ 'AS',
+ 'AZ',
+ 'BE',
+ 'BG',
+ 'BN',
+ 'BO',
+ 'BR',
+ 'BS',
+ 'CA',
+ 'CE',
+ 'CO',
+ 'CS',
+ 'CU',
+ 'CY',
+ 'DA',
+ 'DE',
+ 'EL',
+ 'EN',
+ 'EO',
+ 'ES',
+ 'ET',
+ 'EU',
+ 'FA',
+ 'FI',
+ 'FJ',
+ 'FO',
+ 'FR',
+ 'FY',
+ 'GA',
+ 'GD',
+ 'GL',
+ 'GV',
+ 'HE',
+ 'HI',
+ 'HR',
+ 'HT',
+ 'HU',
+ 'HY',
+ 'ID',
+ 'IS',
+ 'IT',
+ 'JA',
+ 'JV',
+ 'KA',
+ 'KG',
+ 'KO',
+ 'KU',
+ 'KW',
+ 'KY',
+ 'LA',
+ 'LB',
+ 'LI',
+ 'LN',
+ 'LT',
+ 'LV',
+ 'MG',
+ 'MK',
+ 'MN',
+ 'MO',
+ 'MS',
+ 'MT',
+ 'MY',
+ 'NB',
+ 'NE',
+ 'NL',
+ 'NN',
+ 'NO',
+ 'OC',
+ 'PL',
+ 'PT',
+ 'RM',
+ 'RO',
+ 'RU',
+ 'SC',
+ 'SE',
+ 'SK',
+ 'SL',
+ 'SO',
+ 'SQ',
+ 'SR',
+ 'SV',
+ 'SW',
+ 'TK',
+ 'TR',
+ 'TY',
+ 'UK',
+ 'UR',
+ 'UZ',
+ 'VI',
+ 'VO',
+ 'YI',
+ 'ZH',
+ ]);
+ }
+
+ function randomBrowserAndOS(): Array<string | number> {
+ const browser = rnd({
+ chrome: 0.45132810566,
+ iexplorer: 0.27477061836,
+ firefox: 0.19384170608,
+ safari: 0.06186781118,
+ opera: 0.01574236955,
+ });
+ const os = {
+ chrome: { win: 0.89, mac: 0.09, lin: 0.02 },
+ firefox: { win: 0.83, mac: 0.16, lin: 0.01 },
+ opera: { win: 0.91, mac: 0.03, lin: 0.06 },
+ safari: { win: 0.04, mac: 0.96 },
+ iexplorer: ['win'],
+ };
+
+ return [browser, rnd(os[browser])];
+ }
+
+ function randomProc(arch: Arch): string | number {
+ const procs = {
+ lin: ['i686', 'x86_64'],
+ mac: { Intel: 0.48, PPC: 0.01, 'U; Intel': 0.48, 'U; PPC': 0.01 },
+ win: ['', 'WOW64', 'Win64; x64'],
+ };
+ return rnd(procs[arch]);
+ }
+
+ function randomRevision(dots: number): string {
+ let return_val = '';
+ //generate a random revision
+ //dots = 2 returns .x.y where x & y are between 0 and 9
+ for (let x = 0; x < dots; x++) {
+ return_val += '.' + rnd(0, 9);
+ }
+ return return_val;
+ }
+
+ const version_string = {
+ net() {
+ return [rnd(1, 4), rnd(0, 9), rnd(10000, 99999), rnd(0, 9)].join('.');
+ },
+ nt() {
+ return rnd(5, 6) + '.' + rnd(0, 3);
+ },
+ ie() {
+ return rnd(7, 11);
+ },
+ trident() {
+ return rnd(3, 7) + '.' + rnd(0, 1);
+ },
+ osx(delim?: string) {
+ return [10, rnd(5, 10), rnd(0, 9)].join(delim || '.');
+ },
+ chrome() {
+ return [rnd(13, 39), 0, rnd(800, 899), 0].join('.');
+ },
+ presto() {
+ return '2.9.' + rnd(160, 190);
+ },
+ presto2() {
+ return rnd(10, 12) + '.00';
+ },
+ safari() {
+ return rnd(531, 538) + '.' + rnd(0, 2) + '.' + rnd(0, 2);
+ },
+ };
+
+ const browser = {
+ firefox(arch: Arch): string {
+ //https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference
+ const firefox_ver = rnd(5, 15) + randomRevision(2),
+ gecko_ver = 'Gecko/20100101 Firefox/' + firefox_ver,
+ proc = randomProc(arch),
+ os_ver =
+ arch === 'win'
+ ? '(Windows NT ' + version_string.nt() + (proc ? '; ' + proc : '')
+ : arch === 'mac'
+ ? '(Macintosh; ' + proc + ' Mac OS X ' + version_string.osx()
+ : '(X11; Linux ' + proc;
+
+ return (
+ 'Mozilla/5.0 ' +
+ os_ver +
+ '; rv:' +
+ firefox_ver.slice(0, -2) +
+ ') ' +
+ gecko_ver
+ );
+ },
+
+ iexplorer(): string {
+ const ver = version_string.ie();
+
+ if (ver >= 11) {
+ //http://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
+ return (
+ 'Mozilla/5.0 (Windows NT 6.' +
+ rnd(1, 3) +
+ '; Trident/7.0; ' +
+ rnd(['Touch; ', '']) +
+ 'rv:11.0) like Gecko'
+ );
+ }
+
+ //http://msdn.microsoft.com/en-us/library/ie/ms537503(v=vs.85).aspx
+ return (
+ 'Mozilla/5.0 (compatible; MSIE ' +
+ ver +
+ '.0; Windows NT ' +
+ version_string.nt() +
+ '; Trident/' +
+ version_string.trident() +
+ (rnd(0, 1) === 1 ? '; .NET CLR ' + version_string.net() : '') +
+ ')'
+ );
+ },
+
+ opera(arch: Arch): string {
+ //http://www.opera.com/docs/history/
+ const presto_ver =
+ ' Presto/' +
+ version_string.presto() +
+ ' Version/' +
+ version_string.presto2() +
+ ')',
+ os_ver =
+ arch === 'win'
+ ? '(Windows NT ' +
+ version_string.nt() +
+ '; U; ' +
+ randomLang() +
+ presto_ver
+ : arch === 'lin'
+ ? '(X11; Linux ' +
+ randomProc(arch) +
+ '; U; ' +
+ randomLang() +
+ presto_ver
+ : '(Macintosh; Intel Mac OS X ' +
+ version_string.osx() +
+ ' U; ' +
+ randomLang() +
+ ' Presto/' +
+ version_string.presto() +
+ ' Version/' +
+ version_string.presto2() +
+ ')';
+
+ return 'Opera/' + rnd(9, 14) + '.' + rnd(0, 99) + ' ' + os_ver;
+ },
+
+ safari(arch: Arch): string {
+ const safari = version_string.safari(),
+ ver = rnd(4, 7) + '.' + rnd(0, 1) + '.' + rnd(0, 10),
+ os_ver =
+ arch === 'mac'
+ ? '(Macintosh; ' +
+ randomProc('mac') +
+ ' Mac OS X ' +
+ version_string.osx('_') +
+ ' rv:' +
+ rnd(2, 6) +
+ '.0; ' +
+ randomLang() +
+ ') '
+ : '(Windows; U; Windows NT ' + version_string.nt() + ')';
+
+ return (
+ 'Mozilla/5.0 ' +
+ os_ver +
+ 'AppleWebKit/' +
+ safari +
+ ' (KHTML, like Gecko) Version/' +
+ ver +
+ ' Safari/' +
+ safari
+ );
+ },
+
+ chrome(arch: Arch): string {
+ const safari = version_string.safari(),
+ os_ver =
+ arch === 'mac'
+ ? '(Macintosh; ' +
+ randomProc('mac') +
+ ' Mac OS X ' +
+ version_string.osx('_') +
+ ') '
+ : arch === 'win'
+ ? '(Windows; U; Windows NT ' + version_string.nt() + ')'
+ : '(X11; Linux ' + randomProc(arch);
+
+ return (
+ 'Mozilla/5.0 ' +
+ os_ver +
+ ' AppleWebKit/' +
+ safari +
+ ' (KHTML, like Gecko) Chrome/' +
+ version_string.chrome() +
+ ' Safari/' +
+ safari
+ );
+ },
+ };
+
+ const random = randomBrowserAndOS();
+ return browser[random[0]](random[1]);
+}