Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
317 changes: 244 additions & 73 deletions lib/json0.js
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ var isArray = function(obj) {
* @returns {boolean}
*/
var isObject = function(obj) {
return (!!obj) && (obj.constructor === Object);
return !!obj && obj.constructor === Object;
};

/**
@@ -66,7 +66,7 @@ json.create = function(data) {
};

json.invertComponent = function(c) {
var c_ = {p: c.p};
var c_ = { p: c.p };

// handle subtype ops
if (c.t && subtypes[c.t]) {
@@ -83,8 +83,8 @@ json.invertComponent = function(c) {
if (c.na !== void 0) c_.na = -c.na;

if (c.lm !== void 0) {
c_.lm = c.p[c.p.length-1];
c_.p = c.p.slice(0,c.p.length-1).concat([c.lm]);
c_.lm = c.p[c.p.length - 1];
c_.p = c.p.slice(0, c.p.length - 1).concat([c.lm]);
}

return c_;
@@ -106,20 +106,21 @@ json.checkValidOp = function(op) {
};

json.checkList = function(elem) {
if (!isArray(elem))
throw new Error('Referenced element not a list');
if (!isArray(elem)) throw new Error('Referenced element not a list');
};

json.checkObj = function(elem) {
if (!isObject(elem)) {
throw new Error("Referenced element not an object (it was " + JSON.stringify(elem) + ")");
throw new Error(
'Referenced element not an object (it was ' + JSON.stringify(elem) + ')'
);
}
};

// helper functions to convert old string ops to and from subtype ops
function convertFromText(c) {
c.t = 'text0';
var o = {p: c.p.pop()};
var o = { p: c.p.pop() };
if (c.si != null) o.i = c.si;
if (c.sd != null) o.d = c.sd;
c.o = [o];
@@ -133,6 +134,160 @@ function convertToText(c) {
delete c.o;
}

// not checking anything here, we should probably check that u: exists
// (only thing we care about at json0 top level), and then delegate
// to any subtypes if there is already subtype presence data
json.createPresence = function(presence) {
return presence;
};

// this needs more thinking/testing, looking a bit more carefully at
// how this is implemented in ot-rich-text, etc.
json.comparePresence = function(pres1, pres2) {
if (!pres1 || !pres2) {
return false;
}
if (!pres1.p || !pres2.p) {
return false;
}
if (pres1.t !== pres2.t) {
return false;
}
if (pres1.t && subtypes[pres1.t]) {
if (pres1.p[0] === pres2.p[0]) {
return subtypes[pres1.t].comparePresence(pres1, pres2);
}
} else return pres1 === pres2;
};

var transformPosition = function(cursor, op, isOwnOp) {
var cursor = clone(cursor);

var opIsAncestor = cursor.length >= op.p.length; // true also if op is self
var opIsSibling = cursor.length === op.p.length; // true also if op is self
var opIsAncestorSibling = cursor.length >= op.p.length; // true also if op is self or sibling of self
var equalUpTo = -1;
for (var i = 0; i < op.p.length; i++) {
if (op.p[i] !== cursor[i]) {
opIsAncestor = false;
if (i < op.p.length - 1) {
opIsSibling = false;
opIsAncestorSibling = false;
}
}
if (equalUpTo === i - 1 && op.p[i] === cursor[i]) {
equalUpTo += 1;
}
}

if (opIsSibling) {
if (op.sd) {
cursor[cursor.length - 1] = text.transformCursor(
cursor[cursor.length - 1],
[{ p: op.p[op.p.length - 1], d: op.sd }],
isOwnOp ? 'right' : 'left'
);
}
if (op.si) {
cursor[cursor.length - 1] = text.transformCursor(
cursor[cursor.length - 1],
[{ p: op.p[op.p.length - 1], i: op.si }],
isOwnOp ? 'right' : 'left'
);
}
}

if (opIsAncestor) {
if (op.lm !== undefined) {
cursor[equalUpTo] = op.lm;
}
if (op.od && op.oi) {
cursor = op.p.slice(0, op.p.length);
} else if (op.od) {
cursor = op.p.slice(0, op.p.length - 1);
} else if (op.ld && op.li) {
cursor = op.p.slice(0, op.p.length);
} else if (op.ld) {
cursor = op.p.slice(0, op.p.length - 1);
}
}

if (opIsAncestorSibling) {
var lastPathIdx = op.p.length - 1;
if (
!opIsAncestor &&
op.ld &&
!op.li &&
op.p[lastPathIdx] < cursor[lastPathIdx]
) {
cursor[lastPathIdx] -= 1;
} else if (!op.ld && op.li && op.p[lastPathIdx] <= cursor[lastPathIdx]) {
cursor[lastPathIdx] += 1;
}

// if move item in list from after to before
if (
!opIsAncestor &&
op.lm !== undefined &&
op.p[lastPathIdx] > cursor[lastPathIdx] &&
op.lm <= cursor[lastPathIdx]
) {
cursor[lastPathIdx] += 1;
// if move item in list from before to after
} else if (
!opIsAncestor &&
op.lm !== undefined &&
op.p[lastPathIdx] < cursor[lastPathIdx] &&
op.lm >= cursor[lastPathIdx]
) {
cursor[lastPathIdx] -= 1;
}
}

return cursor;
};

json.transformCursor = function(cursor, op, isOwnOp) {
for (var i = 0; i < op.length; i++) {
cursor = transformPosition(cursor, op[i], isOwnOp);
}
return cursor;
};

// this is the key function, always run client-side, both on
// the client that creates a text-change, and on the clients
// that receive text-changes (ops). if there are no ops, just
// return presence, if there are ops, delegate to the subtype
// responsible for those ops (currently only ot-rich-text).
// I am making assumptions many places that all ops will be
// of the same subtype, not sure if this is a given.
// We're only concerned about the first level of object/array,
// not sure if the spec allows nesting of subtypes.
json.transformPresence = function(presence, ops, isOwn) {
if (op.length < 1) {
return presence;
}
ops.forEach(op => {
const opType = op.t;
const path = op.p && op.p[0];
if (opType && subtypes[opType] && path) {
// No path given, or path does not match path in presence --
// no need to transform path since no conflict
if (!presence.p || !presence.p[0] || presence.p[0] !== path) {
return presence;
}
// return result of running the subtype's transformPresence,
// but add path and type, which the subtype will not include
presence.cursor = subtypes[opType].transformCursor(
presence,
op,
isOwn
).cursor;
}
});
return presence;
};

json.apply = function(snapshot, op) {
json.checkValidOp(op);

@@ -146,8 +301,7 @@ json.apply = function(snapshot, op) {
var c = op[i];

// convert old string ops to use subtype for backwards compatibility
if (c.si != null || c.sd != null)
convertFromText(c);
if (c.si != null || c.sd != null) convertFromText(c);

var parent = null;
var parentKey = null;
@@ -162,15 +316,14 @@ json.apply = function(snapshot, op) {
elem = elem[key];
key = p;

if (parent == null)
throw new Error('Path invalid');
if (parent == null) throw new Error('Path invalid');
}

// handle subtype ops
if (c.t && c.o !== void 0 && subtypes[c.t]) {
elem[key] = subtypes[c.t].apply(elem[key], c.o);

// Number add
// Number add
} else if (c.na !== void 0) {
if (typeof elem[key] != 'number')
throw new Error('Referenced element not a number');
@@ -188,14 +341,14 @@ json.apply = function(snapshot, op) {
// List insert
else if (c.li !== void 0) {
json.checkList(elem);
elem.splice(key,0, c.li);
elem.splice(key, 0, c.li);
}

// List delete
else if (c.ld !== void 0) {
json.checkList(elem);
// Should check the list element matches c.ld here too.
elem.splice(key,1);
elem.splice(key, 1);
}

// List move
@@ -204,9 +357,9 @@ json.apply = function(snapshot, op) {
if (c.lm != key) {
var e = elem[key];
// Remove it...
elem.splice(key,1);
elem.splice(key, 1);
// And insert it back.
elem.splice(c.lm,0,e);
elem.splice(c.lm, 0, e);
}
}

@@ -224,9 +377,7 @@ json.apply = function(snapshot, op) {

// Should check that elem[key] == c.od
delete elem[key];
}

else {
} else {
throw new Error('invalid / missing instruction in op');
}
}
@@ -257,19 +408,17 @@ json.incrementalApply = function(snapshot, op, _yield) {
};

// Checks if two paths, p1 and p2 match.
var pathMatches = json.pathMatches = function(p1, p2, ignoreLast) {
if (p1.length != p2.length)
return false;
var pathMatches = (json.pathMatches = function(p1, p2, ignoreLast) {
if (p1.length != p2.length) return false;

for (var i = 0; i < p1.length; i++) {
if (p1[i] !== p2[i] && (!ignoreLast || i !== p1.length - 1))
return false;
if (p1[i] !== p2[i] && (!ignoreLast || i !== p1.length - 1)) return false;
}

return true;
};
});

json.append = function(dest,c) {
json.append = function(dest, c) {
c = clone(c);

if (dest.length === 0) {
@@ -288,7 +437,10 @@ json.append = function(dest,c) {
if (pathMatches(c.p, last.p)) {
// handle subtype ops
if (c.t && last.t && c.t === last.t && subtypes[c.t]) {
last.o = subtypes[c.t].compose(last.o, c.o);
last.o = subtypes[c.t].compose(
last.o,
c.o
);

// convert back to old string ops
if (c.si != null || c.sd != null) {
@@ -303,16 +455,25 @@ json.append = function(dest,c) {
convertToText(last);
}
} else if (last.na != null && c.na != null) {
dest[dest.length - 1] = {p: last.p, na: last.na + c.na};
} else if (last.li !== undefined && c.li === undefined && c.ld === last.li) {
dest[dest.length - 1] = { p: last.p, na: last.na + c.na };
} else if (
last.li !== undefined &&
c.li === undefined &&
c.ld === last.li
) {
// insert immediately followed by delete becomes a noop.
if (last.ld !== undefined) {
// leave the delete part of the replace
delete last.li;
} else {
dest.pop();
}
} else if (last.od !== undefined && last.oi === undefined && c.oi !== undefined && c.od === undefined) {
} else if (
last.od !== undefined &&
last.oi === undefined &&
c.oi !== undefined &&
c.od === undefined
) {
last.oi = c.oi;
} else if (last.oi !== undefined && c.od !== undefined) {
// The last path component inserted something that the new component deletes (or replaces).
@@ -332,7 +493,10 @@ json.append = function(dest,c) {
}
} else {
// convert string ops back
if ((c.si != null || c.sd != null) && (last.si != null || last.sd != null)) {
if (
(c.si != null || c.sd != null) &&
(last.si != null || last.sd != null)
) {
convertToText(c);
convertToText(last);
}
@@ -341,14 +505,14 @@ json.append = function(dest,c) {
}
};

json.compose = function(op1,op2) {
json.compose = function(op1, op2) {
json.checkValidOp(op1);
json.checkValidOp(op2);

var newOp = clone(op1);

for (var i = 0; i < op2.length; i++) {
json.append(newOp,op2[i]);
json.append(newOp, op2[i]);
}

return newOp;
@@ -363,7 +527,7 @@ json.normalize = function(op) {
var c = op[i];
if (c.p == null) c.p = [];

json.append(newOp,c);
json.append(newOp, c);
}

return newOp;
@@ -373,11 +537,9 @@ json.normalize = function(op) {
json.commonLengthForOps = function(a, b) {
var alen = a.p.length;
var blen = b.p.length;
if (a.na != null || a.t)
alen++;
if (a.na != null || a.t) alen++;

if (b.na != null || b.t)
blen++;
if (b.na != null || b.t) blen++;

if (alen === 0) return -1;
if (blen === 0) return null;
@@ -387,16 +549,15 @@ json.commonLengthForOps = function(a, b) {

for (var i = 0; i < alen; i++) {
var p = a.p[i];
if (i >= blen || p !== b.p[i])
return null;
if (i >= blen || p !== b.p[i]) return null;
}

return alen;
};

// Returns true if an op can affect the given path
json.canOpAffectPath = function(op, path) {
return json.commonLengthForOps({p:path}, op) != null;
return json.commonLengthForOps({ p: path }, op) != null;
};

// transform c so it applies to a document with otherC applied.
@@ -408,23 +569,25 @@ json.transformComponent = function(dest, c, otherC, type) {
var cplength = c.p.length;
var otherCplength = otherC.p.length;

if (c.na != null || c.t)
cplength++;
if (c.na != null || c.t) cplength++;

if (otherC.na != null || otherC.t)
otherCplength++;
if (otherC.na != null || otherC.t) otherCplength++;

// if c is deleting something, and that thing is changed by otherC, we need to
// update c to reflect that change for invertibility.
if (common2 != null && otherCplength > cplength && c.p[common2] == otherC.p[common2]) {
if (
common2 != null &&
otherCplength > cplength &&
c.p[common2] == otherC.p[common2]
) {
if (c.ld !== void 0) {
var oc = clone(otherC);
oc.p = oc.p.slice(cplength);
c.ld = json.apply(clone(c.ld),[oc]);
c.ld = json.apply(clone(c.ld), [oc]);
} else if (c.od !== void 0) {
var oc = clone(otherC);
oc.p = oc.p.slice(cplength);
c.od = json.apply(clone(c.od),[oc]);
c.od = json.apply(clone(c.od), [oc]);
}
}

@@ -433,7 +596,10 @@ json.transformComponent = function(dest, c, otherC, type) {

// backward compatibility for old string ops
var oc = otherC;
if ((c.si != null || c.sd != null) && (otherC.si != null || otherC.sd != null)) {
if (
(c.si != null || c.sd != null) &&
(otherC.si != null || otherC.sd != null)
) {
convertFromText(c);
oc = clone(otherC);
convertFromText(oc);
@@ -482,19 +648,22 @@ json.transformComponent = function(dest, c, otherC, type) {
}
}
} else if (otherC.li !== void 0) {
if (c.li !== void 0 && c.ld === undefined && commonOperand && c.p[common] === otherC.p[common]) {
if (
c.li !== void 0 &&
c.ld === undefined &&
commonOperand &&
c.p[common] === otherC.p[common]
) {
// in li vs. li, left wins.
if (type === 'right')
c.p[common]++;
if (type === 'right') c.p[common]++;
} else if (otherC.p[common] <= c.p[common]) {
c.p[common]++;
}

if (c.lm !== void 0) {
if (commonOperand) {
// otherC edits the same list we edit
if (otherC.p[common] <= c.lm)
c.lm++;
if (otherC.p[common] <= c.lm) c.lm++;
// changing c.from is handled above.
}
}
@@ -509,9 +678,7 @@ json.transformComponent = function(dest, c, otherC, type) {
var p = otherC.p[common];
var from = c.p[common];
var to = c.lm;
if (p < to || (p === to && from < to))
c.lm--;

if (p < to || (p === to && from < to)) c.lm--;
}
}

@@ -531,7 +698,6 @@ json.transformComponent = function(dest, c, otherC, type) {
}
}
}

} else if (otherC.lm !== void 0) {
if (c.lm !== void 0 && cplength === otherCplength) {
// lm vs lm, here we go!
@@ -547,7 +713,8 @@ json.transformComponent = function(dest, c, otherC, type) {
// they moved it! tie break.
if (type === 'left') {
c.p[common] = otherTo;
if (from === to) // ugh
if (from === to)
// ugh
c.lm = otherTo;
} else {
return dest;
@@ -559,7 +726,8 @@ json.transformComponent = function(dest, c, otherC, type) {
else if (from === otherTo) {
if (otherFrom > otherTo) {
c.p[common]++;
if (from === to) // ugh, again
if (from === to)
// ugh, again
c.lm++;
}
}
@@ -568,15 +736,16 @@ json.transformComponent = function(dest, c, otherC, type) {
if (to > otherFrom) {
c.lm--;
} else if (to === otherFrom) {
if (to > from)
c.lm--;
if (to > from) c.lm--;
}
if (to > otherTo) {
c.lm++;
} else if (to === otherTo) {
// if we're both moving in the same direction, tie break
if ((otherTo > otherFrom && to > from) ||
(otherTo < otherFrom && to < from)) {
if (
(otherTo > otherFrom && to > from) ||
(otherTo < otherFrom && to < from)
) {
if (type === 'right') c.lm++;
} else {
if (to > from) c.lm++;
@@ -608,8 +777,7 @@ json.transformComponent = function(dest, c, otherC, type) {
else if (p === to && from > to) c.p[common]++;
}
}
}
else if (otherC.oi !== void 0 && otherC.od !== void 0) {
} else if (otherC.oi !== void 0 && otherC.od !== void 0) {
if (c.p[common] === otherC.p[common]) {
if (c.oi !== void 0 && commonOperand) {
// we inserted where someone else replaced
@@ -629,15 +797,14 @@ json.transformComponent = function(dest, c, otherC, type) {
if (c.oi !== void 0 && c.p[common] === otherC.p[common]) {
// left wins if we try to insert at the same place
if (type === 'left') {
json.append(dest,{p: c.p, od:otherC.oi});
json.append(dest, { p: c.p, od: otherC.oi });
} else {
return dest;
}
}
} else if (otherC.od !== void 0) {
if (c.p[common] == otherC.p[common]) {
if (!commonOperand)
return dest;
if (!commonOperand) return dest;
if (c.oi !== void 0) {
delete c.od;
} else {
@@ -647,11 +814,16 @@ json.transformComponent = function(dest, c, otherC, type) {
}
}

json.append(dest,c);
json.append(dest, c);
return dest;
};

require('./bootstrapTransform')(json, json.transformComponent, json.checkValidOp, json.append);
require('./bootstrapTransform')(
json,
json.transformComponent,
json.checkValidOp,
json.append
);

/**
* Register a subtype for string operations, using the text0 type.
@@ -660,4 +832,3 @@ var text = require('./text0');

json.registerSubtype(text);
module.exports = json;

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ot-json0",
"version": "1.1.0",
"description": "JSON OT type",
"name": "@minervaproject/ot-json0",
"version": "1.3.0",
"description": "JSON OT type, fork of sharedb/ot-json0@1.2.0",
"main": "lib/index.js",
"directories": {
"test": "test"
@@ -17,7 +17,7 @@
},
"repository": {
"type": "git",
"url": "git://github.com/ottypes/json0"
"url": "git://github.com/houshuang/json0"
},
"keywords": [
"ot",
172 changes: 172 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


ansi-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=

cli-progress@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-2.1.1.tgz#45ee1b143487c19043a3262131ccb4676f87f032"
integrity sha512-TSJw3LY9ZRSis7yYzQ7flIdtQMbacd9oYoiFphJhI4SzgmqF0zErO+uNv0lbUjk1L4AGfHQJ4OVYYzW+JV66KA==
dependencies:
colors "^1.1.2"
string-width "^2.1.1"

coffee-script@^1.7.1:
version "1.12.7"
resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53"
integrity sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==

colors@^1.1.2:
version "1.3.3"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d"
integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==

commander@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06"
integrity sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=

commander@2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873"
integrity sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=

debug@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.0.0.tgz#89bd9df6732b51256bc6705342bba02ed12131ef"
integrity sha1-ib2d9nMrUSVrxnBTQrugLtEhMe8=
dependencies:
ms "0.6.2"

diff@1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/diff/-/diff-1.0.8.tgz#343276308ec991b7bc82267ed55bc1411f971666"
integrity sha1-NDJ2MI7Jkbe8giZ+1VvBQR+XFmY=

escape-string-regexp@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1"
integrity sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=

glob@3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467"
integrity sha1-4xPusknHr/qlxHUoaw4RW1mDlGc=
dependencies:
graceful-fs "~2.0.0"
inherits "2"
minimatch "~0.2.11"

graceful-fs@~2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0"
integrity sha1-fNLNsiiko/Nule+mzBQt59GhNtA=

growl@1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428"
integrity sha1-Sy3sjZB+k9szZiTc7AGDUC+MlCg=

inherits@2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=

is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=

jade@0.26.3:
version "0.26.3"
resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c"
integrity sha1-jxDXl32NefL2/4YqgbBRPMslaGw=
dependencies:
commander "0.6.1"
mkdirp "0.3.0"

lru-cache@2:
version "2.7.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=

minimatch@~0.2.11:
version "0.2.14"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a"
integrity sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=
dependencies:
lru-cache "2"
sigmund "~1.0.0"

minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=

mkdirp@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e"
integrity sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=

mkdirp@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12"
integrity sha1-HXMHam35hs2TROFecfzAWkyavxI=
dependencies:
minimist "0.0.8"

mocha@^1.20.1:
version "1.21.5"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-1.21.5.tgz#7c58b09174df976e434a23b1e8d639873fc529e9"
integrity sha1-fFiwkXTfl25DSiOx6NY5hz/FKek=
dependencies:
commander "2.3.0"
debug "2.0.0"
diff "1.0.8"
escape-string-regexp "1.0.2"
glob "3.2.3"
growl "1.8.1"
jade "0.26.3"
mkdirp "0.5.0"

ms@0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.6.2.tgz#d89c2124c6fdc1353d65a8b77bf1aac4b193708c"
integrity sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw=

ot-fuzzer@^1.0.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ot-fuzzer/-/ot-fuzzer-1.2.1.tgz#41f70305fdd1d55268f6cc169c14c0eb9e5fb31c"
integrity sha512-dOm+Wb1Mqrw8ql5ksiZFf3Bdsruj5r4mHaa3COqtbg0ClkGjxZXwMGgMLjWslq/b0maeiw5yvYwIdH6As4svHg==
dependencies:
cli-progress "^2.1.1"
seedrandom "^2.4.4"

seedrandom@^2.4.4:
version "2.4.4"
resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-2.4.4.tgz#b25ea98632c73e45f58b77cfaa931678df01f9ba"
integrity sha512-9A+PDmgm+2du77B5i0Ip2cxOqqHjgNxnBgglxLcX78A2D6c2rTo61z4jnVABpF4cKeDMDG+cmXXvdnqse2VqMA==

sigmund@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=

string-width@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
dependencies:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"

strip-ansi@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
dependencies:
ansi-regex "^3.0.0"