mirror of
https://github.com/pezkuwichain/pezkuwi-telemetry.git
synced 2026-06-12 10:01:18 +00:00
Don't sort the list on every render (#58)
This commit is contained in:
+2
-1
@@ -16,6 +16,7 @@
|
||||
"build:backend": "scripts/build-backend.sh",
|
||||
"check:backend": "tsc -p packages/backend --noEmit",
|
||||
"build:common": "tsc -p packages/common",
|
||||
"check:common": "tsc -p packages/common --noEmit"
|
||||
"check:common": "tsc -p packages/common --noEmit",
|
||||
"test:common": "scripts/test-common.sh"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
"node": ">=9.5"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Tests only available from root wrapper\""
|
||||
"test": "node ./test | tap-spec"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tap-spec": "^5.0.0",
|
||||
"tape": "^4.9.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,3 +112,81 @@ export class NumStats<T extends number> {
|
||||
return this.index < this.history ? this.stack.slice(0, this.index) : this.stack;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an item into a sorted array using binary search.
|
||||
*
|
||||
* @type {T} item type
|
||||
* @param {T} item to be inserted
|
||||
* @param {Array<T>} array to be modified
|
||||
* @param {(a, b) => number} compare function
|
||||
*
|
||||
* @return {number} insertion index
|
||||
*/
|
||||
export function sortedInsert<T>(item: T, into: Array<T>, compare: (a: T, b: T) => number): number {
|
||||
if (into.length === 0) {
|
||||
into.push(item);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
let min = 0;
|
||||
let max = into.length - 1;
|
||||
|
||||
while (min !== max) {
|
||||
const guess = (min + max) / 2 | 0;
|
||||
|
||||
if (compare(item, into[guess]) < 0) {
|
||||
max = Math.max(min, guess - 1);
|
||||
} else {
|
||||
min = Math.min(max, guess + 1);
|
||||
}
|
||||
}
|
||||
|
||||
let insert = compare(item, into[min]) <= 0 ? min : min + 1;
|
||||
|
||||
into.splice(insert, 0, item);
|
||||
|
||||
return insert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an index of an element within a sorted array. This should be substantially
|
||||
* faster than `indexOf` for large arrays.
|
||||
*
|
||||
* @type {T} item type
|
||||
* @param {T} item to find
|
||||
* @param {Array<T>} array to look through
|
||||
* @param {(a, b) => number} compare function
|
||||
*
|
||||
* @return {number} index of the element, `-1` if not found
|
||||
*/
|
||||
export function sortedIndexOf<T>(item:T, within: Array<T>, compare: (a: T, b: T) => number): number {
|
||||
if (within.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let min = 0;
|
||||
let max = within.length - 1;
|
||||
|
||||
while (min !== max) {
|
||||
const guess = (min + max) / 2 | 0;
|
||||
const other = within[guess];
|
||||
|
||||
if (item === other) {
|
||||
return guess;
|
||||
}
|
||||
|
||||
if (compare(item, other) < 0) {
|
||||
max = Math.max(min, guess - 1);
|
||||
} else {
|
||||
min = Math.min(max, guess + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (item === within[min]) {
|
||||
return min;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
const test = require('tape');
|
||||
const common = require('../build/');
|
||||
|
||||
test('sortedInsert', (assert) => {
|
||||
const { sortedInsert } = common;
|
||||
const cmp = (a, b) => a - b;
|
||||
|
||||
let mod = sortedInsert(3, [1,2,4,5], cmp);
|
||||
|
||||
function assertInsert(item, into, equals) {
|
||||
sortedInsert(item, into, cmp);
|
||||
assert.same(into, equals, `Inserts ${item}`);
|
||||
}
|
||||
|
||||
assertInsert(1, [2,3,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,9]);
|
||||
assertInsert(2, [1,3,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,9]);
|
||||
assertInsert(3, [1,2,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,9]);
|
||||
assertInsert(4, [1,2,3,5,6,7,8,9], [1,2,3,4,5,6,7,8,9]);
|
||||
assertInsert(5, [1,2,3,4,6,7,8,9], [1,2,3,4,5,6,7,8,9]);
|
||||
assertInsert(6, [1,2,3,4,5,7,8,9], [1,2,3,4,5,6,7,8,9]);
|
||||
assertInsert(7, [1,2,3,4,5,6,8,9], [1,2,3,4,5,6,7,8,9]);
|
||||
assertInsert(8, [1,2,3,4,5,6,7,9], [1,2,3,4,5,6,7,8,9]);
|
||||
assertInsert(9, [1,2,3,4,5,6,7,8], [1,2,3,4,5,6,7,8,9]);
|
||||
|
||||
assert.end();
|
||||
});
|
||||
|
||||
test('sortedInsert fuzz', (assert) => {
|
||||
const { sortedInsert } = common;
|
||||
const cmp = (a, b) => a - b;
|
||||
const scramble = () => Math.random() - 0.5;
|
||||
const sorted = [1,2,3,4,5,6,7,8,9];
|
||||
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const scrambled = sorted.sort(scramble);
|
||||
const resorted = [];
|
||||
|
||||
for (const item of scrambled) {
|
||||
sortedInsert(item, resorted, cmp);
|
||||
}
|
||||
|
||||
assert.same(resorted, [1,2,3,4,5,6,7,8,9], `resort ${scrambled}`);
|
||||
}
|
||||
|
||||
assert.end();
|
||||
});
|
||||
|
||||
test('sortedInsert indexes', (assert) => {
|
||||
const { sortedInsert } = common;
|
||||
const cmp = (a, b) => a - b;
|
||||
const into = [];
|
||||
|
||||
assert.equals(sortedInsert(5, into, cmp), 0, 'Insert 5');
|
||||
assert.same(into, [5], 'Elements check out');
|
||||
assert.equals(sortedInsert(1, into, cmp), 0, 'Insert 1');
|
||||
assert.same(into, [1,5], 'Elements check out');
|
||||
assert.equals(sortedInsert(9, into, cmp), 2, 'Insert 9');
|
||||
assert.same(into, [1,5,9], 'Elements check out');
|
||||
assert.equals(sortedInsert(3, into, cmp), 1, 'Insert 3');
|
||||
assert.same(into, [1,3,5,9], 'Elements check out');
|
||||
assert.equals(sortedInsert(7, into, cmp), 3, 'Insert 7');
|
||||
assert.same(into, [1,3,5,7,9], 'Elements check out');
|
||||
assert.equals(sortedInsert(4, into, cmp), 2, 'Insert 4');
|
||||
assert.same(into, [1,3,4,5,7,9], 'Elements check out');
|
||||
assert.equals(sortedInsert(6, into, cmp), 4, 'Insert 6');
|
||||
assert.same(into, [1,3,4,5,6,7,9], 'Elements check out');
|
||||
assert.equals(sortedInsert(2, into, cmp), 1, 'Insert 2');
|
||||
assert.same(into, [1,2,3,4,5,6,7,9], 'Elements check out');
|
||||
assert.equals(sortedInsert(8, into, cmp), 7, 'Insert 8');
|
||||
assert.same(into, [1,2,3,4,5,6,7,8,9], 'Elements check out');
|
||||
|
||||
assert.end();
|
||||
});
|
||||
|
||||
test('sortedIndexOf', (assert) => {
|
||||
const { sortedIndexOf } = common;
|
||||
const cmp = (a, b) => a - b;
|
||||
|
||||
assert.equals(sortedIndexOf(1, [1,2,3,4,5,6,7,8,9], cmp), 0, 'Found 1');
|
||||
assert.equals(sortedIndexOf(2, [1,2,3,4,5,6,7,8,9], cmp), 1, 'Found 2');
|
||||
assert.equals(sortedIndexOf(3, [1,2,3,4,5,6,7,8,9], cmp), 2, 'Found 3');
|
||||
assert.equals(sortedIndexOf(4, [1,2,3,4,5,6,7,8,9], cmp), 3, 'Found 4');
|
||||
assert.equals(sortedIndexOf(5, [1,2,3,4,5,6,7,8,9], cmp), 4, 'Found 5');
|
||||
assert.equals(sortedIndexOf(6, [1,2,3,4,5,6,7,8,9], cmp), 5, 'Found 6');
|
||||
assert.equals(sortedIndexOf(7, [1,2,3,4,5,6,7,8,9], cmp), 6, 'Found 7');
|
||||
assert.equals(sortedIndexOf(8, [1,2,3,4,5,6,7,8,9], cmp), 7, 'Found 8');
|
||||
assert.equals(sortedIndexOf(9, [1,2,3,4,5,6,7,8,9], cmp), 8, 'Found 9');
|
||||
|
||||
assert.equals(sortedIndexOf(0, [1,2,3,4,5,6,7,8,9], cmp), -1, 'No 0');
|
||||
assert.equals(sortedIndexOf(10, [1,2,3,4,5,6,7,8,9], cmp), -1, 'No 10');
|
||||
assert.equals(sortedIndexOf(5.5, [1,2,3,4,5,6,7,8,9], cmp), -1, 'No 5.5');
|
||||
|
||||
assert.end();
|
||||
});
|
||||
@@ -3,7 +3,7 @@ import { Types } from '@dotstats/common';
|
||||
import { Chains, Chain, Ago, OfflineIndicator } from './components';
|
||||
import { Connection } from './Connection';
|
||||
import { PersistentObject, PersistentSet } from './persist';
|
||||
import { State } from './state';
|
||||
import { State, compareNodes } from './state';
|
||||
|
||||
import './App.css';
|
||||
|
||||
@@ -36,13 +36,13 @@ export default class App extends React.Component<{}, State> {
|
||||
);
|
||||
|
||||
this.pins = new PersistentSet<Types.NodeName>('pinned_names', (pins) => {
|
||||
const { nodes } = this.state;
|
||||
const { nodes, sortedNodes } = this.state;
|
||||
|
||||
for (const node of nodes.values()) {
|
||||
node.pinned = pins.has(node.nodeDetails[0]);
|
||||
}
|
||||
|
||||
this.setState({ nodes, pins });
|
||||
this.setState({ nodes, pins, sortedNodes: sortedNodes.sort(compareNodes) });
|
||||
});
|
||||
|
||||
this.state = {
|
||||
@@ -54,6 +54,7 @@ export default class App extends React.Component<{}, State> {
|
||||
subscribed: null,
|
||||
chains: new Map(),
|
||||
nodes: new Map(),
|
||||
sortedNodes: [],
|
||||
settings: this.settings.raw(),
|
||||
pins: this.pins.get(),
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { VERSION, timestamp, FeedMessage, Types, Maybe, sleep } from '@dotstats/common';
|
||||
import { State, Update } from './state';
|
||||
import { sortedInsert, sortedIndexOf } from '@dotstats/common';
|
||||
import { State, Update, compareNodes } from './state';
|
||||
import { PersistentSet } from './persist';
|
||||
|
||||
const { Actions } = FeedMessage;
|
||||
@@ -140,9 +141,8 @@ export class Connection {
|
||||
|
||||
private handleMessages = (event: MessageEvent) => {
|
||||
const data = event.data as FeedMessage.Data;
|
||||
const nodes = this.state.nodes;
|
||||
const chains = this.state.chains;
|
||||
const changes = { nodes, chains };
|
||||
const { nodes, chains } = this.state;
|
||||
let { sortedNodes } = this.state;
|
||||
|
||||
messages: for (const message of FeedMessage.deserialize(data)) {
|
||||
switch (message.action) {
|
||||
@@ -176,14 +176,32 @@ export class Connection {
|
||||
const node = { pinned, id, nodeDetails, nodeStats, blockDetails, location };
|
||||
|
||||
nodes.set(id, node);
|
||||
sortedInsert(node, sortedNodes, compareNodes);
|
||||
|
||||
if (nodes.size !== sortedNodes.length) {
|
||||
console.error('Node count in sorted array is wrong!');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.RemovedNode: {
|
||||
nodes.delete(message.payload);
|
||||
const id = message.payload;
|
||||
const node = nodes.get(id);
|
||||
|
||||
break;
|
||||
if (node) {
|
||||
nodes.delete(id);
|
||||
const index = sortedIndexOf(node, sortedNodes, compareNodes);
|
||||
sortedNodes.splice(index, 1);
|
||||
|
||||
if (nodes.size !== sortedNodes.length) {
|
||||
console.error('Node count in sorted array is wrong!');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
continue messages;
|
||||
}
|
||||
|
||||
case Actions.LocatedNode: {
|
||||
@@ -191,7 +209,7 @@ export class Connection {
|
||||
const node = nodes.get(id);
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
continue messages;
|
||||
}
|
||||
|
||||
node.location = [latitude, longitude, city];
|
||||
@@ -204,10 +222,11 @@ export class Connection {
|
||||
const node = nodes.get(id);
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
continue messages;
|
||||
}
|
||||
|
||||
node.blockDetails = blockDetails;
|
||||
sortedNodes = sortedNodes.sort(compareNodes);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -245,6 +264,7 @@ export class Connection {
|
||||
|
||||
if (this.state.subscribed === message.payload) {
|
||||
nodes.clear();
|
||||
sortedNodes = [];
|
||||
|
||||
this.state = this.update({ subscribed: null, nodes, chains });
|
||||
|
||||
@@ -263,6 +283,7 @@ export class Connection {
|
||||
case Actions.UnsubscribedFrom: {
|
||||
if (this.state.subscribed === message.payload) {
|
||||
nodes.clear();
|
||||
sortedNodes = [];
|
||||
this.state = this.update({ subscribed: null, nodes });
|
||||
}
|
||||
|
||||
@@ -281,7 +302,7 @@ export class Connection {
|
||||
}
|
||||
}
|
||||
|
||||
this.state = this.update(changes);
|
||||
this.state = this.update({ nodes, chains, sortedNodes });
|
||||
|
||||
this.autoSubscribe();
|
||||
}
|
||||
|
||||
@@ -8,34 +8,14 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.Chain-tabs {
|
||||
position: absolute;
|
||||
right: 9px;
|
||||
bottom: 0;
|
||||
height: 36px;
|
||||
right: 5px;
|
||||
bottom: 10px;
|
||||
width: 200px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.Chain-tab-unit {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Chain-tab-unit .Icon {
|
||||
margin-right: 1px;
|
||||
font-size: 24px;
|
||||
padding: 6px;
|
||||
background: #ccc;
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Chain-tab-unit-on .Icon {
|
||||
background: #222;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.Chain-content-container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
||||
@@ -43,23 +43,6 @@ export namespace Chain {
|
||||
}
|
||||
}
|
||||
|
||||
function sortNodes(a: AppState.Node, b: AppState.Node): number {
|
||||
if (a.pinned === b.pinned) {
|
||||
if (a.blockDetails[0] === b.blockDetails[0]) {
|
||||
const aPropagation = a.blockDetails[4] == null ? Infinity : a.blockDetails[4] as number;
|
||||
const bPropagation = b.blockDetails[4] == null ? Infinity : b.blockDetails[4] as number;
|
||||
|
||||
// Ascending sort by propagation time
|
||||
return aPropagation - bPropagation;
|
||||
}
|
||||
} else {
|
||||
return Number(b.pinned) - Number(a.pinned);
|
||||
}
|
||||
|
||||
// Descending sort by block number
|
||||
return b.blockDetails[0] - a.blockDetails[0];
|
||||
}
|
||||
|
||||
export class Chain extends React.Component<Chain.Props, Chain.State> {
|
||||
constructor(props: Chain.Props) {
|
||||
super(props);
|
||||
@@ -157,9 +140,7 @@ export class Chain extends React.Component<Chain.Props, Chain.State> {
|
||||
<Node.Row.Header settings={settings} />
|
||||
<tbody>
|
||||
{
|
||||
nodes
|
||||
.sort(sortNodes)
|
||||
.map((node) => <Node.Row key={node.id} node={node} settings={settings} pins={pins} />)
|
||||
nodes.map((node) => <Node.Row key={node.id} node={node} settings={settings} pins={pins} />)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -220,7 +201,7 @@ export class Chain extends React.Component<Chain.Props, Chain.State> {
|
||||
}
|
||||
|
||||
private nodes(): AppState.Node[] {
|
||||
return Array.from(this.props.appState.nodes.values());
|
||||
return this.props.appState.sortedNodes;
|
||||
}
|
||||
|
||||
private pixelPosition(lat: Types.Latitude, lon: Types.Longitude): Node.Location.Position {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
.Chain-Tab {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Chain-Tab .Icon {
|
||||
margin-right: 5px;
|
||||
font-size: 24px;
|
||||
padding: 6px;
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
padding: 10px;
|
||||
border-radius: 40px;
|
||||
transition: background-color 0.15s linear;
|
||||
}
|
||||
|
||||
.Chain-Tab:hover .Icon {
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
.Chain-Tab-on .Icon, .Chain-Tab-on:hover .Icon {
|
||||
background: #d64ca8;
|
||||
color: #fff;
|
||||
}
|
||||
@@ -2,6 +2,8 @@ import * as React from 'react';
|
||||
import { Chain } from './';
|
||||
import { Icon } from '../';
|
||||
|
||||
import './Tab.css';
|
||||
|
||||
export namespace Tab {
|
||||
export interface Props {
|
||||
label: string;
|
||||
@@ -17,7 +19,7 @@ export class Tab extends React.Component<Tab.Props, {}> {
|
||||
public render() {
|
||||
const { label, icon, display, current } = this.props;
|
||||
const highlight = display === current;
|
||||
const className = highlight ? 'Chain-tab-unit-on Chain-tab-unit' : 'Chain-tab-unit';
|
||||
const className = highlight ? 'Chain-Tab-on Chain-Tab' : 'Chain-Tab';
|
||||
|
||||
return (
|
||||
<div className={className} onClick={this.onClick}>
|
||||
|
||||
@@ -35,8 +35,26 @@ export interface State {
|
||||
subscribed: Maybe<Types.ChainLabel>;
|
||||
chains: Map<Types.ChainLabel, Types.NodeCount>;
|
||||
nodes: Map<Types.NodeId, State.Node>;
|
||||
sortedNodes: State.Node[];
|
||||
settings: Readonly<State.Settings>;
|
||||
pins: Readonly<Set<Types.NodeName>>;
|
||||
}
|
||||
|
||||
export type Update = <K extends keyof State>(changes: Pick<State, K> | null) => Readonly<State>;
|
||||
|
||||
export function compareNodes(a: State.Node, b: State.Node): number {
|
||||
if (a.pinned === b.pinned) {
|
||||
if (a.blockDetails[0] === b.blockDetails[0]) {
|
||||
const aPropagation = a.blockDetails[4] == null ? Infinity : a.blockDetails[4] as number;
|
||||
const bPropagation = b.blockDetails[4] == null ? Infinity : b.blockDetails[4] as number;
|
||||
|
||||
// Ascending sort by propagation time
|
||||
return aPropagation - bPropagation;
|
||||
}
|
||||
} else {
|
||||
return +b.pinned - +a.pinned;
|
||||
}
|
||||
|
||||
// Descending sort by block number
|
||||
return b.blockDetails[0] - a.blockDetails[0];
|
||||
}
|
||||
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
tsc -p packages/common && node packages/common/test | tap-spec
|
||||
@@ -1289,6 +1289,10 @@ buffer-indexof@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c"
|
||||
|
||||
buffer-shims@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
|
||||
|
||||
buffer-xor@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
|
||||
@@ -1421,7 +1425,7 @@ center-align@^0.1.1:
|
||||
align-text "^0.1.3"
|
||||
lazy-cache "^1.0.3"
|
||||
|
||||
chalk@1.1.3, chalk@^1.1.3:
|
||||
chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
|
||||
dependencies:
|
||||
@@ -2007,7 +2011,7 @@ decode-uri-component@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
||||
|
||||
deep-equal@^1.0.1:
|
||||
deep-equal@^1.0.1, deep-equal@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
|
||||
|
||||
@@ -2055,7 +2059,7 @@ define-property@^2.0.2:
|
||||
is-descriptor "^1.0.2"
|
||||
isobject "^3.0.1"
|
||||
|
||||
defined@^1.0.0:
|
||||
defined@^1.0.0, defined@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
|
||||
|
||||
@@ -2321,7 +2325,7 @@ error-ex@^1.2.0:
|
||||
dependencies:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
es-abstract@^1.5.1, es-abstract@^1.7.0:
|
||||
es-abstract@^1.5.0, es-abstract@^1.5.1, es-abstract@^1.7.0:
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165"
|
||||
dependencies:
|
||||
@@ -2691,6 +2695,13 @@ fbjs@^0.8.16, fbjs@^0.8.9:
|
||||
setimmediate "^1.0.5"
|
||||
ua-parser-js "^0.7.18"
|
||||
|
||||
figures@^1.4.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
|
||||
dependencies:
|
||||
escape-string-regexp "^1.0.5"
|
||||
object-assign "^4.1.0"
|
||||
|
||||
figures@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
|
||||
@@ -2791,6 +2802,12 @@ follow-redirects@^1.0.0:
|
||||
dependencies:
|
||||
debug "^3.1.0"
|
||||
|
||||
for-each@~0.3.3:
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
|
||||
dependencies:
|
||||
is-callable "^1.1.3"
|
||||
|
||||
for-in@^1.0.1, for-in@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||
@@ -2903,7 +2920,7 @@ fsevents@^1.0.0, fsevents@^1.1.3, fsevents@^1.2.2, fsevents@^1.2.3:
|
||||
nan "^2.9.2"
|
||||
node-pre-gyp "^0.10.0"
|
||||
|
||||
function-bind@^1.1.1:
|
||||
function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
|
||||
@@ -2979,6 +2996,17 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@~7.1.2:
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
global-dirs@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
|
||||
@@ -3132,7 +3160,7 @@ has-values@^1.0.0:
|
||||
is-number "^3.0.0"
|
||||
kind-of "^4.0.0"
|
||||
|
||||
has@^1.0.1:
|
||||
has@^1.0.1, has@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
dependencies:
|
||||
@@ -3549,7 +3577,7 @@ is-extglob@^2.1.0, is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
|
||||
is-finite@^1.0.0:
|
||||
is-finite@^1.0.0, is-finite@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
|
||||
dependencies:
|
||||
@@ -4595,7 +4623,7 @@ minimist@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
|
||||
minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
|
||||
minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
|
||||
@@ -4891,6 +4919,10 @@ object-copy@^0.1.0:
|
||||
define-property "^0.2.5"
|
||||
kind-of "^3.0.3"
|
||||
|
||||
object-inspect@~1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b"
|
||||
|
||||
object-keys@^1.0.8:
|
||||
version "1.0.12"
|
||||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2"
|
||||
@@ -5103,6 +5135,10 @@ parse-json@^2.2.0:
|
||||
dependencies:
|
||||
error-ex "^1.2.0"
|
||||
|
||||
parse-ms@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d"
|
||||
|
||||
parse-passwd@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
|
||||
@@ -5215,6 +5251,10 @@ pkg-dir@^2.0.0:
|
||||
dependencies:
|
||||
find-up "^2.1.0"
|
||||
|
||||
plur@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/plur/-/plur-1.0.0.tgz#db85c6814f5e5e5a3b49efc28d604fec62975156"
|
||||
|
||||
pn@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
|
||||
@@ -5553,10 +5593,22 @@ pretty-format@^22.4.0, pretty-format@^22.4.3:
|
||||
ansi-regex "^3.0.0"
|
||||
ansi-styles "^3.2.0"
|
||||
|
||||
pretty-ms@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "http://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz#4257c256df3fb0b451d6affaab021884126981dc"
|
||||
dependencies:
|
||||
is-finite "^1.0.1"
|
||||
parse-ms "^1.0.0"
|
||||
plur "^1.0.0"
|
||||
|
||||
private@^0.1.6, private@^0.1.8:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
|
||||
|
||||
process-nextick-args@~1.0.6:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
|
||||
@@ -5724,6 +5776,10 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
re-emitter@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/re-emitter/-/re-emitter-1.1.3.tgz#fa9e319ffdeeeb35b27296ef0f3d374dac2f52a7"
|
||||
|
||||
react-dev-utils@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-5.0.1.tgz#1f396e161fe44b595db1b186a40067289bf06613"
|
||||
@@ -5889,6 +5945,18 @@ readable-stream@1.0:
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
readable-stream@2.2.9:
|
||||
version "2.2.9"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8"
|
||||
dependencies:
|
||||
buffer-shims "~1.0.0"
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.1"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~1.0.6"
|
||||
string_decoder "~1.0.0"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readdirp@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
|
||||
@@ -6123,6 +6191,12 @@ resolve@^1.1.7, resolve@^1.3.2:
|
||||
dependencies:
|
||||
path-parse "^1.0.5"
|
||||
|
||||
resolve@~1.7.1:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3"
|
||||
dependencies:
|
||||
path-parse "^1.0.5"
|
||||
|
||||
restore-cursor@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
|
||||
@@ -6130,6 +6204,12 @@ restore-cursor@^2.0.0:
|
||||
onetime "^2.0.0"
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
resumer@~0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759"
|
||||
dependencies:
|
||||
through "~2.3.4"
|
||||
|
||||
ret@~0.1.10:
|
||||
version "0.1.15"
|
||||
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
||||
@@ -6527,6 +6607,12 @@ split-string@^3.0.1, split-string@^3.0.2:
|
||||
dependencies:
|
||||
extend-shallow "^3.0.0"
|
||||
|
||||
split@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npmjs.org/split/-/split-1.0.0.tgz#c4395ce683abcd254bc28fe1dabb6e5c27dcffae"
|
||||
dependencies:
|
||||
through "2"
|
||||
|
||||
sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
@@ -6636,6 +6722,14 @@ string-width@^1.0.1, string-width@^1.0.2:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
string.prototype.trim@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea"
|
||||
dependencies:
|
||||
define-properties "^1.1.2"
|
||||
es-abstract "^1.5.0"
|
||||
function-bind "^1.0.2"
|
||||
|
||||
string_decoder@^1.0.0, string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
||||
@@ -6646,6 +6740,12 @@ string_decoder@~0.10.x:
|
||||
version "0.10.31"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
||||
|
||||
string_decoder@~1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
strip-ansi@3.0.1, strip-ansi@^3.0.0, strip-ansi@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
||||
@@ -6763,10 +6863,50 @@ symbol-tree@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
|
||||
|
||||
tap-out@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tap-out/-/tap-out-2.1.0.tgz#c093079a915036de8b835bfa3297f14458b15358"
|
||||
dependencies:
|
||||
re-emitter "1.1.3"
|
||||
readable-stream "2.2.9"
|
||||
split "1.0.0"
|
||||
trim "0.0.1"
|
||||
|
||||
tap-spec@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tap-spec/-/tap-spec-5.0.0.tgz#7329e4e66e8aa68da2a164215abbb903a7c5d352"
|
||||
dependencies:
|
||||
chalk "^1.0.0"
|
||||
duplexer "^0.1.1"
|
||||
figures "^1.4.0"
|
||||
lodash "^4.17.10"
|
||||
pretty-ms "^2.1.0"
|
||||
repeat-string "^1.5.2"
|
||||
tap-out "^2.1.0"
|
||||
through2 "^2.0.0"
|
||||
|
||||
tapable@^0.2.7:
|
||||
version "0.2.8"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
|
||||
|
||||
tape@^4.9.1:
|
||||
version "4.9.1"
|
||||
resolved "https://registry.yarnpkg.com/tape/-/tape-4.9.1.tgz#1173d7337e040c76fbf42ec86fcabedc9b3805c9"
|
||||
dependencies:
|
||||
deep-equal "~1.0.1"
|
||||
defined "~1.0.0"
|
||||
for-each "~0.3.3"
|
||||
function-bind "~1.1.1"
|
||||
glob "~7.1.2"
|
||||
has "~1.0.3"
|
||||
inherits "~2.0.3"
|
||||
minimist "~1.2.0"
|
||||
object-inspect "~1.6.0"
|
||||
resolve "~1.7.1"
|
||||
resumer "~0.0.0"
|
||||
string.prototype.trim "~1.1.2"
|
||||
through "~2.3.8"
|
||||
|
||||
tar@^4:
|
||||
version "4.4.4"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd"
|
||||
@@ -6810,7 +6950,7 @@ through2@^2.0.0:
|
||||
readable-stream "^2.1.5"
|
||||
xtend "~4.0.1"
|
||||
|
||||
through@^2.3.6:
|
||||
through@2, through@^2.3.6, through@~2.3.4, through@~2.3.8:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
|
||||
@@ -6903,6 +7043,10 @@ trim-right@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
|
||||
|
||||
trim@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd"
|
||||
|
||||
ts-jest@22.0.1:
|
||||
version "22.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-22.0.1.tgz#48942936a466c2e76e259b02e2f1356f1839afc3"
|
||||
|
||||
Reference in New Issue
Block a user