uuid 1.4.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.yml +5 -0
- package/README.md +11 -12
- package/benchmark/package.json +9 -0
- package/{test/compare_v1.js → misc/compare.js} +1 -2
- package/misc/perf.js +102 -0
- package/package.json +42 -11
- package/rng-browser.js +31 -0
- package/rng.js +4 -0
- package/test/mocha.opts +1 -0
- package/test/test.js +68 -191
- package/uuid.js +142 -204
- package/test/test.html +0 -17
package/.travis.yml
ADDED
package/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
# node-uuid
|
|
1
|
+
# uuid [](http://travis-ci.org/defunctzombie/node-uuid) #
|
|
2
|
+
|
|
3
|
+
[](https://ci.testling.com/defunctzombie/node-uuid)
|
|
2
4
|
|
|
3
5
|
Simple, fast generation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDS.
|
|
4
6
|
|
|
@@ -7,7 +9,7 @@ Features:
|
|
|
7
9
|
* Generate RFC4122 version 1 or version 4 UUIDs
|
|
8
10
|
* Runs in node.js and all browsers.
|
|
9
11
|
* Cryptographically strong random # generation on supporting platforms
|
|
10
|
-
*
|
|
12
|
+
* 1185 bytes minified and gzip'ed (Want something smaller? Check this [crazy shit](https://gist.github.com/982883) out! )
|
|
11
13
|
* [Annotated source code](http://broofa.github.com/node-uuid/docs/uuid.html)
|
|
12
14
|
|
|
13
15
|
## Getting Started
|
|
@@ -21,16 +23,12 @@ Install it in your browser:
|
|
|
21
23
|
Or in node.js:
|
|
22
24
|
|
|
23
25
|
```
|
|
24
|
-
npm install
|
|
26
|
+
npm install uuid
|
|
25
27
|
```
|
|
26
28
|
|
|
27
29
|
```javascript
|
|
28
|
-
var uuid = require('
|
|
29
|
-
```
|
|
30
|
+
var uuid = require('uuid');
|
|
30
31
|
|
|
31
|
-
Then create some ids ...
|
|
32
|
-
|
|
33
|
-
```javascript
|
|
34
32
|
// Generate a v1 (time-based) id
|
|
35
33
|
uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'
|
|
36
34
|
|
|
@@ -138,7 +136,7 @@ var string = uuid.unparse(bytes); // -> '797ff043-11eb-11e1-80d6-510998755d10'
|
|
|
138
136
|
|
|
139
137
|
(Browsers only) Set `uuid` property back to it's previous value.
|
|
140
138
|
|
|
141
|
-
Returns the
|
|
139
|
+
Returns the uuid object.
|
|
142
140
|
|
|
143
141
|
Example:
|
|
144
142
|
|
|
@@ -179,11 +177,12 @@ open test/test.html
|
|
|
179
177
|
Requires node.js
|
|
180
178
|
|
|
181
179
|
```
|
|
182
|
-
|
|
183
|
-
|
|
180
|
+
cd benchmark/
|
|
181
|
+
npm install
|
|
182
|
+
node benchmark.js
|
|
184
183
|
```
|
|
185
184
|
|
|
186
|
-
For a more complete discussion of
|
|
185
|
+
For a more complete discussion of uuid performance, please see the `benchmark/README.md` file, and the [benchmark wiki](https://github.com/broofa/uuid/wiki/Benchmark)
|
|
187
186
|
|
|
188
187
|
For browser performance [checkout the JSPerf tests](http://jsperf.com/node-uuid-performance).
|
|
189
188
|
|
package/misc/perf.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
var assert = require('assert');
|
|
2
|
+
|
|
3
|
+
var uuid = require('../');
|
|
4
|
+
|
|
5
|
+
var log = console.log;
|
|
6
|
+
|
|
7
|
+
var generators = {
|
|
8
|
+
v1: uuid.v1,
|
|
9
|
+
v4: uuid.v4
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
var UUID_FORMAT = {
|
|
13
|
+
v1: /[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i,
|
|
14
|
+
v4: /[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
var N = 1e4;
|
|
18
|
+
|
|
19
|
+
// Get %'age an actual value differs from the ideal value
|
|
20
|
+
function divergence(actual, ideal) {
|
|
21
|
+
return Math.round(100*100*(actual - ideal)/ideal)/100;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function rate(msg, t) {
|
|
25
|
+
log(msg + ': ' + (N / (Date.now() - t) * 1e3 | 0) + ' uuids\/second');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
for (var version in generators) {
|
|
29
|
+
var counts = {}, max = 0;
|
|
30
|
+
var generator = generators[version];
|
|
31
|
+
var format = UUID_FORMAT[version];
|
|
32
|
+
|
|
33
|
+
log('\nSanity check ' + N + ' ' + version + ' uuids');
|
|
34
|
+
for (var i = 0, ok = 0; i < N; i++) {
|
|
35
|
+
id = generator();
|
|
36
|
+
if (!format.test(id)) {
|
|
37
|
+
throw Error(id + ' is not a valid UUID string');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (id != uuid.unparse(uuid.parse(id))) {
|
|
41
|
+
assert(fail, id + ' is not a valid id');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Count digits for our randomness check
|
|
45
|
+
if (version == 'v4') {
|
|
46
|
+
var digits = id.replace(/-/g, '').split('');
|
|
47
|
+
for (var j = digits.length-1; j >= 0; j--) {
|
|
48
|
+
var c = digits[j];
|
|
49
|
+
max = Math.max(max, counts[c] = (counts[c] || 0) + 1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Check randomness for v4 UUIDs
|
|
55
|
+
if (version == 'v4') {
|
|
56
|
+
// Limit that we get worried about randomness. (Purely empirical choice, this!)
|
|
57
|
+
var limit = 2*100*Math.sqrt(1/N);
|
|
58
|
+
|
|
59
|
+
log('\nChecking v4 randomness. Distribution of Hex Digits (% deviation from ideal)');
|
|
60
|
+
|
|
61
|
+
for (var i = 0; i < 16; i++) {
|
|
62
|
+
var c = i.toString(16);
|
|
63
|
+
var bar = '', n = counts[c], p = Math.round(n/max*100|0);
|
|
64
|
+
|
|
65
|
+
// 1-3,5-8, and D-F: 1:16 odds over 30 digits
|
|
66
|
+
var ideal = N*30/16;
|
|
67
|
+
if (i == 4) {
|
|
68
|
+
// 4: 1:1 odds on 1 digit, plus 1:16 odds on 30 digits
|
|
69
|
+
ideal = N*(1 + 30/16);
|
|
70
|
+
} else if (i >= 8 && i <= 11) {
|
|
71
|
+
// 8-B: 1:4 odds on 1 digit, plus 1:16 odds on 30 digits
|
|
72
|
+
ideal = N*(1/4 + 30/16);
|
|
73
|
+
} else {
|
|
74
|
+
// Otherwise: 1:16 odds on 30 digits
|
|
75
|
+
ideal = N*30/16;
|
|
76
|
+
}
|
|
77
|
+
var d = divergence(n, ideal);
|
|
78
|
+
|
|
79
|
+
// Draw bar using UTF squares (just for grins)
|
|
80
|
+
var s = n/max*50 | 0;
|
|
81
|
+
while (s--) bar += '=';
|
|
82
|
+
|
|
83
|
+
assert(Math.abs(d) < limit, c + ' |' + bar + '| ' + counts[c] + ' (' + d + '% < ' + limit + '%)');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Perf tests
|
|
89
|
+
for (var version in generators) {
|
|
90
|
+
log('\nPerformance testing ' + version + ' UUIDs');
|
|
91
|
+
var generator = generators[version];
|
|
92
|
+
var buf = new uuid.BufferClass(16);
|
|
93
|
+
|
|
94
|
+
for (var i = 0, t = Date.now(); i < N; i++) generator();
|
|
95
|
+
rate('uuid.' + version + '()', t);
|
|
96
|
+
|
|
97
|
+
for (var i = 0, t = Date.now(); i < N; i++) generator('binary');
|
|
98
|
+
rate('uuid.' + version + '(\'binary\')', t);
|
|
99
|
+
|
|
100
|
+
for (var i = 0, t = Date.now(); i < N; i++) generator('binary', buf);
|
|
101
|
+
rate('uuid.' + version + '(\'binary\', buffer)', t);
|
|
102
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,45 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name"
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"keywords"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
"name": "uuid",
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "Rigorous implementation of RFC4122 (v1 and v4) UUIDs.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"uuid",
|
|
7
|
+
"guid",
|
|
8
|
+
"rfc4122"
|
|
9
9
|
],
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
"author": "Robert Kieffer <robert@broofa.com>",
|
|
11
|
+
"contributors": [
|
|
12
|
+
{
|
|
13
|
+
"name": "Christoph Tavan <dev@tavan.de>",
|
|
14
|
+
"github": "https://github.com/ctavan"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "Vincent Voyer <vincent@zeroload.net>",
|
|
18
|
+
"github": "https://github.com/vvo"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"main": "./uuid.js",
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"mocha": "1.8.0"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "mocha test/test.js"
|
|
27
|
+
},
|
|
28
|
+
"browser": {
|
|
29
|
+
"./rng.js": "./rng-browser.js"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/shtylman/node-uuid.git"
|
|
34
|
+
},
|
|
35
|
+
"testling": {
|
|
36
|
+
"browsers": [
|
|
37
|
+
"ie6..latest",
|
|
38
|
+
"firefox/3.6..latest",
|
|
39
|
+
"chrome/22..latest",
|
|
40
|
+
"safari/5.1..latest"
|
|
41
|
+
],
|
|
42
|
+
"harness": "mocha-tdd",
|
|
43
|
+
"files": "test/*.js"
|
|
44
|
+
}
|
|
14
45
|
}
|
package/rng-browser.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
var rng;
|
|
3
|
+
|
|
4
|
+
if (global.crypto && crypto.getRandomValues) {
|
|
5
|
+
// WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
|
|
6
|
+
// Moderately fast, high quality
|
|
7
|
+
var _rnds8 = new Uint8Array(16);
|
|
8
|
+
rng = function whatwgRNG() {
|
|
9
|
+
crypto.getRandomValues(_rnds8);
|
|
10
|
+
return _rnds8;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!rng) {
|
|
15
|
+
// Math.random()-based (RNG)
|
|
16
|
+
//
|
|
17
|
+
// If all else fails, use Math.random(). It's fast, but is of unspecified
|
|
18
|
+
// quality.
|
|
19
|
+
var _rnds = new Array(16);
|
|
20
|
+
rng = function() {
|
|
21
|
+
for (var i = 0, r; i < 16; i++) {
|
|
22
|
+
if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
|
|
23
|
+
_rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return _rnds;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = rng;
|
|
31
|
+
|
package/rng.js
ADDED
package/test/mocha.opts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--ui qunit
|
package/test/test.js
CHANGED
|
@@ -1,54 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
// node.js
|
|
3
|
-
uuid = require('../uuid');
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
// x-platform log/assert shims
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
function _log(msg, type) {
|
|
11
|
-
type = type || 'log';
|
|
12
|
-
|
|
13
|
-
if (typeof(document) != 'undefined') {
|
|
14
|
-
document.write('<div class="' + type + '">' + msg.replace(/\n/g, '<br />') + '</div>');
|
|
15
|
-
}
|
|
16
|
-
if (typeof(console) != 'undefined') {
|
|
17
|
-
var color = {
|
|
18
|
-
log: '\033[39m',
|
|
19
|
-
warn: '\033[33m',
|
|
20
|
-
error: '\033[31m'
|
|
21
|
-
};
|
|
22
|
-
console[type](color[type] + msg + color.log);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function log(msg) {_log(msg, 'log');}
|
|
27
|
-
function warn(msg) {_log(msg, 'warn');}
|
|
28
|
-
function error(msg) {_log(msg, 'error');}
|
|
29
|
-
|
|
30
|
-
function assert(res, msg) {
|
|
31
|
-
if (!res) {
|
|
32
|
-
error('FAIL: ' + msg);
|
|
33
|
-
} else {
|
|
34
|
-
log('Pass: ' + msg);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
1
|
+
var assert = require('assert');
|
|
37
2
|
|
|
38
|
-
|
|
39
|
-
// Unit tests
|
|
40
|
-
//
|
|
3
|
+
var uuid = require('../');
|
|
41
4
|
|
|
42
5
|
// Verify ordering of v1 ids created with explicit times
|
|
43
6
|
var TIME = 1321644961388; // 2011-11-18 11:36:01.388-08:00
|
|
44
7
|
|
|
45
8
|
function compare(name, ids) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
9
|
+
test(name, function() {
|
|
10
|
+
// avoid .map for older browsers
|
|
11
|
+
for (var i=0 ; i<ids.length ; ++i) {
|
|
12
|
+
ids[i] = ids[i].split('-').reverse().join('-');
|
|
13
|
+
}
|
|
14
|
+
ids = ids.sort();
|
|
15
|
+
var sorted = ([].concat(ids)).sort();
|
|
50
16
|
|
|
51
|
-
|
|
17
|
+
assert(sorted.toString() == ids.toString(), name + ' have expected order');
|
|
18
|
+
});
|
|
52
19
|
}
|
|
53
20
|
|
|
54
21
|
// Verify ordering of v1 ids created using default behavior
|
|
@@ -69,160 +36,70 @@ compare('uuids with time option', [
|
|
|
69
36
|
uuid.v1({msecs: TIME + 28*24*3600*1000})
|
|
70
37
|
]);
|
|
71
38
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// Verify throw if too many ids created
|
|
78
|
-
var thrown = false;
|
|
79
|
-
try {
|
|
80
|
-
uuid.v1({msecs: TIME, nsecs: 10000});
|
|
81
|
-
} catch (e) {
|
|
82
|
-
thrown = true;
|
|
83
|
-
}
|
|
84
|
-
assert(thrown, 'Exception thrown when > 10K ids created in 1 ms');
|
|
85
|
-
|
|
86
|
-
// Verify clock regression bumps clockseq
|
|
87
|
-
var uidt = uuid.v1({msecs: TIME});
|
|
88
|
-
var uidtb = uuid.v1({msecs: TIME - 1});
|
|
89
|
-
assert(
|
|
90
|
-
parseInt(uidtb.split('-')[3], 16) - parseInt(uidt.split('-')[3], 16) === 1,
|
|
91
|
-
'Clock regression by msec increments the clockseq'
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
// Verify clock regression bumps clockseq
|
|
95
|
-
var uidtn = uuid.v1({msecs: TIME, nsecs: 10});
|
|
96
|
-
var uidtnb = uuid.v1({msecs: TIME, nsecs: 9});
|
|
97
|
-
assert(
|
|
98
|
-
parseInt(uidtnb.split('-')[3], 16) - parseInt(uidtn.split('-')[3], 16) === 1,
|
|
99
|
-
'Clock regression by nsec increments the clockseq'
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
// Verify explicit options produce expected id
|
|
103
|
-
var id = uuid.v1({
|
|
104
|
-
msecs: 1321651533573,
|
|
105
|
-
nsecs: 5432,
|
|
106
|
-
clockseq: 0x385c,
|
|
107
|
-
node: [ 0x61, 0xcd, 0x3c, 0xbb, 0x32, 0x10 ]
|
|
39
|
+
test('msec', function() {
|
|
40
|
+
assert(
|
|
41
|
+
uuid.v1({msecs: TIME}) != uuid.v1({msecs: TIME}),
|
|
42
|
+
'IDs created at same msec are different'
|
|
43
|
+
);
|
|
108
44
|
});
|
|
109
|
-
assert(id == 'd9428888-122b-11e1-b85c-61cd3cbb3210', 'Explicit options produce expected id');
|
|
110
|
-
|
|
111
|
-
// Verify adjacent ids across a msec boundary are 1 time unit apart
|
|
112
|
-
var u0 = uuid.v1({msecs: TIME, nsecs: 9999});
|
|
113
|
-
var u1 = uuid.v1({msecs: TIME + 1, nsecs: 0});
|
|
114
|
-
|
|
115
|
-
var before = u0.split('-')[0], after = u1.split('-')[0];
|
|
116
|
-
var dt = parseInt(after, 16) - parseInt(before, 16);
|
|
117
|
-
assert(dt === 1, 'Ids spanning 1ms boundary are 100ns apart');
|
|
118
|
-
|
|
119
|
-
//
|
|
120
|
-
// Test parse/unparse
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
id = '00112233445566778899aabbccddeeff';
|
|
124
|
-
assert(uuid.unparse(uuid.parse(id.substr(0,10))) ==
|
|
125
|
-
'00112233-4400-0000-0000-000000000000', 'Short parse');
|
|
126
|
-
assert(uuid.unparse(uuid.parse('(this is the uuid -> ' + id + id)) ==
|
|
127
|
-
'00112233-4455-6677-8899-aabbccddeeff', 'Dirty parse');
|
|
128
|
-
|
|
129
|
-
//
|
|
130
|
-
// Perf tests
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
var generators = {
|
|
134
|
-
v1: uuid.v1,
|
|
135
|
-
v4: uuid.v4
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
var UUID_FORMAT = {
|
|
139
|
-
v1: /[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i,
|
|
140
|
-
v4: /[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i
|
|
141
|
-
};
|
|
142
45
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function rate(msg, t) {
|
|
151
|
-
log(msg + ': ' + (N / (Date.now() - t) * 1e3 | 0) + ' uuids\/second');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
for (var version in generators) {
|
|
155
|
-
var counts = {}, max = 0;
|
|
156
|
-
var generator = generators[version];
|
|
157
|
-
var format = UUID_FORMAT[version];
|
|
158
|
-
|
|
159
|
-
log('\nSanity check ' + N + ' ' + version + ' uuids');
|
|
160
|
-
for (var i = 0, ok = 0; i < N; i++) {
|
|
161
|
-
id = generator();
|
|
162
|
-
if (!format.test(id)) {
|
|
163
|
-
throw Error(id + ' is not a valid UUID string');
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (id != uuid.unparse(uuid.parse(id))) {
|
|
167
|
-
assert(fail, id + ' is not a valid id');
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Count digits for our randomness check
|
|
171
|
-
if (version == 'v4') {
|
|
172
|
-
var digits = id.replace(/-/g, '').split('');
|
|
173
|
-
for (var j = digits.length-1; j >= 0; j--) {
|
|
174
|
-
var c = digits[j];
|
|
175
|
-
max = Math.max(max, counts[c] = (counts[c] || 0) + 1);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
46
|
+
test('exception thrown when > 10k ids created in 1ms', function() {
|
|
47
|
+
// Verify throw if too many ids created
|
|
48
|
+
var thrown = false;
|
|
49
|
+
try {
|
|
50
|
+
uuid.v1({msecs: TIME, nsecs: 10000});
|
|
51
|
+
} catch (e) {
|
|
52
|
+
thrown = true;
|
|
178
53
|
}
|
|
54
|
+
assert(thrown, 'Exception thrown when > 10K ids created in 1 ms');
|
|
55
|
+
});
|
|
179
56
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
var bar = '', n = counts[c], p = Math.round(n/max*100|0);
|
|
190
|
-
|
|
191
|
-
// 1-3,5-8, and D-F: 1:16 odds over 30 digits
|
|
192
|
-
var ideal = N*30/16;
|
|
193
|
-
if (i == 4) {
|
|
194
|
-
// 4: 1:1 odds on 1 digit, plus 1:16 odds on 30 digits
|
|
195
|
-
ideal = N*(1 + 30/16);
|
|
196
|
-
} else if (i >= 8 && i <= 11) {
|
|
197
|
-
// 8-B: 1:4 odds on 1 digit, plus 1:16 odds on 30 digits
|
|
198
|
-
ideal = N*(1/4 + 30/16);
|
|
199
|
-
} else {
|
|
200
|
-
// Otherwise: 1:16 odds on 30 digits
|
|
201
|
-
ideal = N*30/16;
|
|
202
|
-
}
|
|
203
|
-
var d = divergence(n, ideal);
|
|
57
|
+
test('clock regression by msec', function() {
|
|
58
|
+
// Verify clock regression bumps clockseq
|
|
59
|
+
var uidt = uuid.v1({msecs: TIME});
|
|
60
|
+
var uidtb = uuid.v1({msecs: TIME - 1});
|
|
61
|
+
assert(
|
|
62
|
+
parseInt(uidtb.split('-')[3], 16) - parseInt(uidt.split('-')[3], 16) === 1,
|
|
63
|
+
'Clock regression by msec increments the clockseq'
|
|
64
|
+
);
|
|
65
|
+
});
|
|
204
66
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
67
|
+
test('clock regression by nsec', function() {
|
|
68
|
+
// Verify clock regression bumps clockseq
|
|
69
|
+
var uidtn = uuid.v1({msecs: TIME, nsecs: 10});
|
|
70
|
+
var uidtnb = uuid.v1({msecs: TIME, nsecs: 9});
|
|
71
|
+
assert(
|
|
72
|
+
parseInt(uidtnb.split('-')[3], 16) - parseInt(uidtn.split('-')[3], 16) === 1,
|
|
73
|
+
'Clock regression by nsec increments the clockseq'
|
|
74
|
+
);
|
|
75
|
+
});
|
|
208
76
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
77
|
+
test('explicit options product expected id', function() {
|
|
78
|
+
// Verify explicit options produce expected id
|
|
79
|
+
var id = uuid.v1({
|
|
80
|
+
msecs: 1321651533573,
|
|
81
|
+
nsecs: 5432,
|
|
82
|
+
clockseq: 0x385c,
|
|
83
|
+
node: [ 0x61, 0xcd, 0x3c, 0xbb, 0x32, 0x10 ]
|
|
84
|
+
});
|
|
85
|
+
assert(id == 'd9428888-122b-11e1-b85c-61cd3cbb3210', 'Explicit options produce expected id');
|
|
86
|
+
});
|
|
213
87
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
var
|
|
218
|
-
var buf = new uuid.BufferClass(16);
|
|
88
|
+
test('ids spanning 1ms boundary are 100ns apart', function() {
|
|
89
|
+
// Verify adjacent ids across a msec boundary are 1 time unit apart
|
|
90
|
+
var u0 = uuid.v1({msecs: TIME, nsecs: 9999});
|
|
91
|
+
var u1 = uuid.v1({msecs: TIME + 1, nsecs: 0});
|
|
219
92
|
|
|
220
|
-
|
|
221
|
-
|
|
93
|
+
var before = u0.split('-')[0], after = u1.split('-')[0];
|
|
94
|
+
var dt = parseInt(after, 16) - parseInt(before, 16);
|
|
95
|
+
assert(dt === 1, 'Ids spanning 1ms boundary are 100ns apart');
|
|
96
|
+
});
|
|
222
97
|
|
|
223
|
-
|
|
224
|
-
|
|
98
|
+
test('parse/unparse', function() {
|
|
99
|
+
var id = '00112233445566778899aabbccddeeff';
|
|
100
|
+
assert(uuid.unparse(uuid.parse(id.substr(0,10))) ==
|
|
101
|
+
'00112233-4400-0000-0000-000000000000', 'Short parse');
|
|
102
|
+
assert(uuid.unparse(uuid.parse('(this is the uuid -> ' + id + id)) ==
|
|
103
|
+
'00112233-4455-6677-8899-aabbccddeeff', 'Dirty parse');
|
|
104
|
+
});
|
|
225
105
|
|
|
226
|
-
for (var i = 0, t = Date.now(); i < N; i++) generator('binary', buf);
|
|
227
|
-
rate('uuid.' + version + '(\'binary\', buffer)', t);
|
|
228
|
-
}
|
package/uuid.js
CHANGED
|
@@ -3,243 +3,181 @@
|
|
|
3
3
|
// Copyright (c) 2010-2012 Robert Kieffer
|
|
4
4
|
// MIT License - http://opensource.org/licenses/mit-license.php
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
_rng = function whatwgRNG() {
|
|
30
|
-
crypto.getRandomValues(_rnds8);
|
|
31
|
-
return _rnds8;
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!_rng) {
|
|
36
|
-
// Math.random()-based (RNG)
|
|
37
|
-
//
|
|
38
|
-
// If all else fails, use Math.random(). It's fast, but is of unspecified
|
|
39
|
-
// quality.
|
|
40
|
-
var _rnds = new Array(16);
|
|
41
|
-
_rng = function() {
|
|
42
|
-
for (var i = 0, r; i < 16; i++) {
|
|
43
|
-
if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
|
|
44
|
-
_rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return _rnds;
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Buffer class to use
|
|
52
|
-
var BufferClass = typeof(Buffer) == 'function' ? Buffer : Array;
|
|
6
|
+
// Unique ID creation requires a high quality random # generator. We feature
|
|
7
|
+
// detect to determine the best RNG source, normalizing to a function that
|
|
8
|
+
// returns 128-bits of randomness, since that's what's usually required
|
|
9
|
+
var _rng = require('./rng');
|
|
10
|
+
|
|
11
|
+
// Maps for number <-> hex string conversion
|
|
12
|
+
var _byteToHex = [];
|
|
13
|
+
var _hexToByte = {};
|
|
14
|
+
for (var i = 0; i < 256; i++) {
|
|
15
|
+
_byteToHex[i] = (i + 0x100).toString(16).substr(1);
|
|
16
|
+
_hexToByte[_byteToHex[i]] = i;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// **`parse()` - Parse a UUID into it's component bytes**
|
|
20
|
+
function parse(s, buf, offset) {
|
|
21
|
+
var i = (buf && offset) || 0, ii = 0;
|
|
22
|
+
|
|
23
|
+
buf = buf || [];
|
|
24
|
+
s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
|
|
25
|
+
if (ii < 16) { // Don't overflow!
|
|
26
|
+
buf[i + ii++] = _hexToByte[oct];
|
|
27
|
+
}
|
|
28
|
+
});
|
|
53
29
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
for (var i = 0; i < 256; i++) {
|
|
58
|
-
_byteToHex[i] = (i + 0x100).toString(16).substr(1);
|
|
59
|
-
_hexToByte[_byteToHex[i]] = i;
|
|
30
|
+
// Zero out remaining bytes if string was short
|
|
31
|
+
while (ii < 16) {
|
|
32
|
+
buf[i + ii++] = 0;
|
|
60
33
|
}
|
|
61
34
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
35
|
+
return buf;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// **`unparse()` - Convert UUID byte array (ala parse()) into a string**
|
|
39
|
+
function unparse(buf, offset) {
|
|
40
|
+
var i = offset || 0, bth = _byteToHex;
|
|
41
|
+
return bth[buf[i++]] + bth[buf[i++]] +
|
|
42
|
+
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
43
|
+
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
44
|
+
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
45
|
+
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
46
|
+
bth[buf[i++]] + bth[buf[i++]] +
|
|
47
|
+
bth[buf[i++]] + bth[buf[i++]] +
|
|
48
|
+
bth[buf[i++]] + bth[buf[i++]];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// **`v1()` - Generate time-based UUID**
|
|
52
|
+
//
|
|
53
|
+
// Inspired by https://github.com/LiosK/UUID.js
|
|
54
|
+
// and http://docs.python.org/library/uuid.html
|
|
65
55
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (ii < 16) { // Don't overflow!
|
|
69
|
-
buf[i + ii++] = _hexToByte[oct];
|
|
70
|
-
}
|
|
71
|
-
});
|
|
56
|
+
// random #'s we need to init node and clockseq
|
|
57
|
+
var _seedBytes = _rng();
|
|
72
58
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
59
|
+
// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
|
|
60
|
+
var _nodeId = [
|
|
61
|
+
_seedBytes[0] | 0x01,
|
|
62
|
+
_seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
|
|
63
|
+
];
|
|
77
64
|
|
|
78
|
-
|
|
79
|
-
|
|
65
|
+
// Per 4.2.2, randomize (14 bit) clockseq
|
|
66
|
+
var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
|
|
80
67
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
var i = offset || 0, bth = _byteToHex;
|
|
84
|
-
return bth[buf[i++]] + bth[buf[i++]] +
|
|
85
|
-
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
86
|
-
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
87
|
-
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
88
|
-
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
89
|
-
bth[buf[i++]] + bth[buf[i++]] +
|
|
90
|
-
bth[buf[i++]] + bth[buf[i++]] +
|
|
91
|
-
bth[buf[i++]] + bth[buf[i++]];
|
|
92
|
-
}
|
|
68
|
+
// Previous uuid creation time
|
|
69
|
+
var _lastMSecs = 0, _lastNSecs = 0;
|
|
93
70
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
71
|
+
// See https://github.com/broofa/node-uuid for API details
|
|
72
|
+
function v1(options, buf, offset) {
|
|
73
|
+
var i = buf && offset || 0;
|
|
74
|
+
var b = buf || [];
|
|
98
75
|
|
|
99
|
-
|
|
100
|
-
var _seedBytes = _rng();
|
|
76
|
+
options = options || {};
|
|
101
77
|
|
|
102
|
-
|
|
103
|
-
var _nodeId = [
|
|
104
|
-
_seedBytes[0] | 0x01,
|
|
105
|
-
_seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
|
|
106
|
-
];
|
|
78
|
+
var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;
|
|
107
79
|
|
|
108
|
-
//
|
|
109
|
-
|
|
80
|
+
// UUID timestamps are 100 nano-second units since the Gregorian epoch,
|
|
81
|
+
// (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
|
|
82
|
+
// time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
|
|
83
|
+
// (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
|
|
84
|
+
var msecs = options.msecs !== undefined ? options.msecs : new Date().getTime();
|
|
110
85
|
|
|
111
|
-
//
|
|
112
|
-
|
|
86
|
+
// Per 4.2.1.2, use count of uuid's generated during the current clock
|
|
87
|
+
// cycle to simulate higher resolution clock
|
|
88
|
+
var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1;
|
|
113
89
|
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
var i = buf && offset || 0;
|
|
117
|
-
var b = buf || [];
|
|
90
|
+
// Time since last uuid creation (in msecs)
|
|
91
|
+
var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
|
|
118
92
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// UUID timestamps are 100 nano-second units since the Gregorian epoch,
|
|
124
|
-
// (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
|
|
125
|
-
// time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
|
|
126
|
-
// (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
|
|
127
|
-
var msecs = options.msecs != null ? options.msecs : new Date().getTime();
|
|
93
|
+
// Per 4.2.1.2, Bump clockseq on clock regression
|
|
94
|
+
if (dt < 0 && options.clockseq === undefined) {
|
|
95
|
+
clockseq = clockseq + 1 & 0x3fff;
|
|
96
|
+
}
|
|
128
97
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
98
|
+
// Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
|
|
99
|
+
// time interval
|
|
100
|
+
if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
|
|
101
|
+
nsecs = 0;
|
|
102
|
+
}
|
|
132
103
|
|
|
133
|
-
|
|
134
|
-
|
|
104
|
+
// Per 4.2.1.2 Throw error if too many uuids are requested
|
|
105
|
+
if (nsecs >= 10000) {
|
|
106
|
+
throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
|
|
107
|
+
}
|
|
135
108
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
109
|
+
_lastMSecs = msecs;
|
|
110
|
+
_lastNSecs = nsecs;
|
|
111
|
+
_clockseq = clockseq;
|
|
140
112
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
|
|
144
|
-
nsecs = 0;
|
|
145
|
-
}
|
|
113
|
+
// Per 4.1.4 - Convert from unix epoch to Gregorian epoch
|
|
114
|
+
msecs += 12219292800000;
|
|
146
115
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
116
|
+
// `time_low`
|
|
117
|
+
var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
|
|
118
|
+
b[i++] = tl >>> 24 & 0xff;
|
|
119
|
+
b[i++] = tl >>> 16 & 0xff;
|
|
120
|
+
b[i++] = tl >>> 8 & 0xff;
|
|
121
|
+
b[i++] = tl & 0xff;
|
|
151
122
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
123
|
+
// `time_mid`
|
|
124
|
+
var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
|
|
125
|
+
b[i++] = tmh >>> 8 & 0xff;
|
|
126
|
+
b[i++] = tmh & 0xff;
|
|
155
127
|
|
|
156
|
-
|
|
157
|
-
|
|
128
|
+
// `time_high_and_version`
|
|
129
|
+
b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
|
|
130
|
+
b[i++] = tmh >>> 16 & 0xff;
|
|
158
131
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
b[i++] = tl >>> 24 & 0xff;
|
|
162
|
-
b[i++] = tl >>> 16 & 0xff;
|
|
163
|
-
b[i++] = tl >>> 8 & 0xff;
|
|
164
|
-
b[i++] = tl & 0xff;
|
|
132
|
+
// `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
|
|
133
|
+
b[i++] = clockseq >>> 8 | 0x80;
|
|
165
134
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
b[i++] = tmh >>> 8 & 0xff;
|
|
169
|
-
b[i++] = tmh & 0xff;
|
|
135
|
+
// `clock_seq_low`
|
|
136
|
+
b[i++] = clockseq & 0xff;
|
|
170
137
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
138
|
+
// `node`
|
|
139
|
+
var node = options.node || _nodeId;
|
|
140
|
+
for (var n = 0; n < 6; n++) {
|
|
141
|
+
b[i + n] = node[n];
|
|
142
|
+
}
|
|
174
143
|
|
|
175
|
-
|
|
176
|
-
|
|
144
|
+
return buf ? buf : unparse(b);
|
|
145
|
+
}
|
|
177
146
|
|
|
178
|
-
|
|
179
|
-
b[i++] = clockseq & 0xff;
|
|
147
|
+
// **`v4()` - Generate random UUID**
|
|
180
148
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
149
|
+
// See https://github.com/broofa/node-uuid for API details
|
|
150
|
+
function v4(options, buf, offset) {
|
|
151
|
+
// Deprecated - 'format' argument, as supported in v1.2
|
|
152
|
+
var i = buf && offset || 0;
|
|
186
153
|
|
|
187
|
-
|
|
154
|
+
if (typeof(options) == 'string') {
|
|
155
|
+
buf = options == 'binary' ? new Array(16) : null;
|
|
156
|
+
options = null;
|
|
188
157
|
}
|
|
158
|
+
options = options || {};
|
|
189
159
|
|
|
190
|
-
|
|
160
|
+
var rnds = options.random || (options.rng || _rng)();
|
|
191
161
|
|
|
192
|
-
//
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
var i = buf && offset || 0;
|
|
162
|
+
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
|
163
|
+
rnds[6] = (rnds[6] & 0x0f) | 0x40;
|
|
164
|
+
rnds[8] = (rnds[8] & 0x3f) | 0x80;
|
|
196
165
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
166
|
+
// Copy bytes to buffer, if provided
|
|
167
|
+
if (buf) {
|
|
168
|
+
for (var ii = 0; ii < 16; ii++) {
|
|
169
|
+
buf[i + ii] = rnds[ii];
|
|
200
170
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
var rnds = options.random || (options.rng || _rng)();
|
|
204
|
-
|
|
205
|
-
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
|
206
|
-
rnds[6] = (rnds[6] & 0x0f) | 0x40;
|
|
207
|
-
rnds[8] = (rnds[8] & 0x3f) | 0x80;
|
|
171
|
+
}
|
|
208
172
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
for (var ii = 0; ii < 16; ii++) {
|
|
212
|
-
buf[i + ii] = rnds[ii];
|
|
213
|
-
}
|
|
214
|
-
}
|
|
173
|
+
return buf || unparse(rnds);
|
|
174
|
+
}
|
|
215
175
|
|
|
216
|
-
|
|
217
|
-
|
|
176
|
+
// Export public API
|
|
177
|
+
var uuid = v4;
|
|
178
|
+
uuid.v1 = v1;
|
|
179
|
+
uuid.v4 = v4;
|
|
180
|
+
uuid.parse = parse;
|
|
181
|
+
uuid.unparse = unparse;
|
|
218
182
|
|
|
219
|
-
|
|
220
|
-
var uuid = v4;
|
|
221
|
-
uuid.v1 = v1;
|
|
222
|
-
uuid.v4 = v4;
|
|
223
|
-
uuid.parse = parse;
|
|
224
|
-
uuid.unparse = unparse;
|
|
225
|
-
uuid.BufferClass = BufferClass;
|
|
226
|
-
|
|
227
|
-
if (_global.define && define.amd) {
|
|
228
|
-
// Publish as AMD module
|
|
229
|
-
define(function() {return uuid;});
|
|
230
|
-
} else if (typeof(module) != 'undefined' && module.exports) {
|
|
231
|
-
// Publish as node.js module
|
|
232
|
-
module.exports = uuid;
|
|
233
|
-
} else {
|
|
234
|
-
// Publish as global (in browsers)
|
|
235
|
-
var _previousRoot = _global.uuid;
|
|
236
|
-
|
|
237
|
-
// **`noConflict()` - (browser only) to reset global 'uuid' var**
|
|
238
|
-
uuid.noConflict = function() {
|
|
239
|
-
_global.uuid = _previousRoot;
|
|
240
|
-
return uuid;
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
_global.uuid = uuid;
|
|
244
|
-
}
|
|
245
|
-
}).call(this);
|
|
183
|
+
module.exports = uuid;
|
package/test/test.html
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
<html>
|
|
2
|
-
<head>
|
|
3
|
-
<style>
|
|
4
|
-
div {
|
|
5
|
-
font-family: monospace;
|
|
6
|
-
font-size: 8pt;
|
|
7
|
-
}
|
|
8
|
-
div.log {color: #444;}
|
|
9
|
-
div.warn {color: #550;}
|
|
10
|
-
div.error {color: #800; font-weight: bold;}
|
|
11
|
-
</style>
|
|
12
|
-
<script src="../uuid.js"></script>
|
|
13
|
-
</head>
|
|
14
|
-
<body>
|
|
15
|
-
<script src="./test.js"></script>
|
|
16
|
-
</body>
|
|
17
|
-
</html>
|