From 3c595c1e45e736ab2863f2b8e16a78778660dea5 Mon Sep 17 00:00:00 2001 From: maguihai Date: Thu, 11 Jun 2020 21:53:56 +0800 Subject: [PATCH 01/19] Site updated: 2020-06-11 21:53:55 --- about/index.html | 4 +- archives/2019/10/index.html | 6 +- archives/2019/11/index.html | 6 +- archives/2019/12/index.html | 6 +- archives/2019/index.html | 6 +- archives/2019/page/2/index.html | 6 +- archives/2020/01/index.html | 6 +- archives/2020/02/index.html | 6 +- archives/2020/03/index.html | 6 +- archives/2020/04/index.html | 6 +- archives/2020/05/index.html | 6 +- archives/2020/06/index.html | 1269 ++++++++++++ archives/2020/index.html | 76 +- archives/2020/page/2/index.html | 41 +- archives/index.html | 76 +- archives/page/2/index.html | 76 +- archives/page/3/index.html | 41 +- atom.xml | 62 +- baidusitemap.xml | 3 + categories/JDK/Java/index.html | 4 +- .../index.html" | 4 +- categories/JDK/index.html | 4 +- categories/Java/Bloom-filter/index.html | 4 +- categories/Java/GC/index.html | 4 +- categories/Java/Guava/String/index.html | 4 +- categories/Java/Guava/index.html | 4 +- categories/Java/IDEA/index.html | 4 +- .../IDEA/\345\267\245\345\205\267/index.html" | 4 +- .../IO\346\250\241\345\236\213/index.html" | 4 +- categories/Java/JVM/index.html | 4 +- categories/Java/index.html | 56 +- categories/Java/page/2/index.html | 56 +- categories/Java/page/3/index.html | 30 +- categories/Java/unit-test/index.html | 4 +- categories/Java/unit-test/mockito/index.html | 4 +- .../Java/\345\216\237\347\220\206/index.html" | 4 +- .../Java/\345\217\215\345\260\204/index.html" | 4 +- .../index.html" | 4 +- .../Java/\345\271\266\345\217\221/index.html" | 30 +- .../\350\277\233\351\230\266/index.html" | 1250 ++++++++++++ .../Java/\345\274\202\346\255\245/index.html" | 4 +- .../Eureka/index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../Java/\351\207\215\346\236\204/index.html" | 4 +- .../Linux\347\254\224\350\256\260/index.html" | 4 +- categories/index.html | 8 +- .../CAP\345\256\232\347\220\206/index.html" | 4 +- .../index.html" | 4 +- css/main.css | 2 +- index.html | 330 ++-- page/2/index.html | 409 ++-- page/3/index.html | 212 +- post/102cd3d9.html | 4 +- post/11cb7677.html | 4 +- post/192cb539.html | 4 +- post/24042edf.html | 8 +- post/34755d6c.html | 4 +- post/3ae0ff4e.html | 4 +- post/4615256d.html | 4 +- post/4b00e13c.html | 1743 +++++++++++++++++ post/4ea48fa7.html | 4 +- post/51e5bd99.html | 4 +- post/710bd10b.html | 4 +- post/7528c810.html | 4 +- post/7b9ead86.html | 4 +- post/7eb2637f.html | 4 +- post/817c7d82.html | 4 +- post/8a061473.html | 4 +- post/8bd965a0.html | 4 +- post/99ea2970.html | 4 +- post/a38c0645.html | 4 +- post/ab706eb5.html | 4 +- post/b1d4025b.html | 4 +- post/bc557e1a.html | 4 +- post/bfcdfeaf.html | 4 +- post/e09f0428.html | 4 +- post/ee27c07f.html | 4 +- post/f440d00b.html | 4 +- post/fe76043.html | 4 +- search.xml | 14 + sitemap.xml | 7 + tags/Bloom-filter/index.html | 4 +- "tags/CAP\345\256\232\347\220\206/index.html" | 4 +- tags/Eureka/index.html | 4 +- tags/GC/index.html | 4 +- tags/Guava/index.html | 4 +- tags/IDEA/index.html | 4 +- "tags/IO\346\250\241\345\236\213/index.html" | 4 +- tags/JDK/index.html | 4 +- tags/JVM/index.html | 4 +- .../Java-\345\216\237\347\220\206/index.html" | 4 +- .../Java-\345\271\266\345\217\221/index.html" | 4 +- tags/Java/index.html | 56 +- tags/Java/page/2/index.html | 56 +- tags/Java/page/3/index.html | 30 +- .../Linux\347\254\224\350\256\260/index.html" | 4 +- tags/String/index.html | 4 +- tags/index.html | 6 +- tags/mockito/index.html | 4 +- tags/test/index.html | 4 +- .../index.html" | 4 +- "tags/\345\217\215\345\260\204/index.html" | 4 +- .../index.html" | 4 +- "tags/\345\267\245\345\205\267/index.html" | 4 +- "tags/\345\271\266\345\217\221/index.html" | 30 +- "tags/\345\274\202\346\255\245/index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- "tags/\351\207\215\346\236\204/index.html" | 4 +- 110 files changed, 5502 insertions(+), 827 deletions(-) create mode 100644 archives/2020/06/index.html create mode 100644 "categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" create mode 100644 post/4b00e13c.html diff --git a/about/index.html b/about/index.html index 02009ce8..784e2cc0 100644 --- a/about/index.html +++ b/about/index.html @@ -408,7 +408,7 @@

- 26 + 27 日志 @@ -419,7 +419,7 @@

- 26 + 27 分类 diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html index 0df1211b..ba1b32be 100644 --- a/archives/2019/10/index.html +++ b/archives/2019/10/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -546,7 +546,7 @@

- 26 + 27 日志 @@ -557,7 +557,7 @@

diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html index a1faf76a..05ad8531 100644 --- a/archives/2019/11/index.html +++ b/archives/2019/11/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 26 + 27 日志 @@ -522,7 +522,7 @@

diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html index a39780e2..63658a00 100644 --- a/archives/2019/12/index.html +++ b/archives/2019/12/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 26 + 27 日志 @@ -522,7 +522,7 @@

diff --git a/archives/2019/index.html b/archives/2019/index.html index 701ee18e..003aadd9 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -725,7 +725,7 @@

- 26 + 27 日志 @@ -736,7 +736,7 @@

diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html index 3b6156f6..0ca55bc2 100644 --- a/archives/2019/page/2/index.html +++ b/archives/2019/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -480,7 +480,7 @@

- 26 + 27 日志 @@ -491,7 +491,7 @@

diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html index 6263e9dd..6ca4f4a1 100644 --- a/archives/2020/01/index.html +++ b/archives/2020/01/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -441,7 +441,7 @@

- 26 + 27 日志 @@ -452,7 +452,7 @@

diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html index 37193d1b..d1c879a5 100644 --- a/archives/2020/02/index.html +++ b/archives/2020/02/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -406,7 +406,7 @@

- 26 + 27 日志 @@ -417,7 +417,7 @@

diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index eba5965a..18cf597b 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 26 + 27 日志 @@ -522,7 +522,7 @@

diff --git a/archives/2020/04/index.html b/archives/2020/04/index.html index fb8cac7c..201b3d2a 100644 --- a/archives/2020/04/index.html +++ b/archives/2020/04/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 26 + 27 日志 @@ -522,7 +522,7 @@

diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index 1737c0a6..920d93f4 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -441,7 +441,7 @@

- 26 + 27 日志 @@ -452,7 +452,7 @@

diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html new file mode 100644 index 00000000..f3230fe8 --- /dev/null +++ b/archives/2020/06/index.html @@ -0,0 +1,1269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/index.html b/archives/2020/index.html index 6a663f18..3e83537c 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+
+
+ +

+ + + +

+ + + +
+
+ + + + + + + + + + + + + +
@@ -633,41 +668,6 @@

- - - - - - - - - - - - - - - @@ -725,7 +725,7 @@

- 26 + 27 日志 @@ -736,7 +736,7 @@

diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html index e86faa31..1fa3990f 100644 --- a/archives/2020/page/2/index.html +++ b/archives/2020/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -480,7 +515,7 @@

- 26 + 27 日志 @@ -491,7 +526,7 @@

diff --git a/archives/index.html b/archives/index.html index 9df86465..1a6eebd7 100644 --- a/archives/index.html +++ b/archives/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -633,41 +668,6 @@

- - - - - - - - - - - - - - - @@ -725,7 +725,7 @@

- 26 + 27 日志 @@ -736,7 +736,7 @@

diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 08945dc1..7a43af04 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -638,41 +673,6 @@

- - - - - - - - - - - - - - - @@ -730,7 +730,7 @@

- 26 + 27 日志 @@ -741,7 +741,7 @@

diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 347b7358..e3bf2a84 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 26 篇日志。 继续努力。 + 嗯..! 目前共计 27 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2019

+ + + + + + + + + + + + + + +
@@ -585,7 +620,7 @@

- 26 + 27 日志 @@ -596,7 +631,7 @@

diff --git a/atom.xml b/atom.xml index ee49cbcf..63495fe8 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2020-06-03T08:03:59.893Z + 2020-06-11T13:52:13.721Z https://www.mghio.cn/ @@ -16,6 +16,35 @@ Hexo + + Java 中队列同步器 AQS(AbstractQueuedSynchronizer)实现原理 + + https://www.mghio.cn/post/4b00e13c.html + 2020-06-13T12:48:00.000Z + 2020-06-11T13:52:13.721Z + + 前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

AQS 基础数据结构

同步队列

队列同步器 AQS(下文简称为同步器)主要是依赖于内部的一个 FIFO(first-in-first-out)双向队列来对同步状态进行管理的,当线程获取同步状态失败时,同步器会将当前线程和当前等待状态等信息封装成一个内部定义的节点 Node,然后将其加入队列,同时阻塞当前线程;当同步状态释放时,会将同步队列中首节点唤醒,让其再次尝试去获取同步状态。同步队列的基本结构如下:

AQS_QUEUE.png

队列节点 Node

同步队列使用同步器中的静态内部类 Node 用来保存获取同步状态的线程的引用、线程的等待状态、前驱节点和后继节点。

AQS_inner_class_node.png

同步队列中 Node 节点的属性名称和具体含义如下表所示:

属性类型和名称描述
volatile int waitStatus当前节点在队列中的等待状态
volatile Node prev前驱节点,当节点加入同步队列时被赋值(使用尾部添加方式)
volatile Node next后继节点
volatile Thread thread获取同步状态的线程
Node nextWaiter等待队列中的后继节点,如果当前节点是共享的,则该字段是一个 SHARED 常量

每个节点线程都有两种锁模式,分别为 SHARED 表示线程以共享的模式等待锁,EXCLUSIVE 表示线程以独占的方式等待锁。同时每个节点的等待状态 waitStatus 只能取以下表中的枚举值:

枚举值描述
SIGNAL值为 -1,表示该节点的线程已经准备完毕,等待资源释放
CANCELLED值为 1,表示该节点线程获取锁的请求已经取消了
CONDITION值为 -2,表示该节点线程等待在 Condition 上,等待被其它线程唤醒
PROPAGATE值为 -3,表示下一次共享同步状态获取会无限进行下去,只在 SHARED 情况下使用
0值为 0,初始状态,初始化的默认值
同步状态 state

同步器内部使用了一个名为 stateint 类型的变量表示同步状态,同步器的主要使用方式是通过继承,子类通过继承并实现它的抽象方法来管理同步状态,同步器给我们提供了如下三个方法来对同步状态进行更改。

方法签名描述
protected final int getState()获取当前同步状态
protected final void setState(int newState)设置当前同步状态
protected final boolean compareAndSetState(int expect, int update)使用 CAS 设置当前状态,该方法能够保证状态设置的原子性

在独享锁中同步状态 state 这个值通常是 0 或者 1(如果是重入锁的话 state 值就是重入的次数),在共享锁中 state 就是持有锁的数量。

独占式同步状态获取与释放

同步器中提供了 acquire(int arg) 方法来进行独占式同步状态的获取,获取到了同步状态也就是获取到了锁,该方法源码如下所示:

1
2
3
4
5
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}

方法首先会调用 tryAcquire 方法尝试去获取锁,查看方法的源码可以发现,同步器并未对该方法进行实现(只是抛出一个不支持操作异常 UnsupportedOperationException),这个方法是需要后续同步组件的开发人员自己去实现的,如果方法返回 true 则表示当前线程成功获取到锁,调用 selfInterrupt() 中断当前线程(PS:这里留给大家一个问题:为什么获取了锁以后还要中断线程呢?),方法结束返回,如果方法返回 false 则表示当前线程获取锁失败,也就是说有其它线程先前已经获取到了锁,此时就需要把当前线程以及等待状态等信息添加到同步队列中,下面来看看同步器在线程未获取到锁时具体是如何实现。
通过源码发现,当获取锁失败时,会执行判断条件与操作的后半部分 acquireQueued(addWaiter(Node.EXCLUSIVE), arg),首先指定锁模式为 Node.EXCLUSIVE 调用 addWaiter 方法,该方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}

通过方法参数指定的锁模式(共享锁 or 独占锁)和当前线程构造出一个 Node 节点,如果同步队列已经初始化,那么首先会进行一次从尾部加入队列的尝试,使用 compareAndSetTail 方法保证原子性,进入该方法源码可以发现是基于 sun.misc 包下提供的 Unsafe 类来实现的。如果首次尝试加入同步队列失败,会再次调用 enq 方法进行入队操作,继续跟进 enq 方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}

通过其源码可以发现和第一次尝试加入队列的代码类似,只是该方法里面加了同步队列初始化判断,使用 compareAndSetHead 方法保证设置头节点的原子性,同样它底层也是基于 Unsafe 类,然后外层套了一个 for (;;) 死循环,循环唯一的退出条件是从队尾入队成功,也就是说如果从该方法成功返回了就表示已经入队成功了,至此,addWaiter 执行完毕返回当前 Node 节点。然后以该节点作为 acquireQueued 方法的入参继续进行其它步骤,该方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}

可以看到,该方法本质上也是通过一个死循环(自旋)去获取锁并且支持中断,在循环体外面定义两个标记变量,failed 标记是否成功获取到锁,interrupted 标记在等待的过程中是否被中断过。方法首先通过 predecessor 获取当前节点的前驱节点,当当前节点的前驱节点是 head 头节点时就调用 tryAcquire 尝试获取锁,也就是第二个节点则尝试获取锁,这里为什么要从第二个节点才尝试获取锁呢?是因为同步队列本质上是一个双向链表,在双向链表中,第一个节点并不存储任何数据是虚节点,只是起到一个占位的作用,真正存储数据的节点是从第二个节点开始的。如果成功获取锁,也就是 tryAcquire 方法返回 true 后,将 head 指向当前节点并把之前找到的头节点 p 从队列中移除,修改是否成功获取到锁标记,结束方法返回中断标记。
如果当前节点的前驱节点 p 不是头节点或者前驱节点 p 是头节点但是获取锁操作失败,那么会调用 shouldParkAfterFailedAcquire 方法判断当前 node 节点是否需要被阻塞,这里的阻塞判断主要是为了防止长时间自旋给 CPU 带来非常大的执行开销,浪费资源。该方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}

方法参数为当前节点的前驱节点以及当前节点,主要是靠前驱节点来判断是否需要进行阻塞,首先获取到前驱节点的等待状态 ws,如果节点状态 wsSIGNAL,表示前驱节点的线程已经准备完毕,等待资源释放,方法返回 true 表示可以阻塞,如果 ws > 0,通过上文可以知道节点只有一个状态 CANCELLED(值为 1) 满足该条件,表示该节点线程获取锁的请求已经取消了,会通过一个 do-while 循环向前查找 CANCELLED 状态的节点并将其从同步队列中移除,否则进入 else 分支,使用 compareAndSetWaitStatus 原子操作将前驱节点的等待状态修改为 SIGNAL,以上这两种情况都不需要进行阻塞方法返回 false
当经过判断后需要阻塞的话,也就是 compareAndSetWaitStatus 方法返回 true 时,会通过 parkAndCheckInterrupt 方法阻塞挂起当前线程,并返回当前线程的中断标识。方法如下:

1
2
3
4
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}

线程阻塞是通过 LockSupport 这个工具类实现的,深入其源码可以发现它底层也是基于 Unsafe 类实现的。如果以上两个方法都返回 true 的话就更新中断标记。这里还有一个问题就是什么时候会将一个节点的等待状态 waitStatus 修改为 CANCELLED 节点线程获取锁的请求取消状态呢?细心的朋友可能已经发现了,在上文贴出的 acquireQueued 方法源码中的 finally 块中会根据 failed 标记来决定是否调用 cancelAcquire 方法,这个方法就是用来将节点状态修改为 CANCELLED 的,方法的具体实现留给大家去探索。至此 AQS 独占式同步状态获取锁的流程就完成了,下面通过一个流程图来看看整体流程:

AQS_acquire.png


下面再看看独占式锁释放的过程,同步器使用 release 方法来让我们进行独占式锁的释放,其方法源码如下:

1
2
3
4
5
6
7
8
9
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}

首先调用 tryRelease 方法尝试进行锁释放操作,继续跟进该方法发现同步器只是抛出了一个不支持操作异常 UnsupportedOperationException,这里和上文独占锁获取中 tryAcquire 方法是一样的套路,需要开发者自己定义锁释放操作。

AQS_tryrelease.png

通过其 JavaDoc 可以得知,如果返回 false,则表示释放锁失败,方法结束。该方法如果返回 true,则表示当前线程释放锁成功,需要通知队列中等待获取锁的线程进行锁获取操作。首先获取头节点 head,如果当前头节点不为 null,并且其等待状态不是初始状态(0),则解除线程阻塞挂起状态,通过 unparkSuccessor 方法实现,该方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);

/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}

首先获取头节点的等待状态 ws,如果状态值为负数(Node.SIGNAL or Node.PROPAGATE),则通过 CAS 操作将其改为初始状态(0),然后获取头节点的后继节点,如果后继节点为 null 或者后继节点状态为 CANCELLED(获取锁请求已取消),就从队列尾部开始寻找第一个状态为非 CANCELLED 的节点,如果该节点不为空则使用 LockSupportunpark 方法将其唤醒,该方法底层是通过 Unsafe 类的 unpark 实现的。这里需要从队尾查找非 CANCELLED 状态的节点的原因是,在之前的获取独占锁失败时的入队 addWaiter 方法实现中,该方法如下:

AQS_unparkSuccessor.png

假设一个线程执行到了上图中的 ① 处,② 处还没有执行,此时另一个线程恰好执行了 unparkSuccessor 方法,那么就无法通过从前向后查找了,因为节点的后继指针 next 还没赋值呢,所以需要从后往前进行查找。至此,独占式锁释放操作就结束了,同样的,最后我们也通过一个流程图来看看整个锁释放的过程:

AQS_release.png

独占式可中断同步状态获取

同步器提供了 acquireInterruptibly 方法来进行可响应中断的获取锁操作,方法实现源码如下:

1
2
3
4
5
6
7
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}

方法首先检查当前线程的中断状态,如果已中断,则直接抛出中断异常 InterruptedException 即响应中断,否则调用 tryAcquire 方法尝试获取锁,如果获取成功则方法结束返回,获取失败调用 doAcquireInterruptibly 方法,跟进该方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}

仔细观察可以发现该方法实现源码和上文中 acquireQueued 方法的实现基本上类似,只是这里把入队操作 addWaiter 放到了方法里面了,还有一个区别就是当在循环体内判断需要进行中断时会直接抛出异常来响应中断,两个方法的对比如下:

AQS_acquirequeued_interruptibly_compare.png

其它步骤和独占式锁获取一致,流程图大体上和不响应中断的锁获取差不多,只是在最开始多了一步线程中断状态检查和循环是会抛出中断异常而已。

独占式超时获取同步状态

同步器提供了 tryAcquireNanos 方法可以超时获取同步状态(也就是),该方法提供了之前 synchronized 关键字不支持的超时获取的特性,通过该方法我们可以在指定时间段 nanosTimeout 内获取锁,如果获取到锁则返回 true,否则,返回 false。方法源码如下:

1
2
3
4
5
6
7
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}

首先会调用 tryAcquire 方法尝试获取一次锁,如果获取锁成功则立即返回,否则调用 doAcquireNanos 方法进入超时获取锁流程。通过上文可以得知,同步器的 acquireInterruptibly 方法在等待获取同步状态时,如果当前线程被中断了,会抛出中断异常 InterruptedException 并立刻返回。超时获取锁的流程其实是在响应中断的基础上增加了超时获取的特性,doAcquireNanos 方法的源码如下:

1
2
3
4
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
30
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}

由以上方法实现源码可以看出,针对超时获取这里主要实现思路是:先使用当前时间加上参数传入的超时时间间隔 deadline 计算出超时的时间点,然后每次进行循环的时候使用超时时间点 deadline 减去当前时间得到剩余的时间 nanosTimeout,如果剩余时间小于 0 则证明当前获取锁操作已经超时,方法结束返回 false,反如果剩余时间大于 0。
可以看到在里面执行自旋的时候和上面独占式同步获取锁状态 acquireQueued 方法那里是一样的套路,即当当前节点的前驱节点为头节点时调用 tryAcquire 尝试获取锁,如果获取成功则返回。

AQS_acquireQueued_doAcquireNanos_compare.png

除了超时时间计算那里不同外,还有个不同的地方就是在超时获取锁失败之后的操作,如果当前线程获取锁失败,则判断剩余超时时间 nanosTimeout 是否小于 0,如果小于 0 则表示已经超时方法立即返回,反之则会判断是否需要进行阻塞挂起当前线程,如果通过 shouldParkAfterFailedAcquire 方法判断需要挂起阻塞当前线程,还要进一步比较超时剩余时间 nanosTimeoutspinForTimeoutThreshold 的大小,如果小于等于 spinForTimeoutThreshold 值(1000 纳秒)的话,将不会使当前线程进行超时等待,而是再次进行自旋过程。
加后面这个判断的主要原因在于,在非常短(小于 1000 纳秒)的时间内的等待无法做到十分精确,如果这时还进行超时等待的话,反而会让我们指定 nanosTimeout 的超时从整体上给人感觉反而不太精确,因此,在剩余超时时间非常短的情况下,同步器会再次自旋进行超时获取锁的过程,独占式超时获取锁整个过程如下所示:

AQS_tryAcquireNanos_flow.png

共享式同步状态获取与释放

共享锁顾名思义就是可以多个线程共用一个锁,在同步器中使用 acquireShared 来获取共享锁(同步状态),方法源码如下:

1
2
3
4
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}

首先通过 tryAcquireShared 尝试获取共享锁,该方法是一个模板方法在同步器中只是抛出一个不支持操作异常,需要开发人员自己去实现,同时方法的返回值有三种不同的类型分别代表三种不同的状态,其含义如下:

  1. 小于 0 表示当前线程获取锁失败
  2. 等于 0 表示当前线程获取锁成功,但是之后的线程在没有锁释放的情况下获取锁将失败,也就是说这个锁是共享模式下的最后一把锁了
  3. 大于 0 表示当前线程获取锁成功,并且还有剩余的锁可以获取

当方法 tryAcquireShared 返回值小于 0 时,也就是获取锁失败,将会执行方法 doAcquireShared,继续跟进该方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}

方法首先调用 addWaiter 方法封装当前线程和等待状态为共享模块的节点并将其添加到等待同步队列中,可以发现在共享模式下节点的 nextWaiter 属性是固定值 Node.SHARED。然后循环获取当前节点的前驱节点,如果前驱节点是头节点的话就尝试获取共享锁,如果返回值大于等于 0 表示获取共享锁成功,则调用 setHeadAndPropagate 方法,更新头节点同时如果有可用资源,则向后传播,唤醒后继节点,接下来会检查一下中断标识,如果已经中断则中断当前线程,方法结束返回。如果返回值小于 0,则表示获取锁失败,需要挂起阻塞当前线程或者继续自旋获取共享锁。下面看看 setHeadAndPropagate 方法的具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
setHead(node);
/*
* Try to signal next queued node if:
* Propagation was indicated by caller,
* or was recorded (as h.waitStatus either before
* or after setHead) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}

首先将当前获取到锁的节点设置为头节点,然后方法参数 propagate > 0 时表示之前 tryAcquireShared 方法的返回值大于 0,也就是说当前还有剩余的共享锁可以获取,则获取当前节点的后继节点并且后继节点是共享节点时唤醒节点去尝试获取锁,doReleaseShared 方法是同步器共享锁释放的主要逻辑。


同步器提供了 releaseShared 方法来进行共享锁的释放,方法源码如下所示:

1
2
3
4
5
6
7
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}

首先调用 tryReleaseShared 方法尝试释放共享锁,方法返回 false 代表锁释放失败,方法结束返回 false,否则就表示成功释放锁,然后执行 doReleaseShared 方法,进行唤醒后继节点并检查它是否可以向后传播等操作。继续跟进该方法如下:

1
2
3
4
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
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}

可以看到和独占式锁释放不同的是,在共享模式下,状态同步和释放可以同时执行,其原子性由 CAS 来保证,如果头节点改变了也会继续循环。每次共享节点在共享模式下唤醒时,头节点都会指向它,这样就可以保证可以获取到共享锁的所有后续节点都可以唤醒了。

如何自定义同步组件

JDK 中基于同步器实现的一些类绝大部分都是聚合了一个或多个继承了同步器的类,使用同步器提供的模板方法自定义内部同步状态的管理,然后通过这个内部类去实现同步状态管理的功能,其实这从某种程度上来说使用了 模板模式。比如 JDK 中可重入锁 ReentrantLock、读写锁 ReentrantReadWriteLock、信号量 Semaphore 以及同步工具类 CountDownLatch 等,其源码部分截图如下:

AQS_use_in_jdk_examples.png

通过上文可以知道,我们基于同步器可以分别自定义独占锁同步组件和共享锁同步组件,下面以实现一个在同一个时刻最多只允许 3 个线程访问,其它线程的访问将被阻塞的同步工具 TripletsLock 为例,很显然这个工具是共享锁模式,主要思路就是去实现一个 JDk 中的 Lock 接口来提供面向使用者的方法,比如,调用 lock 方法获取锁,使用 unlock 来对锁进行释放等,在 TripletsLock 类内部有一个自定义同步器 Sync 继承自同步器 AQS,用来对线程的访问和同步状态进行控制,当线程调用 lock 方法获取锁时,自定义同步器 Sync 先计算出获取到锁后的同步状态,然后使用 Unsafe 类操作来保证同步状态更新的原子性,由于同一时刻只能 3 个线程访问,这里我们可以将同步状态 state 的初始值设置为 3,表示当前可用的同步资源数量,当有线程成功获取到锁时将同步状态 state 减 1,有线程成功释放锁时将同步状态加 1,同步状态的取值范围为 0、1、2、3,同步状态为 0 时表示没有可用同步资源,这个时候如果有线程访问将被阻塞。下面来看看这个自定义同步组件的实现代码:

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/**
* @author mghio
* @date: 2020-06-13
* @version: 1.0
* @description:
* @since JDK 1.8
*/
public class TripletsLock implements Lock {

private final Sync sync = new Sync(3);

private static final class Sync extends AbstractQueuedSynchronizer {
public Sync(int state) {
setState(state);
}

Condition newCondition() {
return new ConditionObject();
}

@Override
protected int tryAcquireShared(int reduceCount) {
for (; ;) {
int currentState = getState();
int newState = currentState - reduceCount;
if (newState < 0 || compareAndSetState(currentState, newState)) {
return newState;
}
}
}

@Override
protected boolean tryReleaseShared(int count) {
for (; ;) {
int currentState = getState();
int newState = currentState + count;
if (compareAndSetState(currentState, newState)) {
return true;
}
}
}
}

@Override
public void lock() {
sync.acquireShared(1);
}

@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}

@Override
public boolean tryLock() {
return sync.tryAcquireShared(1) > 0;
}

@Override
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

@Override
public void unlock() {
sync.releaseShared(1);
}

@Override
public Condition newCondition() {
return sync.newCondition();
}
}

下面启动 20 个线程测试看看自定义同步同步工具类 TripletsLock 是否达到我们的预期。测试代码如下:

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* @author mghio
* @date: 2020-06-13
* @version: 1.0
* @description:
* @since JDK 1.8
*/
public class TripletsLockTest {
private final Lock lock = new TripletsLock();
private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

@Test
public void testTripletsLock() {
// 启动 20 个线程
for (int i = 0; i < 20; i++) {
Thread worker = new Runner();
worker.setDaemon(true);
worker.start();
}

for (int i = 0; i < 20; i++) {
second(2);
System.out.println();
}
}

private class Runner extends Thread {
@Override
public void run() {
for (; ;) {
lock.lock();
try {
second(1);
System.out.println(dateFormat.format(new Date()) + " ----> " + Thread.currentThread().getName());
second(1);
} finally {
lock.unlock();
}
}
}
}

private static void second(long seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

测试结果如下:

AQS_TripletsLock_Test_Result.png

从以上测试结果可以发现,同一时刻只有三个线程可以获取到锁,符合预期,这里需要明确的是这个锁获取过程是非公平的。

总结

本文主要是对同步器中的基础数据结构、独占式与共享式同步状态获取与释放过程做了简要分析,由于水平有限如有错误之处还请留言讨论。队列同步器 AbstractQueuedSynchronizerJDK 中很多的一些多线程并发工具类的实现基础框架,对其深入学习理解有助于我们更好的去使用其特性和相关工具类。


参考文章

Java并发编程的艺术
Java Synchronizer - AQS Learning
从 ReentrantLock 的实现看 AQS 的原理及应用
The java.util.concurrent Synchronizer Framework

]]> + + + + <h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>在 <code>Java</code> 中通过 <code>锁</code> 来控制多个线程对共享资源的访问,使用 <code>Java</code> 编程语言开发的朋友都知道,可以通过 <code>synchronized</code> 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 <code>synchronized</code> 关键字就比较难实现了。<br>在 <code>Java SE 5</code> 之后,新增加了 <code>Lock</code> 接口和一系列的实现类来提供和 <code>synchronized</code> 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。<code>JDK</code> 中提供的 <code>Lock</code> 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——<code>队列同步器 AQS(AbstractQueuedSynchronizer)</code>。</p> + + + + + + + + + + + + + + + + + 一文让你快速上手 Mockito 单元测试框架 @@ -614,35 +643,4 @@ - - 深挖 HashMap - - https://www.mghio.cn/post/99ea2970.html - 2019-11-14T13:23:23.000Z - 2019-11-16T09:06:26.019Z - - 1.1 前言

做过 java 开发的朋友们相信都很熟悉 HashMap 这个类,它是一个基于 hashing 原理用于存储 Key-Value 键值对的集合,其中的每一个键也叫做 Entry,这些键分别存储在一个数组当中,系统会根据 hash 方法来计算出 Key-Value 的存储位置,可以通过 key 快速存取 value。
HashMap 基于 hashing 原理,当我们将一个键值对(Key-Value) 传入 put 方法时,它将调用这个 key 的 hashcode 方法计算出 key 的 hashcode 值,然后根据这个 hashcode 值来定位其存放数组的位置来存储对象(HashMap 使用链表来解决碰撞问题,当其发生碰撞了,对象将会存储在链表的下一个节点中,在链表的每个节点中存储 Entry 对象,在 JDK 1.8+ 中,当链表的节点个数超过一定值时会转为红黑树来进行存储),当通过 get 方法传入一个 key 来获取其对应的值时,也是先通过 key 的 hashcode 方法来定位其存储在数组的位置,然后通过键对象的 eqauls 方法找到对应的 value 值。接下来让我们看看其内部的一些实现细节。(PS:以下代码分析都是基于 JDK 1.8

1.2 为什么容量始终是 2 的整数次幂

因为获取 key 在数组中对应的下标是通过 key 的哈希值与数组的长度减一进行与运算来确定的(tab[(n - 1) & hash])。当数组的长度 n 为 2 的整数次幂,这样进行 n - 1 运算后,之前为 1 的位后面全是 1 ,这样就能保证 (n - 1) & hash 后相应位的值既可能是 1 又可能是 0 ,这完全取决于 key 的哈希值,这样就能保证散列的均匀,同时与运算(位运算)效率高。如果数组的长度 n 不是 2 的整数次幂,会造成更多的 hash 冲突。HashMap 提供了如下四个重载的构造方法来满足不同的使用场景:

  1. 无参构造:HashMap(),使用该方法表示全部使用 HashMap 的默认配置参数
  2. 指定容量初始值构造:HashMap(int initialCapacity),在初始化 HashMap 时指定其容量大小
  3. 指定容量初始值和扩容因子构造:HashMap(int initialCapacity, float loadFactor),使用自定义初始化容量和扩容因子
  4. 通过 Map 来构造 HashMap:HashMap(Map<? extends K, ? extends V> m),使用默认的扩容因子,其容量大小有传入的 Map 大小来决定前三个构造方法最终都是调用第三个即自定义容量初始值和扩容因子构造 HashMap(int initialCapacity, float loadFactor),其源码实现如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
    throw new IllegalArgumentException("Illegal initial capacity: " +
    initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
    initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
    throw new IllegalArgumentException("Illegal load factor: " +
    loadFactor);
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);
    }

从源码实现可以看出,如果我们传入的初始容量值大于 MAXIMUM_CAPACITY 时,就设置容量为 MAXIMUM_CAPACITY,其值如下:

1
2
3
4
5
6
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;

也就是容量的最大值为 2 的 30 次方(1 << 30)。我们知道,HashMap 的容量始终是 2 的整数次幂,不管我们传入的初始容量是什么,它都会使用最接近这个值并且是 2 的整数次幂作为 HashMap 的初始容量,这一步处理是通过 tableSizeFor 方法来实现的,我们看看它的源码:

hashmap-tableSizeFor.png

通过方法的注释我们也可以知道(英语对于从事技术开发的人太重要了~~~),此方法的返回值始终是 2 的整数次幂,它是如何做到的呢?接下来我们通过一个例子一步一步来看,假设我们传入的初始容量大小 cap 的值 cap 为 15。

第 ① 步:将 cap - 1 后,n 的值为 14(15 - 1)。

第 ② 步:将 n 的值先右移 1 位后与 n 进行 或运算(两者都为 0 结果为 0,其它情况都为 1),下面是具体的计算过程:

hashmap-tableSizeFor-2.png

第 ③ 步:将 n 的值先右移 2 位后与 n 进行 或运算(两者都为 0 结果为 0,其它情况都为 1),下面是具体的计算过程:

hashmap-tableSizeFor-3.png

第 ④ 步:将 n 的值先右移 4 位后与 n 进行 或运算(两者都为 0 结果为 0,其它情况都为 1),下面是具体的计算过程:

hashmap-tableSizeFor-4.png

第 ⑤ 步:将 n 的值先右移 8 位后与 n 进行 或运算(两者都为 0 结果为 0,其它情况都为 1),下面是具体的计算过程:

hashmap-tableSizeFor-5.png

第 ⑥ 步:将 n 的值先右移 16 位后与 n 进行 或运算(两者都为 0 结果为 0,其它情况都为 1),下面是具体的计算过程:

hashmap-tableSizeFor-6.png

最后如果 n 的值小于 0,则返回 1,如果大于最大值 MAXIMUM_CAPACITY 则返回 MAXIMUM_CAPACITY,否则返回 n + 1。 现在 n 为 15,所以返回 n + 1(16),而 16 正好是 2 的 4 次幂。有的朋友可能会问,刚刚上文假设的初始容量大小 cap 是 15,本来就不是 2 的整数次幂,如果我传入初始容量的就是 2 的整数次幂那会怎么样呢?现在假设传的初始容量大小为 32(2 的 5 次方)看看结果是什么。

第 ① 步:将 cap - 1 后,n 的值为 31(32 - 1)。

第 ② 步:将 n 的值先右移 1 位后与 n 进行 或运算(两者都为 0 结果为 0,其它情况都为 1),下面是具体的计算过程:

hashmap-tableSizeFor-even-1.png

第 ③ 步:将 n 的值先右移 2 位后与 n 进行 或运算(两者都为 0 结果为 0,其它情况都为 1),下面是具体的计算过程:

hashmap-tableSizeFor-even-2.png

第 ④ 步:将 n 的值先右移 4 位后与 n 进行 或运算(两者都为 0 结果为 0,其它情况都为 1),下面是具体的计算过程:

hashmap-tableSizeFor-even-4.png

第 ⑤ 步:将 n 的值先右移 8 位后与 n 进行 或运算(两者都为 0 结果为 0,其它情况都为 1),下面是具体的计算过程:

hashmap-tableSizeFor-even-5.png

第 ⑥ 步:将 n 的值先右移 16 位后与 n 进行 或运算(两者都为 0 结果为 0,其它情况都为 1),下面是具体的计算过程:

hashmap-tableSizeFor-even-6.png

经过以上 6 步计算后得出 n 的值为 31,大于 0 小于 MAXIMUM_CAPACITY 返回 n + 1,所以经过计算后的初始容量大小为 32。稍微总结一下,我们可以得出:如果我们传入的初始容量大小不是 2 的整数次幂,那么经过计算后的初始容量大小为大于我们传入初始容量值的最小值并且是 2 的整数次幂。细心的朋友会发现,为什么第一步要进行 cap - 1 的操作呢?那是因为,如果不进行 - 1 运算的话,当我们传入的初始容量大小为 2 的整数次幂的时候,通过以上步骤计算出来的结果值为传入值的 2 倍。假设我们传入的初始容量大小为 32,此时没有第 ① 步(cap - 1)的操作,那么依次通过以上 ②、③、④、⑤、⑥ 后为 63,最后再进行 n + 1 操作,结果为 64 是 传入值 32 的 2 倍,显然和预期结果(32)不符。这个计算初始容量的算法还是很巧妙的,先进行了 -1 的操作,保证传入初始容量值为 2 的整数次幂的时候,返回传入的原始值。

1.3 hash 方法是如何实现的

不管是通过 get 方法获取 key 对应的 Value 值或者通过 put 方法存储 Key-Value 键值对时,都会先根据 key 的哈希值定位到数组的位置,我们看看 HashMap 里的 hash 方法是如何实现的,源码如下:

1
2
3
4
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

当 key 为 null 时,返回 0,否则进行 h = key.hashCode()) ^ (h >>> 16 运算,先调用 key 的 hashCode 方法获取 key 的哈希值,然后与 key 的哈希值右移 16 位后的值进行异或运算(相同为 0,不同为 1,简称 同假异真),为什么获取 key 的哈希值还要再进行异或运算,直接返回 key 的哈希值好像也没什么问题,如果没有后面的异或运算,直接返回哈希值,我们假设数组的长度为 16,现在要往 HashMap 存入的三个键值对的 key 的哈希值分别为 32831、33554495、2097215,根据 hash 方法返回值定位到数组的位置((n - 1) & hash),以上三个值和 15(16 - 1)进行 & 运算(都为 1 才为 1,其它情况都为 0) 如下:

hashmap-hashcode-2.png

可以发现以上三个哈希值都定位的数组下标为 15 的位置上。所以 hash 如果方法没有后面与哈希值右移 16 位后的值进行异或运算的话,当数组长度比较小时很容易造成 哈希碰撞,即多个 key(不同的哈希值)都会定位到数组上的同一个位置,也就是说会放入到同一个链表或者红黑树中,因为此时 key 的哈希值只有低位的才会参与运算,显然和我们的预期不符合。可见 hash 方法将 key 的哈希值与其右移 16 位后进行异或运算能减少哈希碰撞的次数,把高位和低位都参与了运算,提高了分散性。

1.4 总结

HashMap 其实还有很多值得我们深入研究的点,看懂了上面两个方法后,不得不佩服作者的代码设计能力,JDK 中有很多优秀源码都值得我们好好品味,看代码的时候一定要多看几遍多问几个为什么,特别是经典的源代码,然后将这些思想运用到我们的实际工作中。

]]>
- - - - <h4 id="1-1-前言"><a href="#1-1-前言" class="headerlink" title="1.1 前言"></a>1.1 前言</h4><p>做过 java 开发的朋友们相信都很熟悉 HashMap 这个类,它是一个基于 hashing 原理用于存储 Key-Value 键值对的集合,其中的每一个键也叫做 <code>Entry</code>,这些键分别存储在一个数组当中,系统会根据 <code>hash</code> 方法来计算出 Key-Value 的存储位置,可以通过 key 快速存取 value。<br>HashMap 基于 hashing 原理,当我们将一个键值对(Key-Value) 传入 <code>put</code> 方法时,它将调用这个 key 的 <code>hashcode</code> 方法计算出 key 的 hashcode 值,然后根据这个 hashcode 值来定位其存放数组的位置来存储对象(HashMap 使用链表来解决碰撞问题,当其发生碰撞了,对象将会存储在链表的下一个节点中,在链表的每个节点中存储 <code>Entry</code> 对象,在 JDK 1.8+ 中,当链表的节点个数超过一定值时会转为红黑树来进行存储),当通过 <code>get</code> 方法传入一个 key 来获取其对应的值时,也是先通过 key 的 <code>hashcode</code> 方法来定位其存储在数组的位置,然后通过键对象的 <code>eqauls</code> 方法找到对应的 value 值。接下来让我们看看其内部的一些实现细节。(<code>PS:以下代码分析都是基于 JDK 1.8</code>)</p> -<h4 id="1-2-为什么容量始终是-2-的整数次幂"><a href="#1-2-为什么容量始终是-2-的整数次幂" class="headerlink" title="1.2 为什么容量始终是 2 的整数次幂"></a>1.2 为什么容量始终是 2 的整数次幂</h4><p>因为获取 key 在数组中对应的下标是通过 key 的哈希值与数组的长度减一进行与运算来确定的(<code>tab[(n - 1) &amp; hash]</code>)。当数组的长度 n 为 2 的整数次幂,这样进行 n - 1 运算后,之前为 1 的位后面全是 1 ,这样就能保证 <code>(n - 1) &amp; hash</code> 后相应位的值既可能是 1 又可能是 0 ,这完全取决于 key 的哈希值,这样就能保证散列的均匀,同时与运算(位运算)效率高。如果数组的长度 n 不是 2 的整数次幂,会造成更多的 hash 冲突。HashMap 提供了如下四个重载的构造方法来满足不同的使用场景:</p> -<ol> -<li>无参构造:<code>HashMap()</code>,使用该方法表示全部使用 HashMap 的默认配置参数</li> -<li>指定容量初始值构造:<code>HashMap(int initialCapacity)</code>,在初始化 HashMap 时指定其容量大小</li> -<li>指定容量初始值和扩容因子构造:<code>HashMap(int initialCapacity, float loadFactor)</code>,使用自定义初始化容量和扩容因子</li> -<li>通过 <code>Map</code> 来构造 HashMap:<code>HashMap(Map&lt;? extends K, ? extends V&gt; m)</code>,使用默认的扩容因子,其容量大小有传入的 <code>Map</code> 大小来决定 - - - - - - - - - - - -
- diff --git a/baidusitemap.xml b/baidusitemap.xml index 39879dab..e43dc6c9 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -1,6 +1,9 @@ + https://www.mghio.cn/post/4b00e13c.html + 2020-06-11 + https://www.mghio.cn/post/24042edf.html 2020-06-03 diff --git a/categories/JDK/Java/index.html b/categories/JDK/Java/index.html index 344d918d..8e9ca06f 100644 --- a/categories/JDK/Java/index.html +++ b/categories/JDK/Java/index.html @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 8e6ff92d..9c0953f0 100644 --- "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git a/categories/JDK/index.html b/categories/JDK/index.html index 2205b6f9..1e58561b 100644 --- a/categories/JDK/index.html +++ b/categories/JDK/index.html @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git a/categories/Java/Bloom-filter/index.html b/categories/Java/Bloom-filter/index.html index d427f94e..e763a853 100644 --- a/categories/Java/Bloom-filter/index.html +++ b/categories/Java/Bloom-filter/index.html @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git a/categories/Java/GC/index.html b/categories/Java/GC/index.html index 246725a9..0378d054 100644 --- a/categories/Java/GC/index.html +++ b/categories/Java/GC/index.html @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git a/categories/Java/Guava/String/index.html b/categories/Java/Guava/String/index.html index 143ef52b..055880ae 100644 --- a/categories/Java/Guava/String/index.html +++ b/categories/Java/Guava/String/index.html @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git a/categories/Java/Guava/index.html b/categories/Java/Guava/index.html index 21e9d2ef..367134ff 100644 --- a/categories/Java/Guava/index.html +++ b/categories/Java/Guava/index.html @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git a/categories/Java/IDEA/index.html b/categories/Java/IDEA/index.html index 24857ae9..d8d56203 100644 --- a/categories/Java/IDEA/index.html +++ b/categories/Java/IDEA/index.html @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" index c1b50bcb..6e1d65fd 100644 --- "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" +++ "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git "a/categories/Java/IO\346\250\241\345\236\213/index.html" "b/categories/Java/IO\346\250\241\345\236\213/index.html" index ff2fb69d..dec572ef 100644 --- "a/categories/Java/IO\346\250\241\345\236\213/index.html" +++ "b/categories/Java/IO\346\250\241\345\236\213/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git a/categories/Java/JVM/index.html b/categories/Java/JVM/index.html index ff57532e..8c8fc3f2 100644 --- a/categories/Java/JVM/index.html +++ b/categories/Java/JVM/index.html @@ -413,7 +413,7 @@

- 26 + 27 日志 @@ -424,7 +424,7 @@

diff --git a/categories/Java/index.html b/categories/Java/index.html index f4e1b3d8..1f6e1e4f 100644 --- a/categories/Java/index.html +++ b/categories/Java/index.html @@ -309,6 +309,32 @@

Java分类 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -625,7 +625,7 @@

- 26 + 27 日志 @@ -636,7 +636,7 @@

diff --git a/categories/Java/page/2/index.html b/categories/Java/page/2/index.html index b50d21c2..ee059eb3 100644 --- a/categories/Java/page/2/index.html +++ b/categories/Java/page/2/index.html @@ -309,6 +309,32 @@

Java分类 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -625,7 +625,7 @@

- 26 + 27 日志 @@ -636,7 +636,7 @@

diff --git a/categories/Java/page/3/index.html b/categories/Java/page/3/index.html index b760b308..dd3d4d3d 100644 --- a/categories/Java/page/3/index.html +++ b/categories/Java/page/3/index.html @@ -309,6 +309,32 @@

Java分类 + + + + + +
@@ -443,7 +469,7 @@

- 26 + 27 日志 @@ -454,7 +480,7 @@

diff --git a/categories/Java/unit-test/index.html b/categories/Java/unit-test/index.html index 1f968c52..a609360c 100644 --- a/categories/Java/unit-test/index.html +++ b/categories/Java/unit-test/index.html @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git a/categories/Java/unit-test/mockito/index.html b/categories/Java/unit-test/mockito/index.html index e247425b..691249bf 100644 --- a/categories/Java/unit-test/mockito/index.html +++ b/categories/Java/unit-test/mockito/index.html @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git "a/categories/Java/\345\216\237\347\220\206/index.html" "b/categories/Java/\345\216\237\347\220\206/index.html" index 21618a13..b875242c 100644 --- "a/categories/Java/\345\216\237\347\220\206/index.html" +++ "b/categories/Java/\345\216\237\347\220\206/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git "a/categories/Java/\345\217\215\345\260\204/index.html" "b/categories/Java/\345\217\215\345\260\204/index.html" index dd0c1f87..017fc399 100644 --- "a/categories/Java/\345\217\215\345\260\204/index.html" +++ "b/categories/Java/\345\217\215\345\260\204/index.html" @@ -413,7 +413,7 @@

- 26 + 27 日志 @@ -424,7 +424,7 @@

diff --git "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" index d3256283..07bd3d32 100644 --- "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" @@ -413,7 +413,7 @@

- 26 + 27 日志 @@ -424,7 +424,7 @@

diff --git "a/categories/Java/\345\271\266\345\217\221/index.html" "b/categories/Java/\345\271\266\345\217\221/index.html" index 10071e19..d363413f 100644 --- "a/categories/Java/\345\271\266\345\217\221/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/index.html" @@ -309,6 +309,32 @@

并发分类 + + + + + +
@@ -413,7 +439,7 @@

- 26 + 27 日志 @@ -424,7 +450,7 @@

diff --git "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" new file mode 100644 index 00000000..6a04d60b --- /dev/null +++ "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" @@ -0,0 +1,1250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: 进阶 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/Java/\345\274\202\346\255\245/index.html" "b/categories/Java/\345\274\202\346\255\245/index.html" index 64e23a79..b5342cdc 100644 --- "a/categories/Java/\345\274\202\346\255\245/index.html" +++ "b/categories/Java/\345\274\202\346\255\245/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" index 631d5f25..832184a8 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 26d0e9aa..25c2303c 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" index 627d4b60..69f68850 100644 --- "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" +++ "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" @@ -413,7 +413,7 @@

- 26 + 27 日志 @@ -424,7 +424,7 @@

diff --git "a/categories/Java/\351\207\215\346\236\204/index.html" "b/categories/Java/\351\207\215\346\236\204/index.html" index fb431a30..66739461 100644 --- "a/categories/Java/\351\207\215\346\236\204/index.html" +++ "b/categories/Java/\351\207\215\346\236\204/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git "a/categories/Linux\347\254\224\350\256\260/index.html" "b/categories/Linux\347\254\224\350\256\260/index.html" index 9f239446..566c9dd7 100644 --- "a/categories/Linux\347\254\224\350\256\260/index.html" +++ "b/categories/Linux\347\254\224\350\256\260/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git a/categories/index.html b/categories/index.html index 04f93d1e..2c039af9 100644 --- a/categories/index.html +++ b/categories/index.html @@ -317,10 +317,10 @@

@@ -378,7 +378,7 @@

- 26 + 27 日志 @@ -389,7 +389,7 @@

diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" index aa203fab..55549f43 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index d0ca818e..34630035 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -387,7 +387,7 @@

- 26 + 27 日志 @@ -398,7 +398,7 @@

diff --git a/css/main.css b/css/main.css index cda1b8de..e464fe90 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #a84deb; + background: #210620; } .links-of-blogroll { font-size: 13px; diff --git a/index.html b/index.html index 9914ec96..7dd6e9c6 100644 --- a/index.html +++ b/index.html @@ -310,7 +310,7 @@

Java 搬运工 & 终身学习
- +

@@ -467,10 +467,10 @@

-

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

+

前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

- + 阅读全文 »
@@ -523,7 +523,7 @@

前言 - +

@@ -680,10 +680,10 @@

-

前言

对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

+

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

- + 阅读全文 »
@@ -736,7 +736,7 @@

前言 - +

@@ -882,11 +893,10 @@

-

前言

在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

-

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

+

前言

对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

- + 阅读全文 »
@@ -939,7 +949,7 @@

- +

-

+

@@ -1085,14 +1095,11 @@

-

前言

在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

-

原理

布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

-
-

A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

-
+

前言

在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

+

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

- + 阅读全文 »
@@ -1145,7 +1152,7 @@

原理 - +

@@ -1302,15 +1298,14 @@

-

前言

Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

-

如何使用

Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

-
1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
- -

对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

-
1
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
+

前言

在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

+

原理

布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

+
+

A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

+
- + 阅读全文 »
@@ -1363,7 +1358,7 @@

- +

-

+

@@ -1509,11 +1515,15 @@

-

前言

在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

-

什么是 CompletableFuture

CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

+

前言

Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

+

如何使用

Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

+
1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
+ +

对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

+
1
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
- + 阅读全文 »
@@ -1566,7 +1576,7 @@

- +

-

+

@@ -1712,11 +1722,11 @@

-

前言

在日常生活中,当我们买的水果放久了之后会发出一种难闻的气味(“坏味道”),这个时候我们就应该把它扔掉。同样,代码也有“坏味道”,当然确定什么是和不是代码“坏味道”是主观的,它会随语言、开发人员和开发方法的不同而不同。在工作当中,很多时候都是在维护之前的项目和在此基础上增加一些新功能,为了能让项目代码易于理解和维护,要时刻注意代码中的“坏味道”,当发现代码如果有坏味道了,要及时去重构它使其变成优秀的整洁的代码。本文列举代码中一些常见的“坏味道”和相应的重构方案。

-

过长方法 (Long Method)

这种“坏味道”表现为方法代码行数过长,方法行数越长,就越难以理解和维护它。一个比较有用的方案就是当你觉得需要对方法中的内容加注释的时候,你应该将这个代码段作为一个新方法提取出来,哪怕有时候仅仅是一行代码也可以这么做,而且方法的命名要尽量做到见名知意,如果局部变量和参数干扰到方法的提取,则可以使用引入参数对象来进行提取。一般情况下,方法中条件运算符和循环是可以将代码移至单独方法的一个很好的代码段,对于条件运算符,可以尝试分解条件,如果方法出现循环,可以尝试提取方法。

+

前言

在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

+

什么是 CompletableFuture

CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

- + 阅读全文 »
@@ -1769,7 +1779,7 @@

- +

-

+

diff --git a/page/2/index.html b/page/2/index.html index 1b9434f6..10a234ca 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -310,7 +310,7 @@

Java 搬运工 & 终身学习
- +

@@ -456,14 +456,11 @@

-

前言

在互联网时代,我们的应用都是分布式系统,部署在 N 台机器上。说到分布式系统我们就不得不说分布式系统的祖先——集中式系统。它和分布式系统是两个完全相反的概念,集中式系统就是把所有的程序和功能都放到一台主机上,从而对外提供服务。集中式系统的优点就是容易理解、维护方便,它的的弊端也很明显,如果这个主机出故障了那么整个系统就崩溃了。著名投资家巴菲特有个关于投资的名言:

-
-

不要把鸡蛋放在一个篮子里

-
-

对于我们的系统而言也是如此,我们不可能保证主机永远不坏、也无法保证自己的程序永远不会出 bug,所以问题是无法避免的,我们只能把“鸡蛋”分散到不同的“篮子”里,降低系统出故障的风险,这就是我们为什么需要分布式系统的原因之一。使用分布式系统的另一个理由就是扩展性,毕竟单台主机都会有性能的极限,分布式系统可以通过增加主机数量来实现横向水平性能的扩展。接下来我们看看分布式系统中的一个基本定理——CAP定理

+

前言

做过 Java 开发的同学都知道,JVM(Java 虚拟机)Java 实现的基础,虽然在平时工作中真正运用到的时候可能并不多,但是一个程序员想要上升到高级层次,那就必须知道 Java 到底是怎么运行的,这就有必要去学习了解 JVM 的相关知识了。学习 JVM 可以能更深入的理解 Java 这门语言,可以清楚知道Java程序是如何执行的以及为未来排查线上问题打下坚实的基础。接下来我们看看 2020 年的 JVM 生态报告和最新趋势,值得我们每个 Java 开发者去关注了解。

+

JDK 厂商占比

Oracle JDKOpen JDK 加起来占比将近 60%,其中 Oracle JDK 占比略多一些,Oracle JDKOpen JDK 都是市场上的热门选择,我们看看二者之间的一些差异。Oracle JDK 更多的关注稳定性,更适合企业级用户,而 Open JDK 相对而言没有那么稳定,它会经常发布一些新特性。Oracle JDK 支持长期发布的更改,而 Open JDK 仅支持计划和完成下一个发行版,还有一个就是 Oracle JDK 是根据 二进制代码许可协议 获得许可,而 Open JDK 是根据 GPL v2 许可获得许可。使用 Oracle 平台时会产生一些许可影响。如 Oracle 宣布的那样,在没有商业许可的情况下,在 2019 年 1 月之后发布的 Oracle Java SE 8 的公开更新将无法用于商业,商业或生产用途。但是,Open JDK 是完全开源的,可以自由使用。

- + 阅读全文 »
@@ -516,7 +513,7 @@

前言 - +

@@ -673,11 +659,14 @@

-

前言

相信做 Java 开发的朋友们绝大部分人应该都是用 IntelliJ IDEA 作为开发工具,没用过的朋友们建议将你的开发工具换成这个,关于它的优点可以去 Google 一下,我之前都是用 Eclipse 作为开发工具,自从用过一次 IDEA 之后就再也回不去了。。。今天早上更新(作死)了一下 IDEA 到最新版(2019.3.1),安装完毕之后进入就提示说之前的激活码失效了,经过一顿搜索之后终于成功激活了,在此记录一下激活过程。

-

start_welcome.png

+

前言

在互联网时代,我们的应用都是分布式系统,部署在 N 台机器上。说到分布式系统我们就不得不说分布式系统的祖先——集中式系统。它和分布式系统是两个完全相反的概念,集中式系统就是把所有的程序和功能都放到一台主机上,从而对外提供服务。集中式系统的优点就是容易理解、维护方便,它的的弊端也很明显,如果这个主机出故障了那么整个系统就崩溃了。著名投资家巴菲特有个关于投资的名言:

+
+

不要把鸡蛋放在一个篮子里

+
+

对于我们的系统而言也是如此,我们不可能保证主机永远不坏、也无法保证自己的程序永远不会出 bug,所以问题是无法避免的,我们只能把“鸡蛋”分散到不同的“篮子”里,降低系统出故障的风险,这就是我们为什么需要分布式系统的原因之一。使用分布式系统的另一个理由就是扩展性,毕竟单台主机都会有性能的极限,分布式系统可以通过增加主机数量来实现横向水平性能的扩展。接下来我们看看分布式系统中的一个基本定理——CAP定理

- + 阅读全文 »
@@ -730,7 +719,7 @@

前言 - +

@@ -876,14 +876,11 @@

-

前言

在上篇 Java 反射机制(一) 介绍了一些 Java 反射相关的常用 API ,在知道了如何去使用反射之后,作为一个合格的工程师,下一步肯定是要去了解它的如何实现的,我们今天就来看看在 JDK 源码中是如何去实现反射的(PS:以下源码分析基于 JDK1.8)。

-

Field 类 set 方法的实现

Field 类的 set 方法是在运行时用来动态修改一个类的属性的值,进入到 Field 类的 set 方法的源码如下:

-
1
2
3
4
5
6
7
8
9
10
11
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
getFieldAccessor(obj).set(obj, value);
}
- -

首先根据 override 判断是否需要检查字段的访问权限,然后通过 getFieldAccessor 方法获得一个 FieldAccessor 字段访问者对象,最后调用的是 FieldAccessor 类的 set 方法进行下一步操作的,FieldAccessor 是一个接口,定义了对字段的一些操作,该接口有如下一些实现类:

+

前言

相信做 Java 开发的朋友们绝大部分人应该都是用 IntelliJ IDEA 作为开发工具,没用过的朋友们建议将你的开发工具换成这个,关于它的优点可以去 Google 一下,我之前都是用 Eclipse 作为开发工具,自从用过一次 IDEA 之后就再也回不去了。。。今天早上更新(作死)了一下 IDEA 到最新版(2019.3.1),安装完毕之后进入就提示说之前的激活码失效了,经过一顿搜索之后终于成功激活了,在此记录一下激活过程。

+

start_welcome.png

- + 阅读全文 »
@@ -936,7 +933,7 @@

- +

-

+

@@ -1082,11 +1079,14 @@

-

前言

Java 中有两种方式可以让我们在运行时识别对象和类的信息。一种是 RTTI(运行时类型识别:Run-Time Type Identification),它假定了我们在编译时已经知道了所有的类型;另一种是我们本文要说的反射机制,它允许我们在运行时获取和使用类的信息。无论是 RTTI 还是反射,其本质都是一样的,都是去动态的获取类的信息。它们唯一不同的是,RTTI 在编译时期知道要解析的类型,而反射是在运行时才知道要解析的类型。

-

反射概述

反射就是把 Java 类中的各个部分(属性、方法、构造方法等)映射成一个个对象。Class 类与 java.lang.reflect 类库一起对反射的概念提供了支持,类库中包含了 FieldMethodConstructor 类,每个类都实现了 Member 接口。这些类型的对象都是由 JVM 运行时创建的,用来表示未知类里对应的成员。这样我们就可以使用 Constructor 创建新的对象,用 getset 方法读取和修改类中与 Field 对象关联的字段,用 invoke 方法调用类中与 Method 对象关联的方法等。
Java 反射机制是在运行状态中的,对于任意一个类我们可以通过反射获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。重要的是,要认识到反射机制并没有什么特别之处,当我们通过反射和一个未知类型的对象打交道时,JVM 只是简单的对这个对象做检查,看它属于哪个类,在用它做其它事情之前必须先加载那个类 Class 对象。所以那个类的字节码文件对象对于 JVM 来说必须是可获取的,要么在本地机器上,要么通过网络获取。

+

前言

在上篇 Java 反射机制(一) 介绍了一些 Java 反射相关的常用 API ,在知道了如何去使用反射之后,作为一个合格的工程师,下一步肯定是要去了解它的如何实现的,我们今天就来看看在 JDK 源码中是如何去实现反射的(PS:以下源码分析基于 JDK1.8)。

+

Field 类 set 方法的实现

Field 类的 set 方法是在运行时用来动态修改一个类的属性的值,进入到 Field 类的 set 方法的源码如下:

+
1
2
3
4
5
6
7
8
9
10
11
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
getFieldAccessor(obj).set(obj, value);
}
+ +

首先根据 override 判断是否需要检查字段的访问权限,然后通过 getFieldAccessor 方法获得一个 FieldAccessor 字段访问者对象,最后调用的是 FieldAccessor 类的 set 方法进行下一步操作的,FieldAccessor 是一个接口,定义了对字段的一些操作,该接口有如下一些实现类:

- + 阅读全文 »
@@ -1139,7 +1139,7 @@

- +

-

+

@@ -1274,47 +1285,11 @@

-

1.1 前言

作为 Java 后端开发的我们,开发的项目绝大部分都是部署在 Linux 系统上的,因此熟练使用一些常用的 Linux 命令不管是对于日常开发、服务部署或者查找问题都非常有用。以下整理了一些常用的 Linux 常用命令。

-

1.2 文件管理

1.2.1 ls 命令

ls 命令是 Linux 最常用的命令之一,其功能是列出指定目录下的内容及其相关属性信息。默认状态下,ls 命令会列出当前目录的内容,它也可以带上一些参数来实现更多的功能。
语法格式:ls [选项] [文件]
常用参数

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
参数描述
-a显示所有文件及目录(包括以 . 开头的隐藏文件)
-l使用长格式列出文件及目录
-r将文件以相反次序显示(默认按照英文字母次序)
-t根据最后的修改时间排序
-A-a,但是不列出 .(当前目录)以及 ..(父级目录)
-S根据文件大小排序
-R递归列出所有子目录
+

前言

Java 中有两种方式可以让我们在运行时识别对象和类的信息。一种是 RTTI(运行时类型识别:Run-Time Type Identification),它假定了我们在编译时已经知道了所有的类型;另一种是我们本文要说的反射机制,它允许我们在运行时获取和使用类的信息。无论是 RTTI 还是反射,其本质都是一样的,都是去动态的获取类的信息。它们唯一不同的是,RTTI 在编译时期知道要解析的类型,而反射是在运行时才知道要解析的类型。

+

反射概述

反射就是把 Java 类中的各个部分(属性、方法、构造方法等)映射成一个个对象。Class 类与 java.lang.reflect 类库一起对反射的概念提供了支持,类库中包含了 FieldMethodConstructor 类,每个类都实现了 Member 接口。这些类型的对象都是由 JVM 运行时创建的,用来表示未知类里对应的成员。这样我们就可以使用 Constructor 创建新的对象,用 getset 方法读取和修改类中与 Field 对象关联的字段,用 invoke 方法调用类中与 Method 对象关联的方法等。
Java 反射机制是在运行状态中的,对于任意一个类我们可以通过反射获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。重要的是,要认识到反射机制并没有什么特别之处,当我们通过反射和一个未知类型的对象打交道时,JVM 只是简单的对这个对象做检查,看它属于哪个类,在用它做其它事情之前必须先加载那个类 Class 对象。所以那个类的字节码文件对象对于 JVM 来说必须是可获取的,要么在本地机器上,要么通过网络获取。

- + 阅读全文 »
@@ -1367,7 +1342,7 @@

- +

-

+

@@ -1513,11 +1477,47 @@

-

简介

在上篇 Java 多线程基础(一) 我们提到了一些线程的常用方法,这篇我们具体看看其中一些方法的使用以及方法的区别,让我们在工作中更好的使用。

-

wait 方法与 notify 方法

Object 类中定义了 wait 方法和 notify 方法,wait 方法的作用是让当前线程进入等待状态,将当前线程置入 预执行队列,会在 wait 方法所在代码处停止执行,直到被通知或者被中断,在调用 wait 方法之前,线程必须获取该对象的锁,因此只能在同步方法或者同步代码块中调用 wait 方法,并且该方法会释放当前线程锁持有的锁。notify 方法是唤醒在当前对象上等待的单个线程,如果有多个线程等待,那么线程调度器会挑出一个 wait 的线程,对其发出 notify ,并使它等待获取该对象的对象锁,这意味着,即使收到了通知,线程也不会立即获取到对象锁,必须等待 notify 方法的线程释放锁才可以。和 wait 方法一样,notify 方法也只能在同步方法或者同步代码块中调用。它还有个相似的方法 notifyAll,它的作用是唤醒在当前对象上等待的所有线程

+

1.1 前言

作为 Java 后端开发的我们,开发的项目绝大部分都是部署在 Linux 系统上的,因此熟练使用一些常用的 Linux 命令不管是对于日常开发、服务部署或者查找问题都非常有用。以下整理了一些常用的 Linux 常用命令。

+

1.2 文件管理

1.2.1 ls 命令

ls 命令是 Linux 最常用的命令之一,其功能是列出指定目录下的内容及其相关属性信息。默认状态下,ls 命令会列出当前目录的内容,它也可以带上一些参数来实现更多的功能。
语法格式:ls [选项] [文件]
常用参数

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数描述
-a显示所有文件及目录(包括以 . 开头的隐藏文件)
-l使用长格式列出文件及目录
-r将文件以相反次序显示(默认按照英文字母次序)
-t根据最后的修改时间排序
-A-a,但是不列出 .(当前目录)以及 ..(父级目录)
-S根据文件大小排序
-R递归列出所有子目录
- + 阅读全文 »
@@ -1570,7 +1570,7 @@

- +

-

+

@@ -1716,12 +1716,11 @@

-

简介

在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

-

进程与线程的区别

进程

进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

-
线程

线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

+

简介

在上篇 Java 多线程基础(一) 我们提到了一些线程的常用方法,这篇我们具体看看其中一些方法的使用以及方法的区别,让我们在工作中更好的使用。

+

wait 方法与 notify 方法

Object 类中定义了 wait 方法和 notify 方法,wait 方法的作用是让当前线程进入等待状态,将当前线程置入 预执行队列,会在 wait 方法所在代码处停止执行,直到被通知或者被中断,在调用 wait 方法之前,线程必须获取该对象的锁,因此只能在同步方法或者同步代码块中调用 wait 方法,并且该方法会释放当前线程锁持有的锁。notify 方法是唤醒在当前对象上等待的单个线程,如果有多个线程等待,那么线程调度器会挑出一个 wait 的线程,对其发出 notify ,并使它等待获取该对象的对象锁,这意味着,即使收到了通知,线程也不会立即获取到对象锁,必须等待 notify 方法的线程释放锁才可以。和 wait 方法一样,notify 方法也只能在同步方法或者同步代码块中调用。它还有个相似的方法 notifyAll,它的作用是唤醒在当前对象上等待的所有线程

- + 阅读全文 »
@@ -1774,7 +1773,7 @@
线程 - +
@@ -1920,12 +1919,12 @@

-

简介

在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

-

线程池如何处理提交的任务

我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
+

简介

在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

+

进程与线程的区别

进程

进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

+
线程

线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

- + 阅读全文 »
@@ -1978,7 +1977,7 @@

- +

-

+

@@ -2124,17 +2123,12 @@

-

线程池简介

使用线程池可以很好的提高性能,线程池在运行之初就会创建一定数量的空闲线程,我们将一个任务提交给线程池,线程池就会使用一个空闲的线程来执行这个任务,该任务执行完后,该线程不会死亡,而是再次变成空闲状态返回线程池,等待下一个任务的到来。在使用线程池时,我们把要执行的任务提交给整个线程池,而不是提交给某个线程,线程池拿到提交的任务后,会在内部寻找是否还有空闲的线程,如果有,就将这个任务提交给某个空闲的线程,虽然一个线程同一时刻只能执行一个任务,但是我们可以向线程池提交多个任务。合理使用线程池有以下几个优点:
降低资源消耗 多线程运行期间,系统不断的启动和关闭新线程,成本高,会过度消耗系统资源,通过重用存在的线程,减少对象创建、消亡的开销
提高响应速度 当有任务到达时,任务可以不需要等待线程的创建,可以直接从线程池中取出空闲的线程来执行任务
方便线程管理 线程对计算机来说是很稀缺的资源,如果让他无限制创建,它不仅消耗系统的资源,还会降低系统的稳定性,我们使用线程池后可以统一进行分配和监控
谈到线程池就会想到池化技术,核心思想就是把宝贵的资源放到一个池子中,每次要使用都从池子里面取,用完之后又放回池子让别人用。那么线程池在 Java 中是如何实现的呢?

-

Java 四种线程池

在 Java 中 Executors 工具类给我们提供了四种不同使用场景的线程池的创建方法,分别为:

-
    -
  1. newSingleThreadExecutor 只有一个线程来执行任务,适用于有顺序的任务的应用场景。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,它可以保证任务按照指定顺序(FIFO,LIFO)执行,它还有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为
  2. -
  3. newFixedThreadPool 固定线程数的线程池,只有核心线程,核心线程的即为最大的线程数量,没有非核心线程。每次提交一个任务就创建一个线程,直到达到线程池的最大大小。线程池一旦达到最大值就会保持不变,如果当中的某个线程因为异常而结束,那么线程池会新建一个线程加入到线程池中。它还可以控制线程的最大并发数,超出的线程会在阻塞队列(LinkedBlockingQueue)中等待,同样它也有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为。
  4. -
  5. newCachedThreadPool 创建一个可缓存线程池,最大的线程个数为 2^31 - 1(Integer.MAX_VALUE),可以认为是无限大,若无可回收,则新建线程,如果线程池的大小超出了处理任务所需要的线程,那么就会回收部分空闲(60s 不执行任务)的线程。
  6. -
  7. newScheduledThreadPool 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大(Integer.MAX_VALUE:2^31 - 1),适用于执行周期性的任务。
  8. -
+

简介

在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

+

线程池如何处理提交的任务

我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
- + 阅读全文 »
@@ -2187,7 +2181,7 @@

- +

-

+

@@ -2333,23 +2327,24 @@

-

1.1 前言

做过 java 开发的朋友们相信都很熟悉 HashMap 这个类,它是一个基于 hashing 原理用于存储 Key-Value 键值对的集合,其中的每一个键也叫做 Entry,这些键分别存储在一个数组当中,系统会根据 hash 方法来计算出 Key-Value 的存储位置,可以通过 key 快速存取 value。
HashMap 基于 hashing 原理,当我们将一个键值对(Key-Value) 传入 put 方法时,它将调用这个 key 的 hashcode 方法计算出 key 的 hashcode 值,然后根据这个 hashcode 值来定位其存放数组的位置来存储对象(HashMap 使用链表来解决碰撞问题,当其发生碰撞了,对象将会存储在链表的下一个节点中,在链表的每个节点中存储 Entry 对象,在 JDK 1.8+ 中,当链表的节点个数超过一定值时会转为红黑树来进行存储),当通过 get 方法传入一个 key 来获取其对应的值时,也是先通过 key 的 hashcode 方法来定位其存储在数组的位置,然后通过键对象的 eqauls 方法找到对应的 value 值。接下来让我们看看其内部的一些实现细节。(PS:以下代码分析都是基于 JDK 1.8

-

1.2 为什么容量始终是 2 的整数次幂

因为获取 key 在数组中对应的下标是通过 key 的哈希值与数组的长度减一进行与运算来确定的(tab[(n - 1) & hash])。当数组的长度 n 为 2 的整数次幂,这样进行 n - 1 运算后,之前为 1 的位后面全是 1 ,这样就能保证 (n - 1) & hash 后相应位的值既可能是 1 又可能是 0 ,这完全取决于 key 的哈希值,这样就能保证散列的均匀,同时与运算(位运算)效率高。如果数组的长度 n 不是 2 的整数次幂,会造成更多的 hash 冲突。HashMap 提供了如下四个重载的构造方法来满足不同的使用场景:

+

线程池简介

使用线程池可以很好的提高性能,线程池在运行之初就会创建一定数量的空闲线程,我们将一个任务提交给线程池,线程池就会使用一个空闲的线程来执行这个任务,该任务执行完后,该线程不会死亡,而是再次变成空闲状态返回线程池,等待下一个任务的到来。在使用线程池时,我们把要执行的任务提交给整个线程池,而不是提交给某个线程,线程池拿到提交的任务后,会在内部寻找是否还有空闲的线程,如果有,就将这个任务提交给某个空闲的线程,虽然一个线程同一时刻只能执行一个任务,但是我们可以向线程池提交多个任务。合理使用线程池有以下几个优点:
降低资源消耗 多线程运行期间,系统不断的启动和关闭新线程,成本高,会过度消耗系统资源,通过重用存在的线程,减少对象创建、消亡的开销
提高响应速度 当有任务到达时,任务可以不需要等待线程的创建,可以直接从线程池中取出空闲的线程来执行任务
方便线程管理 线程对计算机来说是很稀缺的资源,如果让他无限制创建,它不仅消耗系统的资源,还会降低系统的稳定性,我们使用线程池后可以统一进行分配和监控
谈到线程池就会想到池化技术,核心思想就是把宝贵的资源放到一个池子中,每次要使用都从池子里面取,用完之后又放回池子让别人用。那么线程池在 Java 中是如何实现的呢?

+

Java 四种线程池

在 Java 中 Executors 工具类给我们提供了四种不同使用场景的线程池的创建方法,分别为:

    -
  1. 无参构造:HashMap(),使用该方法表示全部使用 HashMap 的默认配置参数
  2. -
  3. 指定容量初始值构造:HashMap(int initialCapacity),在初始化 HashMap 时指定其容量大小
  4. -
  5. 指定容量初始值和扩容因子构造:HashMap(int initialCapacity, float loadFactor),使用自定义初始化容量和扩容因子
  6. -
  7. 通过 Map 来构造 HashMap:HashMap(Map<? extends K, ? extends V> m),使用默认的扩容因子,其容量大小有传入的 Map 大小来决定 +
  8. newSingleThreadExecutor 只有一个线程来执行任务,适用于有顺序的任务的应用场景。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,它可以保证任务按照指定顺序(FIFO,LIFO)执行,它还有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为
  9. +
  10. newFixedThreadPool 固定线程数的线程池,只有核心线程,核心线程的即为最大的线程数量,没有非核心线程。每次提交一个任务就创建一个线程,直到达到线程池的最大大小。线程池一旦达到最大值就会保持不变,如果当中的某个线程因为异常而结束,那么线程池会新建一个线程加入到线程池中。它还可以控制线程的最大并发数,超出的线程会在阻塞队列(LinkedBlockingQueue)中等待,同样它也有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为。
  11. +
  12. newCachedThreadPool 创建一个可缓存线程池,最大的线程个数为 2^31 - 1(Integer.MAX_VALUE),可以认为是无限大,若无可回收,则新建线程,如果线程池的大小超出了处理任务所需要的线程,那么就会回收部分空闲(60s 不执行任务)的线程。
  13. +
  14. newScheduledThreadPool 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大(Integer.MAX_VALUE:2^31 - 1),适用于执行周期性的任务。
  15. +
- + 阅读全文 »
- + @@ -2434,7 +2429,7 @@

- 26 + 27 日志 @@ -2445,7 +2440,7 @@

- 26 + 27 分类 diff --git a/page/3/index.html b/page/3/index.html index a6093a1c..1c53f72d 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -305,6 +305,214 @@

Java 搬运工 & 终身学习 +
+ + + +
+ + + + + + + +
+ + + +

+ +

+ + + +
+ + + + + +
+ + + + + + +

1.1 前言

做过 java 开发的朋友们相信都很熟悉 HashMap 这个类,它是一个基于 hashing 原理用于存储 Key-Value 键值对的集合,其中的每一个键也叫做 Entry,这些键分别存储在一个数组当中,系统会根据 hash 方法来计算出 Key-Value 的存储位置,可以通过 key 快速存取 value。
HashMap 基于 hashing 原理,当我们将一个键值对(Key-Value) 传入 put 方法时,它将调用这个 key 的 hashcode 方法计算出 key 的 hashcode 值,然后根据这个 hashcode 值来定位其存放数组的位置来存储对象(HashMap 使用链表来解决碰撞问题,当其发生碰撞了,对象将会存储在链表的下一个节点中,在链表的每个节点中存储 Entry 对象,在 JDK 1.8+ 中,当链表的节点个数超过一定值时会转为红黑树来进行存储),当通过 get 方法传入一个 key 来获取其对应的值时,也是先通过 key 的 hashcode 方法来定位其存储在数组的位置,然后通过键对象的 eqauls 方法找到对应的 value 值。接下来让我们看看其内部的一些实现细节。(PS:以下代码分析都是基于 JDK 1.8

+

1.2 为什么容量始终是 2 的整数次幂

因为获取 key 在数组中对应的下标是通过 key 的哈希值与数组的长度减一进行与运算来确定的(tab[(n - 1) & hash])。当数组的长度 n 为 2 的整数次幂,这样进行 n - 1 运算后,之前为 1 的位后面全是 1 ,这样就能保证 (n - 1) & hash 后相应位的值既可能是 1 又可能是 0 ,这完全取决于 key 的哈希值,这样就能保证散列的均匀,同时与运算(位运算)效率高。如果数组的长度 n 不是 2 的整数次幂,会造成更多的 hash 冲突。HashMap 提供了如下四个重载的构造方法来满足不同的使用场景:

+
    +
  1. 无参构造:HashMap(),使用该方法表示全部使用 HashMap 的默认配置参数
  2. +
  3. 指定容量初始值构造:HashMap(int initialCapacity),在初始化 HashMap 时指定其容量大小
  4. +
  5. 指定容量初始值和扩容因子构造:HashMap(int initialCapacity, float loadFactor),使用自定义初始化容量和扩容因子
  6. +
  7. 通过 Map 来构造 HashMap:HashMap(Map<? extends K, ? extends V> m),使用默认的扩容因子,其容量大小有传入的 Map 大小来决定 + +
    + + 阅读全文 » + +
    + + + +
+ + + + + + + + + + + + +
+ + + + + + + + +
+ +
+
+ + + +
+ + + + + + + + + + +
@@ -1568,7 +1776,7 @@

- 26 + 27 日志 @@ -1579,7 +1787,7 @@

diff --git a/post/102cd3d9.html b/post/102cd3d9.html index 64a89684..272c5e4b 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -847,7 +847,7 @@

总结 - 26 + 27 日志 @@ -858,7 +858,7 @@

总结 - 26 + 27 分类 diff --git a/post/11cb7677.html b/post/11cb7677.html index 59551ae8..b9f13aa9 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -698,7 +698,7 @@

总结 - 26 + 27 日志 @@ -709,7 +709,7 @@

总结 - 26 + 27 分类 diff --git a/post/192cb539.html b/post/192cb539.html index 20a4153f..40c57607 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -762,7 +762,7 @@

- 26 + 27 日志 @@ -773,7 +773,7 @@

diff --git a/post/24042edf.html b/post/24042edf.html index ec6b0d3d..d033a396 100644 --- a/post/24042edf.html +++ b/post/24042edf.html @@ -679,6 +679,10 @@

总结 + + @@ -766,7 +770,7 @@

总结 - 26 + 27 日志 @@ -777,7 +781,7 @@

总结 - 26 + 27 分类 diff --git a/post/34755d6c.html b/post/34755d6c.html index a3d16842..0338c358 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -677,7 +677,7 @@

总结 - 26 + 27 日志 @@ -688,7 +688,7 @@

总结 - 26 + 27 分类 diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index 014875ef..caeced70 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -744,7 +744,7 @@

总结 - 26 + 27 日志 @@ -755,7 +755,7 @@

总结 - 26 + 27 分类 diff --git a/post/4615256d.html b/post/4615256d.html index a27163fb..db48e21b 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -753,7 +753,7 @@

- 26 + 27 日志 @@ -764,7 +764,7 @@

- 26 + 27 分类 diff --git a/post/4b00e13c.html b/post/4b00e13c.html new file mode 100644 index 00000000..0362e47f --- /dev/null +++ b/post/4b00e13c.html @@ -0,0 +1,1743 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Java 中队列同步器 AQS(AbstractQueuedSynchronizer)实现原理 | mghio + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

Java 中队列同步器 AQS(AbstractQueuedSynchronizer)实现原理

+ + + +
+ + + + + +
+ + + + + +

前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

+ + +

AQS 基础数据结构

同步队列

队列同步器 AQS(下文简称为同步器)主要是依赖于内部的一个 FIFO(first-in-first-out)双向队列来对同步状态进行管理的,当线程获取同步状态失败时,同步器会将当前线程和当前等待状态等信息封装成一个内部定义的节点 Node,然后将其加入队列,同时阻塞当前线程;当同步状态释放时,会将同步队列中首节点唤醒,让其再次尝试去获取同步状态。同步队列的基本结构如下:

+

AQS_QUEUE.png

+
队列节点 Node

同步队列使用同步器中的静态内部类 Node 用来保存获取同步状态的线程的引用、线程的等待状态、前驱节点和后继节点。

+

AQS_inner_class_node.png

+

同步队列中 Node 节点的属性名称和具体含义如下表所示:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
属性类型和名称描述
volatile int waitStatus当前节点在队列中的等待状态
volatile Node prev前驱节点,当节点加入同步队列时被赋值(使用尾部添加方式)
volatile Node next后继节点
volatile Thread thread获取同步状态的线程
Node nextWaiter等待队列中的后继节点,如果当前节点是共享的,则该字段是一个 SHARED 常量
+

每个节点线程都有两种锁模式,分别为 SHARED 表示线程以共享的模式等待锁,EXCLUSIVE 表示线程以独占的方式等待锁。同时每个节点的等待状态 waitStatus 只能取以下表中的枚举值:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
枚举值描述
SIGNAL值为 -1,表示该节点的线程已经准备完毕,等待资源释放
CANCELLED值为 1,表示该节点线程获取锁的请求已经取消了
CONDITION值为 -2,表示该节点线程等待在 Condition 上,等待被其它线程唤醒
PROPAGATE值为 -3,表示下一次共享同步状态获取会无限进行下去,只在 SHARED 情况下使用
0值为 0,初始状态,初始化的默认值
+
同步状态 state

同步器内部使用了一个名为 stateint 类型的变量表示同步状态,同步器的主要使用方式是通过继承,子类通过继承并实现它的抽象方法来管理同步状态,同步器给我们提供了如下三个方法来对同步状态进行更改。

+ + + + + + + + + + + + + + + + + + + +
方法签名描述
protected final int getState()获取当前同步状态
protected final void setState(int newState)设置当前同步状态
protected final boolean compareAndSetState(int expect, int update)使用 CAS 设置当前状态,该方法能够保证状态设置的原子性
+

在独享锁中同步状态 state 这个值通常是 0 或者 1(如果是重入锁的话 state 值就是重入的次数),在共享锁中 state 就是持有锁的数量。

+

独占式同步状态获取与释放

同步器中提供了 acquire(int arg) 方法来进行独占式同步状态的获取,获取到了同步状态也就是获取到了锁,该方法源码如下所示:

+
1
2
3
4
5
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
+ +

方法首先会调用 tryAcquire 方法尝试去获取锁,查看方法的源码可以发现,同步器并未对该方法进行实现(只是抛出一个不支持操作异常 UnsupportedOperationException),这个方法是需要后续同步组件的开发人员自己去实现的,如果方法返回 true 则表示当前线程成功获取到锁,调用 selfInterrupt() 中断当前线程(PS:这里留给大家一个问题:为什么获取了锁以后还要中断线程呢?),方法结束返回,如果方法返回 false 则表示当前线程获取锁失败,也就是说有其它线程先前已经获取到了锁,此时就需要把当前线程以及等待状态等信息添加到同步队列中,下面来看看同步器在线程未获取到锁时具体是如何实现。
通过源码发现,当获取锁失败时,会执行判断条件与操作的后半部分 acquireQueued(addWaiter(Node.EXCLUSIVE), arg),首先指定锁模式为 Node.EXCLUSIVE 调用 addWaiter 方法,该方法源码如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
+ +

通过方法参数指定的锁模式(共享锁 or 独占锁)和当前线程构造出一个 Node 节点,如果同步队列已经初始化,那么首先会进行一次从尾部加入队列的尝试,使用 compareAndSetTail 方法保证原子性,进入该方法源码可以发现是基于 sun.misc 包下提供的 Unsafe 类来实现的。如果首次尝试加入同步队列失败,会再次调用 enq 方法进行入队操作,继续跟进 enq 方法源码如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
+ +

通过其源码可以发现和第一次尝试加入队列的代码类似,只是该方法里面加了同步队列初始化判断,使用 compareAndSetHead 方法保证设置头节点的原子性,同样它底层也是基于 Unsafe 类,然后外层套了一个 for (;;) 死循环,循环唯一的退出条件是从队尾入队成功,也就是说如果从该方法成功返回了就表示已经入队成功了,至此,addWaiter 执行完毕返回当前 Node 节点。然后以该节点作为 acquireQueued 方法的入参继续进行其它步骤,该方法如下所示:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
+ +

可以看到,该方法本质上也是通过一个死循环(自旋)去获取锁并且支持中断,在循环体外面定义两个标记变量,failed 标记是否成功获取到锁,interrupted 标记在等待的过程中是否被中断过。方法首先通过 predecessor 获取当前节点的前驱节点,当当前节点的前驱节点是 head 头节点时就调用 tryAcquire 尝试获取锁,也就是第二个节点则尝试获取锁,这里为什么要从第二个节点才尝试获取锁呢?是因为同步队列本质上是一个双向链表,在双向链表中,第一个节点并不存储任何数据是虚节点,只是起到一个占位的作用,真正存储数据的节点是从第二个节点开始的。如果成功获取锁,也就是 tryAcquire 方法返回 true 后,将 head 指向当前节点并把之前找到的头节点 p 从队列中移除,修改是否成功获取到锁标记,结束方法返回中断标记。
如果当前节点的前驱节点 p 不是头节点或者前驱节点 p 是头节点但是获取锁操作失败,那么会调用 shouldParkAfterFailedAcquire 方法判断当前 node 节点是否需要被阻塞,这里的阻塞判断主要是为了防止长时间自旋给 CPU 带来非常大的执行开销,浪费资源。该方法源码如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
+ +

方法参数为当前节点的前驱节点以及当前节点,主要是靠前驱节点来判断是否需要进行阻塞,首先获取到前驱节点的等待状态 ws,如果节点状态 wsSIGNAL,表示前驱节点的线程已经准备完毕,等待资源释放,方法返回 true 表示可以阻塞,如果 ws > 0,通过上文可以知道节点只有一个状态 CANCELLED(值为 1) 满足该条件,表示该节点线程获取锁的请求已经取消了,会通过一个 do-while 循环向前查找 CANCELLED 状态的节点并将其从同步队列中移除,否则进入 else 分支,使用 compareAndSetWaitStatus 原子操作将前驱节点的等待状态修改为 SIGNAL,以上这两种情况都不需要进行阻塞方法返回 false
当经过判断后需要阻塞的话,也就是 compareAndSetWaitStatus 方法返回 true 时,会通过 parkAndCheckInterrupt 方法阻塞挂起当前线程,并返回当前线程的中断标识。方法如下:

+
1
2
3
4
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
+ +

线程阻塞是通过 LockSupport 这个工具类实现的,深入其源码可以发现它底层也是基于 Unsafe 类实现的。如果以上两个方法都返回 true 的话就更新中断标记。这里还有一个问题就是什么时候会将一个节点的等待状态 waitStatus 修改为 CANCELLED 节点线程获取锁的请求取消状态呢?细心的朋友可能已经发现了,在上文贴出的 acquireQueued 方法源码中的 finally 块中会根据 failed 标记来决定是否调用 cancelAcquire 方法,这个方法就是用来将节点状态修改为 CANCELLED 的,方法的具体实现留给大家去探索。至此 AQS 独占式同步状态获取锁的流程就完成了,下面通过一个流程图来看看整体流程:

+

AQS_acquire.png

+
+

下面再看看独占式锁释放的过程,同步器使用 release 方法来让我们进行独占式锁的释放,其方法源码如下:

+
1
2
3
4
5
6
7
8
9
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
+ +

首先调用 tryRelease 方法尝试进行锁释放操作,继续跟进该方法发现同步器只是抛出了一个不支持操作异常 UnsupportedOperationException,这里和上文独占锁获取中 tryAcquire 方法是一样的套路,需要开发者自己定义锁释放操作。

+

AQS_tryrelease.png

+

通过其 JavaDoc 可以得知,如果返回 false,则表示释放锁失败,方法结束。该方法如果返回 true,则表示当前线程释放锁成功,需要通知队列中等待获取锁的线程进行锁获取操作。首先获取头节点 head,如果当前头节点不为 null,并且其等待状态不是初始状态(0),则解除线程阻塞挂起状态,通过 unparkSuccessor 方法实现,该方法源码如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);

/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
+ +

首先获取头节点的等待状态 ws,如果状态值为负数(Node.SIGNAL or Node.PROPAGATE),则通过 CAS 操作将其改为初始状态(0),然后获取头节点的后继节点,如果后继节点为 null 或者后继节点状态为 CANCELLED(获取锁请求已取消),就从队列尾部开始寻找第一个状态为非 CANCELLED 的节点,如果该节点不为空则使用 LockSupportunpark 方法将其唤醒,该方法底层是通过 Unsafe 类的 unpark 实现的。这里需要从队尾查找非 CANCELLED 状态的节点的原因是,在之前的获取独占锁失败时的入队 addWaiter 方法实现中,该方法如下:

+

AQS_unparkSuccessor.png

+

假设一个线程执行到了上图中的 ① 处,② 处还没有执行,此时另一个线程恰好执行了 unparkSuccessor 方法,那么就无法通过从前向后查找了,因为节点的后继指针 next 还没赋值呢,所以需要从后往前进行查找。至此,独占式锁释放操作就结束了,同样的,最后我们也通过一个流程图来看看整个锁释放的过程:

+

AQS_release.png

+

独占式可中断同步状态获取

同步器提供了 acquireInterruptibly 方法来进行可响应中断的获取锁操作,方法实现源码如下:

+
1
2
3
4
5
6
7
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
+ +

方法首先检查当前线程的中断状态,如果已中断,则直接抛出中断异常 InterruptedException 即响应中断,否则调用 tryAcquire 方法尝试获取锁,如果获取成功则方法结束返回,获取失败调用 doAcquireInterruptibly 方法,跟进该方法如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
+ +

仔细观察可以发现该方法实现源码和上文中 acquireQueued 方法的实现基本上类似,只是这里把入队操作 addWaiter 放到了方法里面了,还有一个区别就是当在循环体内判断需要进行中断时会直接抛出异常来响应中断,两个方法的对比如下:

+

AQS_acquirequeued_interruptibly_compare.png

+

其它步骤和独占式锁获取一致,流程图大体上和不响应中断的锁获取差不多,只是在最开始多了一步线程中断状态检查和循环是会抛出中断异常而已。

+

独占式超时获取同步状态

同步器提供了 tryAcquireNanos 方法可以超时获取同步状态(也就是),该方法提供了之前 synchronized 关键字不支持的超时获取的特性,通过该方法我们可以在指定时间段 nanosTimeout 内获取锁,如果获取到锁则返回 true,否则,返回 false。方法源码如下:

+
1
2
3
4
5
6
7
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
+ +

首先会调用 tryAcquire 方法尝试获取一次锁,如果获取锁成功则立即返回,否则调用 doAcquireNanos 方法进入超时获取锁流程。通过上文可以得知,同步器的 acquireInterruptibly 方法在等待获取同步状态时,如果当前线程被中断了,会抛出中断异常 InterruptedException 并立刻返回。超时获取锁的流程其实是在响应中断的基础上增加了超时获取的特性,doAcquireNanos 方法的源码如下:

+
1
2
3
4
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
30
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
+ +

由以上方法实现源码可以看出,针对超时获取这里主要实现思路是:先使用当前时间加上参数传入的超时时间间隔 deadline 计算出超时的时间点,然后每次进行循环的时候使用超时时间点 deadline 减去当前时间得到剩余的时间 nanosTimeout,如果剩余时间小于 0 则证明当前获取锁操作已经超时,方法结束返回 false,反如果剩余时间大于 0。
可以看到在里面执行自旋的时候和上面独占式同步获取锁状态 acquireQueued 方法那里是一样的套路,即当当前节点的前驱节点为头节点时调用 tryAcquire 尝试获取锁,如果获取成功则返回。

+

AQS_acquireQueued_doAcquireNanos_compare.png

+

除了超时时间计算那里不同外,还有个不同的地方就是在超时获取锁失败之后的操作,如果当前线程获取锁失败,则判断剩余超时时间 nanosTimeout 是否小于 0,如果小于 0 则表示已经超时方法立即返回,反之则会判断是否需要进行阻塞挂起当前线程,如果通过 shouldParkAfterFailedAcquire 方法判断需要挂起阻塞当前线程,还要进一步比较超时剩余时间 nanosTimeoutspinForTimeoutThreshold 的大小,如果小于等于 spinForTimeoutThreshold 值(1000 纳秒)的话,将不会使当前线程进行超时等待,而是再次进行自旋过程。
加后面这个判断的主要原因在于,在非常短(小于 1000 纳秒)的时间内的等待无法做到十分精确,如果这时还进行超时等待的话,反而会让我们指定 nanosTimeout 的超时从整体上给人感觉反而不太精确,因此,在剩余超时时间非常短的情况下,同步器会再次自旋进行超时获取锁的过程,独占式超时获取锁整个过程如下所示:

+

AQS_tryAcquireNanos_flow.png

+

共享式同步状态获取与释放

共享锁顾名思义就是可以多个线程共用一个锁,在同步器中使用 acquireShared 来获取共享锁(同步状态),方法源码如下:

+
1
2
3
4
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
+ +

首先通过 tryAcquireShared 尝试获取共享锁,该方法是一个模板方法在同步器中只是抛出一个不支持操作异常,需要开发人员自己去实现,同时方法的返回值有三种不同的类型分别代表三种不同的状态,其含义如下:

+
    +
  1. 小于 0 表示当前线程获取锁失败
  2. +
  3. 等于 0 表示当前线程获取锁成功,但是之后的线程在没有锁释放的情况下获取锁将失败,也就是说这个锁是共享模式下的最后一把锁了
  4. +
  5. 大于 0 表示当前线程获取锁成功,并且还有剩余的锁可以获取
  6. +
+

当方法 tryAcquireShared 返回值小于 0 时,也就是获取锁失败,将会执行方法 doAcquireShared,继续跟进该方法:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
+ +

方法首先调用 addWaiter 方法封装当前线程和等待状态为共享模块的节点并将其添加到等待同步队列中,可以发现在共享模式下节点的 nextWaiter 属性是固定值 Node.SHARED。然后循环获取当前节点的前驱节点,如果前驱节点是头节点的话就尝试获取共享锁,如果返回值大于等于 0 表示获取共享锁成功,则调用 setHeadAndPropagate 方法,更新头节点同时如果有可用资源,则向后传播,唤醒后继节点,接下来会检查一下中断标识,如果已经中断则中断当前线程,方法结束返回。如果返回值小于 0,则表示获取锁失败,需要挂起阻塞当前线程或者继续自旋获取共享锁。下面看看 setHeadAndPropagate 方法的具体实现:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
setHead(node);
/*
* Try to signal next queued node if:
* Propagation was indicated by caller,
* or was recorded (as h.waitStatus either before
* or after setHead) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
+ +

首先将当前获取到锁的节点设置为头节点,然后方法参数 propagate > 0 时表示之前 tryAcquireShared 方法的返回值大于 0,也就是说当前还有剩余的共享锁可以获取,则获取当前节点的后继节点并且后继节点是共享节点时唤醒节点去尝试获取锁,doReleaseShared 方法是同步器共享锁释放的主要逻辑。

+
+

同步器提供了 releaseShared 方法来进行共享锁的释放,方法源码如下所示:

+
1
2
3
4
5
6
7
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
+ +

首先调用 tryReleaseShared 方法尝试释放共享锁,方法返回 false 代表锁释放失败,方法结束返回 false,否则就表示成功释放锁,然后执行 doReleaseShared 方法,进行唤醒后继节点并检查它是否可以向后传播等操作。继续跟进该方法如下:

+
1
2
3
4
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
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
+ +

可以看到和独占式锁释放不同的是,在共享模式下,状态同步和释放可以同时执行,其原子性由 CAS 来保证,如果头节点改变了也会继续循环。每次共享节点在共享模式下唤醒时,头节点都会指向它,这样就可以保证可以获取到共享锁的所有后续节点都可以唤醒了。

+

如何自定义同步组件

JDK 中基于同步器实现的一些类绝大部分都是聚合了一个或多个继承了同步器的类,使用同步器提供的模板方法自定义内部同步状态的管理,然后通过这个内部类去实现同步状态管理的功能,其实这从某种程度上来说使用了 模板模式。比如 JDK 中可重入锁 ReentrantLock、读写锁 ReentrantReadWriteLock、信号量 Semaphore 以及同步工具类 CountDownLatch 等,其源码部分截图如下:

+

AQS_use_in_jdk_examples.png

+

通过上文可以知道,我们基于同步器可以分别自定义独占锁同步组件和共享锁同步组件,下面以实现一个在同一个时刻最多只允许 3 个线程访问,其它线程的访问将被阻塞的同步工具 TripletsLock 为例,很显然这个工具是共享锁模式,主要思路就是去实现一个 JDk 中的 Lock 接口来提供面向使用者的方法,比如,调用 lock 方法获取锁,使用 unlock 来对锁进行释放等,在 TripletsLock 类内部有一个自定义同步器 Sync 继承自同步器 AQS,用来对线程的访问和同步状态进行控制,当线程调用 lock 方法获取锁时,自定义同步器 Sync 先计算出获取到锁后的同步状态,然后使用 Unsafe 类操作来保证同步状态更新的原子性,由于同一时刻只能 3 个线程访问,这里我们可以将同步状态 state 的初始值设置为 3,表示当前可用的同步资源数量,当有线程成功获取到锁时将同步状态 state 减 1,有线程成功释放锁时将同步状态加 1,同步状态的取值范围为 0、1、2、3,同步状态为 0 时表示没有可用同步资源,这个时候如果有线程访问将被阻塞。下面来看看这个自定义同步组件的实现代码:

+
1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/**
* @author mghio
* @date: 2020-06-13
* @version: 1.0
* @description:
* @since JDK 1.8
*/
public class TripletsLock implements Lock {

private final Sync sync = new Sync(3);

private static final class Sync extends AbstractQueuedSynchronizer {
public Sync(int state) {
setState(state);
}

Condition newCondition() {
return new ConditionObject();
}

@Override
protected int tryAcquireShared(int reduceCount) {
for (; ;) {
int currentState = getState();
int newState = currentState - reduceCount;
if (newState < 0 || compareAndSetState(currentState, newState)) {
return newState;
}
}
}

@Override
protected boolean tryReleaseShared(int count) {
for (; ;) {
int currentState = getState();
int newState = currentState + count;
if (compareAndSetState(currentState, newState)) {
return true;
}
}
}
}

@Override
public void lock() {
sync.acquireShared(1);
}

@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}

@Override
public boolean tryLock() {
return sync.tryAcquireShared(1) > 0;
}

@Override
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

@Override
public void unlock() {
sync.releaseShared(1);
}

@Override
public Condition newCondition() {
return sync.newCondition();
}
}
+ +

下面启动 20 个线程测试看看自定义同步同步工具类 TripletsLock 是否达到我们的预期。测试代码如下:

+
1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* @author mghio
* @date: 2020-06-13
* @version: 1.0
* @description:
* @since JDK 1.8
*/
public class TripletsLockTest {
private final Lock lock = new TripletsLock();
private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

@Test
public void testTripletsLock() {
// 启动 20 个线程
for (int i = 0; i < 20; i++) {
Thread worker = new Runner();
worker.setDaemon(true);
worker.start();
}

for (int i = 0; i < 20; i++) {
second(2);
System.out.println();
}
}

private class Runner extends Thread {
@Override
public void run() {
for (; ;) {
lock.lock();
try {
second(1);
System.out.println(dateFormat.format(new Date()) + " ----> " + Thread.currentThread().getName());
second(1);
} finally {
lock.unlock();
}
}
}
}

private static void second(long seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
+ +

测试结果如下:

+

AQS_TripletsLock_Test_Result.png

+

从以上测试结果可以发现,同一时刻只有三个线程可以获取到锁,符合预期,这里需要明确的是这个锁获取过程是非公平的。

+

总结

本文主要是对同步器中的基础数据结构、独占式与共享式同步状态获取与释放过程做了简要分析,由于水平有限如有错误之处还请留言讨论。队列同步器 AbstractQueuedSynchronizerJDK 中很多的一些多线程并发工具类的实现基础框架,对其深入学习理解有助于我们更好的去使用其特性和相关工具类。

+
+

参考文章

+

Java并发编程的艺术
Java Synchronizer - AQS Learning
从 ReentrantLock 的实现看 AQS 的原理及应用
The java.util.concurrent Synchronizer Framework

+ + +
+ + + + + +
+
-------------本文结束感谢您的阅读-------------
+
+ + + +
+
+ mghio wechat +
微信公众号「mghio」
+
+ +
+ + + +
+
+
请我吃🍗
+ + +
+ +
+ + + +
+ +
+ + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ +
+
+ + + + + +
+ + + + + + + + + +
+
+ +
+ +
+ + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index 8190bcdf..612ca464 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -685,7 +685,7 @@

总结 - 26 + 27 日志 @@ -696,7 +696,7 @@

总结 - 26 + 27 分类 diff --git a/post/51e5bd99.html b/post/51e5bd99.html index 0d1fc936..18e50204 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -726,7 +726,7 @@

- 26 + 27 日志 @@ -737,7 +737,7 @@

- 26 + 27 分类 diff --git a/post/710bd10b.html b/post/710bd10b.html index e8d2d7e7..0da8a382 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -732,7 +732,7 @@

总结 - 26 + 27 日志 @@ -743,7 +743,7 @@

总结 - 26 + 27 分类 diff --git a/post/7528c810.html b/post/7528c810.html index 8cd636c7..cba61837 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -715,7 +715,7 @@

总结 - 26 + 27 日志 @@ -726,7 +726,7 @@

总结 - 26 + 27 分类 diff --git a/post/7b9ead86.html b/post/7b9ead86.html index 00e9123b..5d52e984 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -715,7 +715,7 @@

总结 - 26 + 27 日志 @@ -726,7 +726,7 @@

总结 - 26 + 27 分类 diff --git a/post/7eb2637f.html b/post/7eb2637f.html index 7bfc5f40..d10f4af9 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -754,7 +754,7 @@

- 26 + 27 日志 @@ -765,7 +765,7 @@

- 26 + 27 分类 diff --git a/post/817c7d82.html b/post/817c7d82.html index 8fd5b65b..498259b4 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1323,7 +1323,7 @@

- 26 + 27 日志 @@ -1334,7 +1334,7 @@
- 26 + 27 分类 diff --git a/post/8a061473.html b/post/8a061473.html index bf0f300d..2f7c2515 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -791,7 +791,7 @@
- 26 + 27 日志 @@ -802,7 +802,7 @@
- 26 + 27 分类 diff --git a/post/8bd965a0.html b/post/8bd965a0.html index a93a2a4e..38932c37 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -714,7 +714,7 @@

- 26 + 27 日志 @@ -725,7 +725,7 @@

diff --git a/post/99ea2970.html b/post/99ea2970.html index b646e932..d043ecdc 100644 --- a/post/99ea2970.html +++ b/post/99ea2970.html @@ -710,7 +710,7 @@

- 26 + 27 日志 @@ -721,7 +721,7 @@

diff --git a/post/a38c0645.html b/post/a38c0645.html index 448a01dd..0a6d7a3d 100644 --- a/post/a38c0645.html +++ b/post/a38c0645.html @@ -694,7 +694,7 @@

总结 - 26 + 27 日志 @@ -705,7 +705,7 @@

总结 - 26 + 27 分类 diff --git a/post/ab706eb5.html b/post/ab706eb5.html index eb6d5b8f..99e48f6b 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -697,7 +697,7 @@

总结 - 26 + 27 日志 @@ -708,7 +708,7 @@

总结 - 26 + 27 分类 diff --git a/post/b1d4025b.html b/post/b1d4025b.html index 4f8cc635..da317b0d 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -627,7 +627,7 @@

hello world

- 26 + 27 日志 @@ -638,7 +638,7 @@

hello world

diff --git a/post/bc557e1a.html b/post/bc557e1a.html index 60478b6f..10333621 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -762,7 +762,7 @@
- 26 + 27 日志 @@ -773,7 +773,7 @@
- 26 + 27 分类 diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index 1b8f1362..4c068f1c 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -714,7 +714,7 @@

- 26 + 27 日志 @@ -725,7 +725,7 @@

diff --git a/post/e09f0428.html b/post/e09f0428.html index db847892..0b7f4553 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -684,7 +684,7 @@

- 26 + 27 日志 @@ -695,7 +695,7 @@

- 26 + 27 分类 diff --git a/post/ee27c07f.html b/post/ee27c07f.html index a70396b1..a8d8035d 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -677,7 +677,7 @@

- 26 + 27 日志 @@ -688,7 +688,7 @@

diff --git a/post/f440d00b.html b/post/f440d00b.html index 1e492bf2..10ab8764 100644 --- a/post/f440d00b.html +++ b/post/f440d00b.html @@ -713,7 +713,7 @@

总结 - 26 + 27 日志 @@ -724,7 +724,7 @@

总结 - 26 + 27 分类 diff --git a/post/fe76043.html b/post/fe76043.html index d5ea22e0..5f76a8d9 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -680,7 +680,7 @@

总结 - 26 + 27 日志 @@ -691,7 +691,7 @@

总结 - 26 + 27 分类 diff --git a/search.xml b/search.xml index dab79538..6c539a58 100644 --- a/search.xml +++ b/search.xml @@ -1,5 +1,19 @@ + + <![CDATA[Java 中队列同步器 AQS(AbstractQueuedSynchronizer)实现原理]]> + %2Fpost%2F4b00e13c.html + + + Java + 并发 + 进阶 + + + Java + 并发 + + <![CDATA[一文让你快速上手 Mockito 单元测试框架]]> %2Fpost%2F24042edf.html diff --git a/sitemap.xml b/sitemap.xml index fcfbf4db..8fa8f8d3 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,13 @@ + + https://www.mghio.cn/post/4b00e13c.html + + 2020-06-11T13:52:13.721Z + + + https://www.mghio.cn/post/24042edf.html diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index eb4e7de5..a9c14e24 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index b2d7a6ac..205aaa62 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index 8ff7b367..39eb902f 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git a/tags/GC/index.html b/tags/GC/index.html index 09ab65f5..7dd6244b 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git a/tags/Guava/index.html b/tags/Guava/index.html index cca4756a..b5751298 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index 5dd9f5dd..1a83759c 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index 631b7dd2..573b3ee7 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git a/tags/JDK/index.html b/tags/JDK/index.html index 991f21ae..3b94acb9 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git a/tags/JVM/index.html b/tags/JVM/index.html index a9be223f..c46bb320 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -412,7 +412,7 @@

- 26 + 27 日志 @@ -423,7 +423,7 @@

diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index 8ed25003..dc5d9737 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index f2ddf652..96dc1233 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git a/tags/Java/index.html b/tags/Java/index.html index 2ca3375d..c9a2683f 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -624,7 +624,7 @@

- 26 + 27 日志 @@ -635,7 +635,7 @@

diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index e8b8b404..ce6df622 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -624,7 +624,7 @@

- 26 + 27 日志 @@ -635,7 +635,7 @@

diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index 7f0da72d..37a32dea 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -416,7 +442,7 @@

- 26 + 27 日志 @@ -427,7 +453,7 @@

diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index eb87a275..ca431d3e 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git a/tags/String/index.html b/tags/String/index.html index 9c0983e5..e98c2ea4 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git a/tags/index.html b/tags/index.html index ecb1c431..d2d170b3 100644 --- a/tags/index.html +++ b/tags/index.html @@ -320,7 +320,7 @@

目前共计 25 个标签 @@ -378,7 +378,7 @@

- 26 + 27 日志 @@ -389,7 +389,7 @@

diff --git a/tags/mockito/index.html b/tags/mockito/index.html index 61d1f40f..4ce068b7 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git a/tags/test/index.html b/tags/test/index.html index fe5a34ca..85d4a980 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index ce9b35a1..e1abbc01 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index 0566af95..90a6a70f 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -412,7 +412,7 @@

- 26 + 27 日志 @@ -423,7 +423,7 @@

diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 058de1f4..7f057748 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -412,7 +412,7 @@

- 26 + 27 日志 @@ -423,7 +423,7 @@

diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index 05eb9e08..29475f40 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index ca6f14c2..48e44134 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -309,6 +309,32 @@

并发标签 + + + + + +
@@ -386,7 +412,7 @@

- 26 + 27 日志 @@ -397,7 +423,7 @@

diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index 6cd6c483..e3d8c2bf 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 85ed83a4..0d482ff2 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 59d40c25..94e64c7a 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index b92c5bb2..3b26a729 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -386,7 +386,7 @@

- 26 + 27 日志 @@ -397,7 +397,7 @@

From ddd380cf7bc1c4d776bf847b43a4338f01d84718 Mon Sep 17 00:00:00 2001 From: maguihai Date: Sat, 13 Jun 2020 19:00:13 +0800 Subject: [PATCH 02/19] Site updated: 2020-06-13 19:00:12 --- atom.xml | 6 +++--- baidusitemap.xml | 2 +- css/main.css | 2 +- post/4b00e13c.html | 10 +++++----- sitemap.xml | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/atom.xml b/atom.xml index 63495fe8..4c7720ab 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2020-06-11T13:52:13.721Z + 2020-06-13T10:59:03.430Z https://www.mghio.cn/ @@ -21,9 +21,9 @@ https://www.mghio.cn/post/4b00e13c.html 2020-06-13T12:48:00.000Z - 2020-06-11T13:52:13.721Z + 2020-06-13T10:59:03.430Z - 前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

AQS 基础数据结构

同步队列

队列同步器 AQS(下文简称为同步器)主要是依赖于内部的一个 FIFO(first-in-first-out)双向队列来对同步状态进行管理的,当线程获取同步状态失败时,同步器会将当前线程和当前等待状态等信息封装成一个内部定义的节点 Node,然后将其加入队列,同时阻塞当前线程;当同步状态释放时,会将同步队列中首节点唤醒,让其再次尝试去获取同步状态。同步队列的基本结构如下:

AQS_QUEUE.png

队列节点 Node

同步队列使用同步器中的静态内部类 Node 用来保存获取同步状态的线程的引用、线程的等待状态、前驱节点和后继节点。

AQS_inner_class_node.png

同步队列中 Node 节点的属性名称和具体含义如下表所示:

属性类型和名称描述
volatile int waitStatus当前节点在队列中的等待状态
volatile Node prev前驱节点,当节点加入同步队列时被赋值(使用尾部添加方式)
volatile Node next后继节点
volatile Thread thread获取同步状态的线程
Node nextWaiter等待队列中的后继节点,如果当前节点是共享的,则该字段是一个 SHARED 常量

每个节点线程都有两种锁模式,分别为 SHARED 表示线程以共享的模式等待锁,EXCLUSIVE 表示线程以独占的方式等待锁。同时每个节点的等待状态 waitStatus 只能取以下表中的枚举值:

枚举值描述
SIGNAL值为 -1,表示该节点的线程已经准备完毕,等待资源释放
CANCELLED值为 1,表示该节点线程获取锁的请求已经取消了
CONDITION值为 -2,表示该节点线程等待在 Condition 上,等待被其它线程唤醒
PROPAGATE值为 -3,表示下一次共享同步状态获取会无限进行下去,只在 SHARED 情况下使用
0值为 0,初始状态,初始化的默认值
同步状态 state

同步器内部使用了一个名为 stateint 类型的变量表示同步状态,同步器的主要使用方式是通过继承,子类通过继承并实现它的抽象方法来管理同步状态,同步器给我们提供了如下三个方法来对同步状态进行更改。

方法签名描述
protected final int getState()获取当前同步状态
protected final void setState(int newState)设置当前同步状态
protected final boolean compareAndSetState(int expect, int update)使用 CAS 设置当前状态,该方法能够保证状态设置的原子性

在独享锁中同步状态 state 这个值通常是 0 或者 1(如果是重入锁的话 state 值就是重入的次数),在共享锁中 state 就是持有锁的数量。

独占式同步状态获取与释放

同步器中提供了 acquire(int arg) 方法来进行独占式同步状态的获取,获取到了同步状态也就是获取到了锁,该方法源码如下所示:

1
2
3
4
5
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}

方法首先会调用 tryAcquire 方法尝试去获取锁,查看方法的源码可以发现,同步器并未对该方法进行实现(只是抛出一个不支持操作异常 UnsupportedOperationException),这个方法是需要后续同步组件的开发人员自己去实现的,如果方法返回 true 则表示当前线程成功获取到锁,调用 selfInterrupt() 中断当前线程(PS:这里留给大家一个问题:为什么获取了锁以后还要中断线程呢?),方法结束返回,如果方法返回 false 则表示当前线程获取锁失败,也就是说有其它线程先前已经获取到了锁,此时就需要把当前线程以及等待状态等信息添加到同步队列中,下面来看看同步器在线程未获取到锁时具体是如何实现。
通过源码发现,当获取锁失败时,会执行判断条件与操作的后半部分 acquireQueued(addWaiter(Node.EXCLUSIVE), arg),首先指定锁模式为 Node.EXCLUSIVE 调用 addWaiter 方法,该方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}

通过方法参数指定的锁模式(共享锁 or 独占锁)和当前线程构造出一个 Node 节点,如果同步队列已经初始化,那么首先会进行一次从尾部加入队列的尝试,使用 compareAndSetTail 方法保证原子性,进入该方法源码可以发现是基于 sun.misc 包下提供的 Unsafe 类来实现的。如果首次尝试加入同步队列失败,会再次调用 enq 方法进行入队操作,继续跟进 enq 方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}

通过其源码可以发现和第一次尝试加入队列的代码类似,只是该方法里面加了同步队列初始化判断,使用 compareAndSetHead 方法保证设置头节点的原子性,同样它底层也是基于 Unsafe 类,然后外层套了一个 for (;;) 死循环,循环唯一的退出条件是从队尾入队成功,也就是说如果从该方法成功返回了就表示已经入队成功了,至此,addWaiter 执行完毕返回当前 Node 节点。然后以该节点作为 acquireQueued 方法的入参继续进行其它步骤,该方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}

可以看到,该方法本质上也是通过一个死循环(自旋)去获取锁并且支持中断,在循环体外面定义两个标记变量,failed 标记是否成功获取到锁,interrupted 标记在等待的过程中是否被中断过。方法首先通过 predecessor 获取当前节点的前驱节点,当当前节点的前驱节点是 head 头节点时就调用 tryAcquire 尝试获取锁,也就是第二个节点则尝试获取锁,这里为什么要从第二个节点才尝试获取锁呢?是因为同步队列本质上是一个双向链表,在双向链表中,第一个节点并不存储任何数据是虚节点,只是起到一个占位的作用,真正存储数据的节点是从第二个节点开始的。如果成功获取锁,也就是 tryAcquire 方法返回 true 后,将 head 指向当前节点并把之前找到的头节点 p 从队列中移除,修改是否成功获取到锁标记,结束方法返回中断标记。
如果当前节点的前驱节点 p 不是头节点或者前驱节点 p 是头节点但是获取锁操作失败,那么会调用 shouldParkAfterFailedAcquire 方法判断当前 node 节点是否需要被阻塞,这里的阻塞判断主要是为了防止长时间自旋给 CPU 带来非常大的执行开销,浪费资源。该方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}

方法参数为当前节点的前驱节点以及当前节点,主要是靠前驱节点来判断是否需要进行阻塞,首先获取到前驱节点的等待状态 ws,如果节点状态 wsSIGNAL,表示前驱节点的线程已经准备完毕,等待资源释放,方法返回 true 表示可以阻塞,如果 ws > 0,通过上文可以知道节点只有一个状态 CANCELLED(值为 1) 满足该条件,表示该节点线程获取锁的请求已经取消了,会通过一个 do-while 循环向前查找 CANCELLED 状态的节点并将其从同步队列中移除,否则进入 else 分支,使用 compareAndSetWaitStatus 原子操作将前驱节点的等待状态修改为 SIGNAL,以上这两种情况都不需要进行阻塞方法返回 false
当经过判断后需要阻塞的话,也就是 compareAndSetWaitStatus 方法返回 true 时,会通过 parkAndCheckInterrupt 方法阻塞挂起当前线程,并返回当前线程的中断标识。方法如下:

1
2
3
4
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}

线程阻塞是通过 LockSupport 这个工具类实现的,深入其源码可以发现它底层也是基于 Unsafe 类实现的。如果以上两个方法都返回 true 的话就更新中断标记。这里还有一个问题就是什么时候会将一个节点的等待状态 waitStatus 修改为 CANCELLED 节点线程获取锁的请求取消状态呢?细心的朋友可能已经发现了,在上文贴出的 acquireQueued 方法源码中的 finally 块中会根据 failed 标记来决定是否调用 cancelAcquire 方法,这个方法就是用来将节点状态修改为 CANCELLED 的,方法的具体实现留给大家去探索。至此 AQS 独占式同步状态获取锁的流程就完成了,下面通过一个流程图来看看整体流程:

AQS_acquire.png


下面再看看独占式锁释放的过程,同步器使用 release 方法来让我们进行独占式锁的释放,其方法源码如下:

1
2
3
4
5
6
7
8
9
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}

首先调用 tryRelease 方法尝试进行锁释放操作,继续跟进该方法发现同步器只是抛出了一个不支持操作异常 UnsupportedOperationException,这里和上文独占锁获取中 tryAcquire 方法是一样的套路,需要开发者自己定义锁释放操作。

AQS_tryrelease.png

通过其 JavaDoc 可以得知,如果返回 false,则表示释放锁失败,方法结束。该方法如果返回 true,则表示当前线程释放锁成功,需要通知队列中等待获取锁的线程进行锁获取操作。首先获取头节点 head,如果当前头节点不为 null,并且其等待状态不是初始状态(0),则解除线程阻塞挂起状态,通过 unparkSuccessor 方法实现,该方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);

/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}

首先获取头节点的等待状态 ws,如果状态值为负数(Node.SIGNAL or Node.PROPAGATE),则通过 CAS 操作将其改为初始状态(0),然后获取头节点的后继节点,如果后继节点为 null 或者后继节点状态为 CANCELLED(获取锁请求已取消),就从队列尾部开始寻找第一个状态为非 CANCELLED 的节点,如果该节点不为空则使用 LockSupportunpark 方法将其唤醒,该方法底层是通过 Unsafe 类的 unpark 实现的。这里需要从队尾查找非 CANCELLED 状态的节点的原因是,在之前的获取独占锁失败时的入队 addWaiter 方法实现中,该方法如下:

AQS_unparkSuccessor.png

假设一个线程执行到了上图中的 ① 处,② 处还没有执行,此时另一个线程恰好执行了 unparkSuccessor 方法,那么就无法通过从前向后查找了,因为节点的后继指针 next 还没赋值呢,所以需要从后往前进行查找。至此,独占式锁释放操作就结束了,同样的,最后我们也通过一个流程图来看看整个锁释放的过程:

AQS_release.png

独占式可中断同步状态获取

同步器提供了 acquireInterruptibly 方法来进行可响应中断的获取锁操作,方法实现源码如下:

1
2
3
4
5
6
7
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}

方法首先检查当前线程的中断状态,如果已中断,则直接抛出中断异常 InterruptedException 即响应中断,否则调用 tryAcquire 方法尝试获取锁,如果获取成功则方法结束返回,获取失败调用 doAcquireInterruptibly 方法,跟进该方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}

仔细观察可以发现该方法实现源码和上文中 acquireQueued 方法的实现基本上类似,只是这里把入队操作 addWaiter 放到了方法里面了,还有一个区别就是当在循环体内判断需要进行中断时会直接抛出异常来响应中断,两个方法的对比如下:

AQS_acquirequeued_interruptibly_compare.png

其它步骤和独占式锁获取一致,流程图大体上和不响应中断的锁获取差不多,只是在最开始多了一步线程中断状态检查和循环是会抛出中断异常而已。

独占式超时获取同步状态

同步器提供了 tryAcquireNanos 方法可以超时获取同步状态(也就是),该方法提供了之前 synchronized 关键字不支持的超时获取的特性,通过该方法我们可以在指定时间段 nanosTimeout 内获取锁,如果获取到锁则返回 true,否则,返回 false。方法源码如下:

1
2
3
4
5
6
7
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}

首先会调用 tryAcquire 方法尝试获取一次锁,如果获取锁成功则立即返回,否则调用 doAcquireNanos 方法进入超时获取锁流程。通过上文可以得知,同步器的 acquireInterruptibly 方法在等待获取同步状态时,如果当前线程被中断了,会抛出中断异常 InterruptedException 并立刻返回。超时获取锁的流程其实是在响应中断的基础上增加了超时获取的特性,doAcquireNanos 方法的源码如下:

1
2
3
4
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
30
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}

由以上方法实现源码可以看出,针对超时获取这里主要实现思路是:先使用当前时间加上参数传入的超时时间间隔 deadline 计算出超时的时间点,然后每次进行循环的时候使用超时时间点 deadline 减去当前时间得到剩余的时间 nanosTimeout,如果剩余时间小于 0 则证明当前获取锁操作已经超时,方法结束返回 false,反如果剩余时间大于 0。
可以看到在里面执行自旋的时候和上面独占式同步获取锁状态 acquireQueued 方法那里是一样的套路,即当当前节点的前驱节点为头节点时调用 tryAcquire 尝试获取锁,如果获取成功则返回。

AQS_acquireQueued_doAcquireNanos_compare.png

除了超时时间计算那里不同外,还有个不同的地方就是在超时获取锁失败之后的操作,如果当前线程获取锁失败,则判断剩余超时时间 nanosTimeout 是否小于 0,如果小于 0 则表示已经超时方法立即返回,反之则会判断是否需要进行阻塞挂起当前线程,如果通过 shouldParkAfterFailedAcquire 方法判断需要挂起阻塞当前线程,还要进一步比较超时剩余时间 nanosTimeoutspinForTimeoutThreshold 的大小,如果小于等于 spinForTimeoutThreshold 值(1000 纳秒)的话,将不会使当前线程进行超时等待,而是再次进行自旋过程。
加后面这个判断的主要原因在于,在非常短(小于 1000 纳秒)的时间内的等待无法做到十分精确,如果这时还进行超时等待的话,反而会让我们指定 nanosTimeout 的超时从整体上给人感觉反而不太精确,因此,在剩余超时时间非常短的情况下,同步器会再次自旋进行超时获取锁的过程,独占式超时获取锁整个过程如下所示:

AQS_tryAcquireNanos_flow.png

共享式同步状态获取与释放

共享锁顾名思义就是可以多个线程共用一个锁,在同步器中使用 acquireShared 来获取共享锁(同步状态),方法源码如下:

1
2
3
4
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}

首先通过 tryAcquireShared 尝试获取共享锁,该方法是一个模板方法在同步器中只是抛出一个不支持操作异常,需要开发人员自己去实现,同时方法的返回值有三种不同的类型分别代表三种不同的状态,其含义如下:

  1. 小于 0 表示当前线程获取锁失败
  2. 等于 0 表示当前线程获取锁成功,但是之后的线程在没有锁释放的情况下获取锁将失败,也就是说这个锁是共享模式下的最后一把锁了
  3. 大于 0 表示当前线程获取锁成功,并且还有剩余的锁可以获取

当方法 tryAcquireShared 返回值小于 0 时,也就是获取锁失败,将会执行方法 doAcquireShared,继续跟进该方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}

方法首先调用 addWaiter 方法封装当前线程和等待状态为共享模块的节点并将其添加到等待同步队列中,可以发现在共享模式下节点的 nextWaiter 属性是固定值 Node.SHARED。然后循环获取当前节点的前驱节点,如果前驱节点是头节点的话就尝试获取共享锁,如果返回值大于等于 0 表示获取共享锁成功,则调用 setHeadAndPropagate 方法,更新头节点同时如果有可用资源,则向后传播,唤醒后继节点,接下来会检查一下中断标识,如果已经中断则中断当前线程,方法结束返回。如果返回值小于 0,则表示获取锁失败,需要挂起阻塞当前线程或者继续自旋获取共享锁。下面看看 setHeadAndPropagate 方法的具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
setHead(node);
/*
* Try to signal next queued node if:
* Propagation was indicated by caller,
* or was recorded (as h.waitStatus either before
* or after setHead) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}

首先将当前获取到锁的节点设置为头节点,然后方法参数 propagate > 0 时表示之前 tryAcquireShared 方法的返回值大于 0,也就是说当前还有剩余的共享锁可以获取,则获取当前节点的后继节点并且后继节点是共享节点时唤醒节点去尝试获取锁,doReleaseShared 方法是同步器共享锁释放的主要逻辑。


同步器提供了 releaseShared 方法来进行共享锁的释放,方法源码如下所示:

1
2
3
4
5
6
7
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}

首先调用 tryReleaseShared 方法尝试释放共享锁,方法返回 false 代表锁释放失败,方法结束返回 false,否则就表示成功释放锁,然后执行 doReleaseShared 方法,进行唤醒后继节点并检查它是否可以向后传播等操作。继续跟进该方法如下:

1
2
3
4
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
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}

可以看到和独占式锁释放不同的是,在共享模式下,状态同步和释放可以同时执行,其原子性由 CAS 来保证,如果头节点改变了也会继续循环。每次共享节点在共享模式下唤醒时,头节点都会指向它,这样就可以保证可以获取到共享锁的所有后续节点都可以唤醒了。

如何自定义同步组件

JDK 中基于同步器实现的一些类绝大部分都是聚合了一个或多个继承了同步器的类,使用同步器提供的模板方法自定义内部同步状态的管理,然后通过这个内部类去实现同步状态管理的功能,其实这从某种程度上来说使用了 模板模式。比如 JDK 中可重入锁 ReentrantLock、读写锁 ReentrantReadWriteLock、信号量 Semaphore 以及同步工具类 CountDownLatch 等,其源码部分截图如下:

AQS_use_in_jdk_examples.png

通过上文可以知道,我们基于同步器可以分别自定义独占锁同步组件和共享锁同步组件,下面以实现一个在同一个时刻最多只允许 3 个线程访问,其它线程的访问将被阻塞的同步工具 TripletsLock 为例,很显然这个工具是共享锁模式,主要思路就是去实现一个 JDk 中的 Lock 接口来提供面向使用者的方法,比如,调用 lock 方法获取锁,使用 unlock 来对锁进行释放等,在 TripletsLock 类内部有一个自定义同步器 Sync 继承自同步器 AQS,用来对线程的访问和同步状态进行控制,当线程调用 lock 方法获取锁时,自定义同步器 Sync 先计算出获取到锁后的同步状态,然后使用 Unsafe 类操作来保证同步状态更新的原子性,由于同一时刻只能 3 个线程访问,这里我们可以将同步状态 state 的初始值设置为 3,表示当前可用的同步资源数量,当有线程成功获取到锁时将同步状态 state 减 1,有线程成功释放锁时将同步状态加 1,同步状态的取值范围为 0、1、2、3,同步状态为 0 时表示没有可用同步资源,这个时候如果有线程访问将被阻塞。下面来看看这个自定义同步组件的实现代码:

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/**
* @author mghio
* @date: 2020-06-13
* @version: 1.0
* @description:
* @since JDK 1.8
*/
public class TripletsLock implements Lock {

private final Sync sync = new Sync(3);

private static final class Sync extends AbstractQueuedSynchronizer {
public Sync(int state) {
setState(state);
}

Condition newCondition() {
return new ConditionObject();
}

@Override
protected int tryAcquireShared(int reduceCount) {
for (; ;) {
int currentState = getState();
int newState = currentState - reduceCount;
if (newState < 0 || compareAndSetState(currentState, newState)) {
return newState;
}
}
}

@Override
protected boolean tryReleaseShared(int count) {
for (; ;) {
int currentState = getState();
int newState = currentState + count;
if (compareAndSetState(currentState, newState)) {
return true;
}
}
}
}

@Override
public void lock() {
sync.acquireShared(1);
}

@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}

@Override
public boolean tryLock() {
return sync.tryAcquireShared(1) > 0;
}

@Override
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

@Override
public void unlock() {
sync.releaseShared(1);
}

@Override
public Condition newCondition() {
return sync.newCondition();
}
}

下面启动 20 个线程测试看看自定义同步同步工具类 TripletsLock 是否达到我们的预期。测试代码如下:

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* @author mghio
* @date: 2020-06-13
* @version: 1.0
* @description:
* @since JDK 1.8
*/
public class TripletsLockTest {
private final Lock lock = new TripletsLock();
private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

@Test
public void testTripletsLock() {
// 启动 20 个线程
for (int i = 0; i < 20; i++) {
Thread worker = new Runner();
worker.setDaemon(true);
worker.start();
}

for (int i = 0; i < 20; i++) {
second(2);
System.out.println();
}
}

private class Runner extends Thread {
@Override
public void run() {
for (; ;) {
lock.lock();
try {
second(1);
System.out.println(dateFormat.format(new Date()) + " ----> " + Thread.currentThread().getName());
second(1);
} finally {
lock.unlock();
}
}
}
}

private static void second(long seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

测试结果如下:

AQS_TripletsLock_Test_Result.png

从以上测试结果可以发现,同一时刻只有三个线程可以获取到锁,符合预期,这里需要明确的是这个锁获取过程是非公平的。

总结

本文主要是对同步器中的基础数据结构、独占式与共享式同步状态获取与释放过程做了简要分析,由于水平有限如有错误之处还请留言讨论。队列同步器 AbstractQueuedSynchronizerJDK 中很多的一些多线程并发工具类的实现基础框架,对其深入学习理解有助于我们更好的去使用其特性和相关工具类。


参考文章

Java并发编程的艺术
Java Synchronizer - AQS Learning
从 ReentrantLock 的实现看 AQS 的原理及应用
The java.util.concurrent Synchronizer Framework

]]> + 前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

AQS 基础数据结构

同步队列

队列同步器 AQS(下文简称为同步器)主要是依赖于内部的一个 FIFO(first-in-first-out)双向队列来对同步状态进行管理的,当线程获取同步状态失败时,同步器会将当前线程和当前等待状态等信息封装成一个内部定义的节点 Node,然后将其加入队列,同时阻塞当前线程;当同步状态释放时,会将同步队列中首节点唤醒,让其再次尝试去获取同步状态。同步队列的基本结构如下:

AQS_QUEUE.png

队列节点 Node

同步队列使用同步器中的静态内部类 Node 用来保存获取同步状态的线程的引用、线程的等待状态、前驱节点和后继节点。

AQS_inner_class_node.png

同步队列中 Node 节点的属性名称和具体含义如下表所示:

属性类型和名称描述
volatile int waitStatus当前节点在队列中的等待状态
volatile Node prev前驱节点,当节点加入同步队列时被赋值(使用尾部添加方式)
volatile Node next后继节点
volatile Thread thread获取同步状态的线程
Node nextWaiter等待队列中的后继节点,如果当前节点是共享的,则该字段是一个 SHARED 常量

每个节点线程都有两种锁模式,分别为 SHARED 表示线程以共享的模式等待锁,EXCLUSIVE 表示线程以独占的方式等待锁。同时每个节点的等待状态 waitStatus 只能取以下表中的枚举值:

枚举值描述
SIGNAL值为 -1,表示该节点的线程已经准备完毕,等待资源释放
CANCELLED值为 1,表示该节点线程获取锁的请求已经取消了
CONDITION值为 -2,表示该节点线程等待在 Condition 上,等待被其它线程唤醒
PROPAGATE值为 -3,表示下一次共享同步状态获取会无限进行下去,只在 SHARED 情况下使用
0值为 0,初始状态,初始化的默认值
同步状态 state

同步器内部使用了一个名为 stateint 类型的变量表示同步状态,同步器的主要使用方式是通过继承,子类通过继承并实现它的抽象方法来管理同步状态,同步器给我们提供了如下三个方法来对同步状态进行更改。

方法签名描述
protected final int getState()获取当前同步状态
protected final void setState(int newState)设置当前同步状态
protected final boolean compareAndSetState(int expect, int update)使用 CAS 设置当前状态,该方法能够保证状态设置的原子性

在独享锁中同步状态 state 这个值通常是 0 或者 1(如果是重入锁的话 state 值就是重入的次数),在共享锁中 state 就是持有锁的数量。

独占式同步状态获取与释放

同步器中提供了 acquire(int arg) 方法来进行独占式同步状态的获取,获取到了同步状态也就是获取到了锁,该方法源码如下所示:

1
2
3
4
5
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}

方法首先会调用 tryAcquire 方法尝试去获取锁,查看方法的源码可以发现,同步器并未对该方法进行实现(只是抛出一个不支持操作异常 UnsupportedOperationException),这个方法是需要后续同步组件的开发人员自己去实现的,如果方法返回 true 则表示当前线程成功获取到锁,调用 selfInterrupt() 中断当前线程(PS:这里留给大家一个问题:为什么获取了锁以后还要中断线程呢?),方法结束返回,如果方法返回 false 则表示当前线程获取锁失败,也就是说有其它线程先前已经获取到了锁,此时就需要把当前线程以及等待状态等信息添加到同步队列中,下面来看看同步器在线程未获取到锁时具体是如何实现。
通过源码发现,当获取锁失败时,会执行判断条件与操作的后半部分 acquireQueued(addWaiter(Node.EXCLUSIVE), arg),首先指定锁模式为 Node.EXCLUSIVE 调用 addWaiter 方法,该方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}

通过方法参数指定的锁模式(共享锁 or 独占锁)和当前线程构造出一个 Node 节点,如果同步队列已经初始化,那么首先会进行一次从尾部加入队列的尝试,使用 compareAndSetTail 方法保证原子性,进入该方法源码可以发现是基于 sun.misc 包下提供的 Unsafe 类来实现的。如果首次尝试加入同步队列失败,会再次调用 enq 方法进行入队操作,继续跟进 enq 方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}

通过其源码可以发现和第一次尝试加入队列的代码类似,只是该方法里面加了同步队列初始化判断,使用 compareAndSetHead 方法保证设置头节点的原子性,同样它底层也是基于 Unsafe 类,然后外层套了一个 for (;;) 死循环,循环唯一的退出条件是从队尾入队成功,也就是说如果从该方法成功返回了就表示已经入队成功了,至此,addWaiter 执行完毕返回当前 Node 节点。然后以该节点作为 acquireQueued 方法的入参继续进行其它步骤,该方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}

可以看到,该方法本质上也是通过一个死循环(自旋)去获取锁并且支持中断,在循环体外面定义两个标记变量,failed 标记是否成功获取到锁,interrupted 标记在等待的过程中是否被中断过。方法首先通过 predecessor 获取当前节点的前驱节点,当当前节点的前驱节点是 head 头节点时就调用 tryAcquire 尝试获取锁,也就是第二个节点则尝试获取锁,这里为什么要从第二个节点才尝试获取锁呢?是因为同步队列本质上是一个双向链表,在双向链表中,第一个节点并不存储任何数据是虚节点,只是起到一个占位的作用,真正存储数据的节点是从第二个节点开始的。如果成功获取锁,也就是 tryAcquire 方法返回 true 后,将 head 指向当前节点并把之前找到的头节点 p 从队列中移除,修改是否成功获取到锁标记,结束方法返回中断标记。
如果当前节点的前驱节点 p 不是头节点或者前驱节点 p 是头节点但是获取锁操作失败,那么会调用 shouldParkAfterFailedAcquire 方法判断当前 node 节点是否需要被阻塞,这里的阻塞判断主要是为了防止长时间自旋给 CPU 带来非常大的执行开销,浪费资源。该方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}

方法参数为当前节点的前驱节点以及当前节点,主要是靠前驱节点来判断是否需要进行阻塞,首先获取到前驱节点的等待状态 ws,如果节点状态 wsSIGNAL,表示前驱节点的线程已经准备完毕,等待资源释放,方法返回 true 表示可以阻塞,如果 ws > 0,通过上文可以知道节点只有一个状态 CANCELLED(值为 1) 满足该条件,表示该节点线程获取锁的请求已经取消了,会通过一个 do-while 循环向前查找 CANCELLED 状态的节点并将其从同步队列中移除,否则进入 else 分支,使用 compareAndSetWaitStatus 原子操作将前驱节点的等待状态修改为 SIGNAL,以上这两种情况都不需要进行阻塞方法返回 false
当经过判断后需要阻塞的话,也就是 compareAndSetWaitStatus 方法返回 true 时,会通过 parkAndCheckInterrupt 方法阻塞挂起当前线程,并返回当前线程的中断标识。方法如下:

1
2
3
4
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}

线程阻塞是通过 LockSupport 这个工具类实现的,深入其源码可以发现它底层也是基于 Unsafe 类实现的。如果以上两个方法都返回 true 的话就更新中断标记。这里还有一个问题就是什么时候会将一个节点的等待状态 waitStatus 修改为 CANCELLED 节点线程获取锁的请求取消状态呢?细心的朋友可能已经发现了,在上文贴出的 acquireQueued 方法源码中的 finally 块中会根据 failed 标记来决定是否调用 cancelAcquire 方法,这个方法就是用来将节点状态修改为 CANCELLED 的,方法的具体实现留给大家去探索。至此 AQS 独占式同步状态获取锁的流程就完成了,下面通过一个流程图来看看整体流程:

AQS_acquire.png


下面再看看独占式锁释放的过程,同步器使用 release 方法来让我们进行独占式锁的释放,其方法源码如下:

1
2
3
4
5
6
7
8
9
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}

首先调用 tryRelease 方法尝试进行锁释放操作,继续跟进该方法发现同步器只是抛出了一个不支持操作异常 UnsupportedOperationException,这里和上文独占锁获取中 tryAcquire 方法是一样的套路,需要开发者自己定义锁释放操作。

AQS_tryrelease.png

通过其 JavaDoc 可以得知,如果返回 false,则表示释放锁失败,方法结束。该方法如果返回 true,则表示当前线程释放锁成功,需要通知队列中等待获取锁的线程进行锁获取操作。首先获取头节点 head,如果当前头节点不为 null,并且其等待状态不是初始状态(0),则解除线程阻塞挂起状态,通过 unparkSuccessor 方法实现,该方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);

/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}

首先获取头节点的等待状态 ws,如果状态值为负数(Node.SIGNAL or Node.PROPAGATE),则通过 CAS 操作将其改为初始状态(0),然后获取头节点的后继节点,如果后继节点为 null 或者后继节点状态为 CANCELLED(获取锁请求已取消),就从队列尾部开始寻找第一个状态为非 CANCELLED 的节点,如果该节点不为空则使用 LockSupportunpark 方法将其唤醒,该方法底层是通过 Unsafe 类的 unpark 实现的。这里需要从队尾查找非 CANCELLED 状态的节点的原因是,在之前的获取独占锁失败时的入队 addWaiter 方法实现中,该方法如下:

AQS_unparkSuccessor.png

假设一个线程执行到了上图中的 ① 处,② 处还没有执行,此时另一个线程恰好执行了 unparkSuccessor 方法,那么就无法通过从前向后查找了,因为节点的后继指针 next 还没赋值呢,所以需要从后往前进行查找。至此,独占式锁释放操作就结束了,同样的,最后我们也通过一个流程图来看看整个锁释放的过程:

AQS_release.png

独占式可中断同步状态获取

同步器提供了 acquireInterruptibly 方法来进行可响应中断的获取锁操作,方法实现源码如下:

1
2
3
4
5
6
7
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}

方法首先检查当前线程的中断状态,如果已中断,则直接抛出中断异常 InterruptedException 即响应中断,否则调用 tryAcquire 方法尝试获取锁,如果获取成功则方法结束返回,获取失败调用 doAcquireInterruptibly 方法,跟进该方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}

仔细观察可以发现该方法实现源码和上文中 acquireQueued 方法的实现基本上类似,只是这里把入队操作 addWaiter 放到了方法里面了,还有一个区别就是当在循环体内判断需要进行中断时会直接抛出异常来响应中断,两个方法的对比如下:

AQS_acquirequeued_interruptibly_compare.png

其它步骤和独占式锁获取一致,流程图大体上和不响应中断的锁获取差不多,只是在最开始多了一步线程中断状态检查和循环是会抛出中断异常而已。

独占式超时获取同步状态

同步器提供了 tryAcquireNanos 方法可以超时获取同步状态(也就是),该方法提供了之前 synchronized 关键字不支持的超时获取的特性,通过该方法我们可以在指定时间段 nanosTimeout 内获取锁,如果获取到锁则返回 true,否则,返回 false。方法源码如下:

1
2
3
4
5
6
7
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}

首先会调用 tryAcquire 方法尝试获取一次锁,如果获取锁成功则立即返回,否则调用 doAcquireNanos 方法进入超时获取锁流程。通过上文可以得知,同步器的 acquireInterruptibly 方法在等待获取同步状态时,如果当前线程被中断了,会抛出中断异常 InterruptedException 并立刻返回。超时获取锁的流程其实是在响应中断的基础上增加了超时获取的特性,doAcquireNanos 方法的源码如下:

1
2
3
4
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
30
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}

由以上方法实现源码可以看出,针对超时获取这里主要实现思路是:先使用当前时间加上参数传入的超时时间间隔 deadline 计算出超时的时间点,然后每次进行循环的时候使用超时时间点 deadline 减去当前时间得到剩余的时间 nanosTimeout,如果剩余时间小于 0 则证明当前获取锁操作已经超时,方法结束返回 false,反如果剩余时间大于 0。
可以看到在里面执行自旋的时候和上面独占式同步获取锁状态 acquireQueued 方法那里是一样的套路,即当当前节点的前驱节点为头节点时调用 tryAcquire 尝试获取锁,如果获取成功则返回。

AQS_acquireQueued_doAcquireNanos_compare.png

除了超时时间计算那里不同外,还有个不同的地方就是在超时获取锁失败之后的操作,如果当前线程获取锁失败,则判断剩余超时时间 nanosTimeout 是否小于 0,如果小于 0 则表示已经超时方法立即返回,反之则会判断是否需要进行阻塞挂起当前线程,如果通过 shouldParkAfterFailedAcquire 方法判断需要挂起阻塞当前线程,还要进一步比较超时剩余时间 nanosTimeoutspinForTimeoutThreshold 的大小,如果小于等于 spinForTimeoutThreshold 值(1000 纳秒)的话,将不会使当前线程进行超时等待,而是再次进行自旋过程。
加后面这个判断的主要原因在于,在非常短(小于 1000 纳秒)的时间内的等待无法做到十分精确,如果这时还进行超时等待的话,反而会让我们指定 nanosTimeout 的超时从整体上给人感觉反而不太精确,因此,在剩余超时时间非常短的情况下,同步器会再次自旋进行超时获取锁的过程,独占式超时获取锁整个过程如下所示:

AQS_tryAcquireNanos_flow.png

共享式同步状态获取与释放

共享锁顾名思义就是可以多个线程共用一个锁,在同步器中使用 acquireShared 来获取共享锁(同步状态),方法源码如下:

1
2
3
4
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}

首先通过 tryAcquireShared 尝试获取共享锁,该方法是一个模板方法在同步器中只是抛出一个不支持操作异常,需要开发人员自己去实现,同时方法的返回值有三种不同的类型分别代表三种不同的状态,其含义如下:

  1. 小于 0 表示当前线程获取锁失败
  2. 等于 0 表示当前线程获取锁成功,但是之后的线程在没有锁释放的情况下获取锁将失败,也就是说这个锁是共享模式下的最后一把锁了
  3. 大于 0 表示当前线程获取锁成功,并且还有剩余的锁可以获取

当方法 tryAcquireShared 返回值小于 0 时,也就是获取锁失败,将会执行方法 doAcquireShared,继续跟进该方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}

方法首先调用 addWaiter 方法封装当前线程和等待状态为共享模块的节点并将其添加到等待同步队列中,可以发现在共享模式下节点的 nextWaiter 属性是固定值 Node.SHARED。然后循环获取当前节点的前驱节点,如果前驱节点是头节点的话就尝试获取共享锁,如果返回值大于等于 0 表示获取共享锁成功,则调用 setHeadAndPropagate 方法,更新头节点同时如果有可用资源,则向后传播,唤醒后继节点,接下来会检查一下中断标识,如果已经中断则中断当前线程,方法结束返回。如果返回值小于 0,则表示获取锁失败,需要挂起阻塞当前线程或者继续自旋获取共享锁。下面看看 setHeadAndPropagate 方法的具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
setHead(node);
/*
* Try to signal next queued node if:
* Propagation was indicated by caller,
* or was recorded (as h.waitStatus either before
* or after setHead) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}

首先将当前获取到锁的节点设置为头节点,然后方法参数 propagate > 0 时表示之前 tryAcquireShared 方法的返回值大于 0,也就是说当前还有剩余的共享锁可以获取,则获取当前节点的后继节点并且后继节点是共享节点时唤醒节点去尝试获取锁,doReleaseShared 方法是同步器共享锁释放的主要逻辑。


同步器提供了 releaseShared 方法来进行共享锁的释放,方法源码如下所示:

1
2
3
4
5
6
7
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}

首先调用 tryReleaseShared 方法尝试释放共享锁,方法返回 false 代表锁释放失败,方法结束返回 false,否则就表示成功释放锁,然后执行 doReleaseShared 方法,进行唤醒后继节点并检查它是否可以向后传播等操作。继续跟进该方法如下:

1
2
3
4
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
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}

可以看到和独占式锁释放不同的是,在共享模式下,状态同步和释放可以同时执行,其原子性由 CAS 来保证,如果头节点改变了也会继续循环。每次共享节点在共享模式下唤醒时,头节点都会指向它,这样就可以保证可以获取到共享锁的所有后续节点都可以唤醒了。

如何自定义同步组件

JDK 中基于同步器实现的一些类绝大部分都是聚合了一个或多个继承了同步器的类,使用同步器提供的模板方法自定义内部同步状态的管理,然后通过这个内部类去实现同步状态管理的功能,其实这从某种程度上来说使用了 模板模式。比如 JDK 中可重入锁 ReentrantLock、读写锁 ReentrantReadWriteLock、信号量 Semaphore 以及同步工具类 CountDownLatch 等,其源码部分截图如下:

AQS_use_in_jdk_examples.png

通过上文可以知道,我们基于同步器可以分别自定义独占锁同步组件和共享锁同步组件,下面以实现一个在同一个时刻最多只允许 3 个线程访问,其它线程的访问将被阻塞的同步工具 TripletsLock 为例,很显然这个工具是共享锁模式,主要思路就是去实现一个 JDk 中的 Lock 接口来提供面向使用者的方法,比如,调用 lock 方法获取锁,使用 unlock 来对锁进行释放等,在 TripletsLock 类内部有一个自定义同步器 Sync 继承自同步器 AQS,用来对线程的访问和同步状态进行控制,当线程调用 lock 方法获取锁时,自定义同步器 Sync 先计算出获取到锁后的同步状态,然后使用 Unsafe 类操作来保证同步状态更新的原子性,由于同一时刻只能 3 个线程访问,这里我们可以将同步状态 state 的初始值设置为 3,表示当前可用的同步资源数量,当有线程成功获取到锁时将同步状态 state 减 1,有线程成功释放锁时将同步状态加 1,同步状态的取值范围为 0、1、2、3,同步状态为 0 时表示没有可用同步资源,这个时候如果有线程访问将被阻塞。下面来看看这个自定义同步组件的实现代码:

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/**
* @author mghio
* @date: 2020-06-13
* @version: 1.0
* @description:
* @since JDK 1.8
*/
public class TripletsLock implements Lock {

private final Sync sync = new Sync(3);

private static final class Sync extends AbstractQueuedSynchronizer {
public Sync(int state) {
setState(state);
}

Condition newCondition() {
return new ConditionObject();
}

@Override
protected int tryAcquireShared(int reduceCount) {
for (; ;) {
int currentState = getState();
int newState = currentState - reduceCount;
if (newState < 0 || compareAndSetState(currentState, newState)) {
return newState;
}
}
}

@Override
protected boolean tryReleaseShared(int count) {
for (; ;) {
int currentState = getState();
int newState = currentState + count;
if (compareAndSetState(currentState, newState)) {
return true;
}
}
}
}

@Override
public void lock() {
sync.acquireShared(1);
}

@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}

@Override
public boolean tryLock() {
return sync.tryAcquireShared(1) > 0;
}

@Override
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

@Override
public void unlock() {
sync.releaseShared(1);
}

@Override
public Condition newCondition() {
return sync.newCondition();
}
}

下面启动 20 个线程测试看看自定义同步同步工具类 TripletsLock 是否达到我们的预期。测试代码如下:

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* @author mghio
* @date: 2020-06-13
* @version: 1.0
* @description:
* @since JDK 1.8
*/
public class TripletsLockTest {
private final Lock lock = new TripletsLock();
private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

@Test
public void testTripletsLock() {
// 启动 20 个线程
for (int i = 0; i < 20; i++) {
Thread worker = new Runner();
worker.setDaemon(true);
worker.start();
}

for (int i = 0; i < 20; i++) {
second(2);
System.out.println();
}
}

private class Runner extends Thread {
@Override
public void run() {
for (; ;) {
lock.lock();
try {
second(1);
System.out.println(dateFormat.format(new Date()) + " ----> " + Thread.currentThread().getName());
second(1);
} finally {
lock.unlock();
}
}
}
}

private static void second(long seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

测试结果如下:

AQS_TripletsLock_Test_Result.png

从以上测试结果可以发现,同一时刻只有三个线程可以获取到锁,符合预期,这里需要明确的是这个锁获取过程是非公平的。

总结

本文主要是对同步器中的基础数据结构、独占式与共享式同步状态获取与释放过程做了简要分析,由于水平有限如有错误之处还请留言讨论。队列同步器 AbstractQueuedSynchronizerJDK 中很多的一些多线程并发工具类的实现基础框架,对其深入学习理解有助于我们更好的去使用其特性和相关工具类。


参考文章

Java并发编程的艺术
Java Synchronizer - AQS Learning
从 ReentrantLock 的实现看 AQS 的原理及应用
The java.util.concurrent Synchronizer Framework

]]> diff --git a/baidusitemap.xml b/baidusitemap.xml index e43dc6c9..09d18dfb 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -2,7 +2,7 @@ https://www.mghio.cn/post/4b00e13c.html - 2020-06-11 + 2020-06-13 https://www.mghio.cn/post/24042edf.html 2020-06-03 diff --git a/css/main.css b/css/main.css index e464fe90..db5f78de 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #210620; + background: #2fa2bd; } .links-of-blogroll { font-size: 13px; diff --git a/post/4b00e13c.html b/post/4b00e13c.html index 0362e47f..bf1951b1 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -107,13 +107,13 @@ - + - + - + @@ -600,7 +600,7 @@

假设一个线程执行到了上图中的 ① 处,② 处还没有执行,此时另一个线程恰好执行了 unparkSuccessor 方法,那么就无法通过从前向后查找了,因为节点的后继指针 next 还没赋值呢,所以需要从后往前进行查找。至此,独占式锁释放操作就结束了,同样的,最后我们也通过一个流程图来看看整个锁释放的过程:

-

AQS_release.png

+

AQS_release.png

独占式可中断同步状态获取

同步器提供了 acquireInterruptibly 方法来进行可响应中断的获取锁操作,方法实现源码如下:

1
2
3
4
5
6
7
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
@@ -619,7 +619,7 @@

除了超时时间计算那里不同外,还有个不同的地方就是在超时获取锁失败之后的操作,如果当前线程获取锁失败,则判断剩余超时时间 nanosTimeout 是否小于 0,如果小于 0 则表示已经超时方法立即返回,反之则会判断是否需要进行阻塞挂起当前线程,如果通过 shouldParkAfterFailedAcquire 方法判断需要挂起阻塞当前线程,还要进一步比较超时剩余时间 nanosTimeoutspinForTimeoutThreshold 的大小,如果小于等于 spinForTimeoutThreshold 值(1000 纳秒)的话,将不会使当前线程进行超时等待,而是再次进行自旋过程。
加后面这个判断的主要原因在于,在非常短(小于 1000 纳秒)的时间内的等待无法做到十分精确,如果这时还进行超时等待的话,反而会让我们指定 nanosTimeout 的超时从整体上给人感觉反而不太精确,因此,在剩余超时时间非常短的情况下,同步器会再次自旋进行超时获取锁的过程,独占式超时获取锁整个过程如下所示:

-

AQS_tryAcquireNanos_flow.png

+

AQS_tryAcquireNanos_flow.png

共享式同步状态获取与释放

共享锁顾名思义就是可以多个线程共用一个锁,在同步器中使用 acquireShared 来获取共享锁(同步状态),方法源码如下:

1
2
3
4
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
diff --git a/sitemap.xml b/sitemap.xml index 8fa8f8d3..abeac4cb 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -4,7 +4,7 @@ https://www.mghio.cn/post/4b00e13c.html - 2020-06-11T13:52:13.721Z + 2020-06-13T10:59:03.430Z From 1449344a638f6a9fe04ad24410e557e5bcfa25ab Mon Sep 17 00:00:00 2001 From: maguihai Date: Sat, 4 Jul 2020 19:39:48 +0800 Subject: [PATCH 03/19] Site updated: 2020-07-04 19:39:47 --- about/index.html | 4 ++++ archives/2019/10/index.html | 4 ++++ archives/2019/11/index.html | 4 ++++ archives/2019/12/index.html | 4 ++++ archives/2019/index.html | 4 ++++ archives/2019/page/2/index.html | 4 ++++ archives/2020/01/index.html | 4 ++++ archives/2020/02/index.html | 4 ++++ archives/2020/03/index.html | 4 ++++ archives/2020/04/index.html | 4 ++++ archives/2020/05/index.html | 4 ++++ archives/2020/06/index.html | 4 ++++ archives/2020/index.html | 4 ++++ archives/2020/page/2/index.html | 4 ++++ archives/index.html | 4 ++++ archives/page/2/index.html | 4 ++++ archives/page/3/index.html | 4 ++++ categories/JDK/Java/index.html | 4 ++++ .../index.html" | 4 ++++ categories/JDK/index.html | 4 ++++ categories/Java/Bloom-filter/index.html | 4 ++++ categories/Java/GC/index.html | 4 ++++ categories/Java/Guava/String/index.html | 4 ++++ categories/Java/Guava/index.html | 4 ++++ categories/Java/IDEA/index.html | 4 ++++ "categories/Java/IDEA/\345\267\245\345\205\267/index.html" | 4 ++++ "categories/Java/IO\346\250\241\345\236\213/index.html" | 4 ++++ categories/Java/JVM/index.html | 4 ++++ categories/Java/index.html | 4 ++++ categories/Java/page/2/index.html | 4 ++++ categories/Java/page/3/index.html | 4 ++++ categories/Java/unit-test/index.html | 4 ++++ categories/Java/unit-test/mockito/index.html | 4 ++++ "categories/Java/\345\216\237\347\220\206/index.html" | 4 ++++ "categories/Java/\345\217\215\345\260\204/index.html" | 4 ++++ .../Java/\345\244\232\347\272\277\347\250\213/index.html" | 4 ++++ "categories/Java/\345\271\266\345\217\221/index.html" | 4 ++++ .../\350\277\233\351\230\266/index.html" | 4 ++++ "categories/Java/\345\274\202\346\255\245/index.html" | 4 ++++ .../Eureka/index.html" | 4 ++++ .../index.html" | 4 ++++ .../Java/\347\272\277\347\250\213\346\261\240/index.html" | 4 ++++ "categories/Java/\351\207\215\346\236\204/index.html" | 4 ++++ "categories/Linux\347\254\224\350\256\260/index.html" | 4 ++++ categories/index.html | 4 ++++ .../CAP\345\256\232\347\220\206/index.html" | 4 ++++ .../index.html" | 4 ++++ css/main.css | 2 +- index.html | 4 ++++ page/2/index.html | 4 ++++ page/3/index.html | 4 ++++ post/102cd3d9.html | 4 ++++ post/11cb7677.html | 4 ++++ post/192cb539.html | 4 ++++ post/24042edf.html | 4 ++++ post/34755d6c.html | 4 ++++ post/3ae0ff4e.html | 4 ++++ post/4615256d.html | 4 ++++ post/4b00e13c.html | 4 ++++ post/4ea48fa7.html | 4 ++++ post/51e5bd99.html | 4 ++++ post/710bd10b.html | 4 ++++ post/7528c810.html | 4 ++++ post/7b9ead86.html | 4 ++++ post/7eb2637f.html | 4 ++++ post/817c7d82.html | 4 ++++ post/8a061473.html | 4 ++++ post/8bd965a0.html | 4 ++++ post/99ea2970.html | 4 ++++ post/a38c0645.html | 4 ++++ post/ab706eb5.html | 4 ++++ post/b1d4025b.html | 4 ++++ post/bc557e1a.html | 4 ++++ post/bfcdfeaf.html | 4 ++++ post/e09f0428.html | 4 ++++ post/ee27c07f.html | 4 ++++ post/f440d00b.html | 4 ++++ post/fe76043.html | 4 ++++ tags/Bloom-filter/index.html | 4 ++++ "tags/CAP\345\256\232\347\220\206/index.html" | 4 ++++ tags/Eureka/index.html | 4 ++++ tags/GC/index.html | 4 ++++ tags/Guava/index.html | 4 ++++ tags/IDEA/index.html | 4 ++++ "tags/IO\346\250\241\345\236\213/index.html" | 4 ++++ tags/JDK/index.html | 4 ++++ tags/JVM/index.html | 4 ++++ "tags/Java-\345\216\237\347\220\206/index.html" | 4 ++++ "tags/Java-\345\271\266\345\217\221/index.html" | 4 ++++ tags/Java/index.html | 4 ++++ tags/Java/page/2/index.html | 4 ++++ tags/Java/page/3/index.html | 4 ++++ "tags/Linux\347\254\224\350\256\260/index.html" | 4 ++++ tags/String/index.html | 4 ++++ tags/index.html | 4 ++++ tags/mockito/index.html | 4 ++++ tags/test/index.html | 4 ++++ .../index.html" | 4 ++++ "tags/\345\217\215\345\260\204/index.html" | 4 ++++ "tags/\345\244\232\347\272\277\347\250\213/index.html" | 4 ++++ "tags/\345\267\245\345\205\267/index.html" | 4 ++++ "tags/\345\271\266\345\217\221/index.html" | 4 ++++ "tags/\345\274\202\346\255\245/index.html" | 4 ++++ .../index.html" | 4 ++++ .../index.html" | 4 ++++ "tags/\351\207\215\346\236\204/index.html" | 4 ++++ 106 files changed, 421 insertions(+), 1 deletion(-) diff --git a/about/index.html b/about/index.html index 784e2cc0..341d6cf9 100644 --- a/about/index.html +++ b/about/index.html @@ -631,6 +631,10 @@

荷戟独彷徨 + + diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html index ba1b32be..7fa411c1 100644 --- a/archives/2019/10/index.html +++ b/archives/2019/10/index.html @@ -769,6 +769,10 @@

荷戟独彷徨 + + diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html index 05ad8531..1ea87e08 100644 --- a/archives/2019/11/index.html +++ b/archives/2019/11/index.html @@ -734,6 +734,10 @@

荷戟独彷徨 + + diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html index 63658a00..f64ecc17 100644 --- a/archives/2019/12/index.html +++ b/archives/2019/12/index.html @@ -734,6 +734,10 @@

荷戟独彷徨 + + diff --git a/archives/2019/index.html b/archives/2019/index.html index 003aadd9..ab53c4d4 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -948,6 +948,10 @@

荷戟独彷徨 + + diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html index 0ca55bc2..f7b580d4 100644 --- a/archives/2019/page/2/index.html +++ b/archives/2019/page/2/index.html @@ -703,6 +703,10 @@

荷戟独彷徨 + + diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html index 6ca4f4a1..898d99b2 100644 --- a/archives/2020/01/index.html +++ b/archives/2020/01/index.html @@ -664,6 +664,10 @@

荷戟独彷徨 + + diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html index d1c879a5..32e4a94c 100644 --- a/archives/2020/02/index.html +++ b/archives/2020/02/index.html @@ -629,6 +629,10 @@

荷戟独彷徨 + + diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index 18cf597b..7563cfad 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -734,6 +734,10 @@

荷戟独彷徨 + + diff --git a/archives/2020/04/index.html b/archives/2020/04/index.html index 201b3d2a..56011a90 100644 --- a/archives/2020/04/index.html +++ b/archives/2020/04/index.html @@ -734,6 +734,10 @@

荷戟独彷徨 + + diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index 920d93f4..ed8d2338 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -664,6 +664,10 @@

荷戟独彷徨 + + diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html index f3230fe8..88186420 100644 --- a/archives/2020/06/index.html +++ b/archives/2020/06/index.html @@ -629,6 +629,10 @@

荷戟独彷徨 + + diff --git a/archives/2020/index.html b/archives/2020/index.html index 3e83537c..b2dbd3d5 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -948,6 +948,10 @@

荷戟独彷徨 + + diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html index 1fa3990f..6fcdc6ae 100644 --- a/archives/2020/page/2/index.html +++ b/archives/2020/page/2/index.html @@ -738,6 +738,10 @@

荷戟独彷徨 + + diff --git a/archives/index.html b/archives/index.html index 1a6eebd7..f429856b 100644 --- a/archives/index.html +++ b/archives/index.html @@ -948,6 +948,10 @@

荷戟独彷徨 + + diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 7a43af04..7dd44849 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -953,6 +953,10 @@

荷戟独彷徨 + + diff --git a/archives/page/3/index.html b/archives/page/3/index.html index e3bf2a84..7537d100 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -843,6 +843,10 @@

荷戟独彷徨 + + diff --git a/categories/JDK/Java/index.html b/categories/JDK/Java/index.html index 8e9ca06f..bcb4bf6b 100644 --- a/categories/JDK/Java/index.html +++ b/categories/JDK/Java/index.html @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 9c0953f0..22f189c5 100644 --- "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git a/categories/JDK/index.html b/categories/JDK/index.html index 1e58561b..938afddf 100644 --- a/categories/JDK/index.html +++ b/categories/JDK/index.html @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/Bloom-filter/index.html b/categories/Java/Bloom-filter/index.html index e763a853..bc3ed1c7 100644 --- a/categories/Java/Bloom-filter/index.html +++ b/categories/Java/Bloom-filter/index.html @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/GC/index.html b/categories/Java/GC/index.html index 0378d054..9ad67249 100644 --- a/categories/Java/GC/index.html +++ b/categories/Java/GC/index.html @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/Guava/String/index.html b/categories/Java/Guava/String/index.html index 055880ae..9339c24f 100644 --- a/categories/Java/Guava/String/index.html +++ b/categories/Java/Guava/String/index.html @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/Guava/index.html b/categories/Java/Guava/index.html index 367134ff..0c091e28 100644 --- a/categories/Java/Guava/index.html +++ b/categories/Java/Guava/index.html @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/IDEA/index.html b/categories/Java/IDEA/index.html index d8d56203..c3a20a29 100644 --- a/categories/Java/IDEA/index.html +++ b/categories/Java/IDEA/index.html @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" index 6e1d65fd..649072ac 100644 --- "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" +++ "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/IO\346\250\241\345\236\213/index.html" "b/categories/Java/IO\346\250\241\345\236\213/index.html" index dec572ef..6f11b67b 100644 --- "a/categories/Java/IO\346\250\241\345\236\213/index.html" +++ "b/categories/Java/IO\346\250\241\345\236\213/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/JVM/index.html b/categories/Java/JVM/index.html index 8c8fc3f2..a0a2a86d 100644 --- a/categories/Java/JVM/index.html +++ b/categories/Java/JVM/index.html @@ -636,6 +636,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/index.html b/categories/Java/index.html index 1f6e1e4f..db636802 100644 --- a/categories/Java/index.html +++ b/categories/Java/index.html @@ -848,6 +848,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/page/2/index.html b/categories/Java/page/2/index.html index ee059eb3..c02a6c34 100644 --- a/categories/Java/page/2/index.html +++ b/categories/Java/page/2/index.html @@ -848,6 +848,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/page/3/index.html b/categories/Java/page/3/index.html index dd3d4d3d..0e00da3a 100644 --- a/categories/Java/page/3/index.html +++ b/categories/Java/page/3/index.html @@ -692,6 +692,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/unit-test/index.html b/categories/Java/unit-test/index.html index a609360c..5553efc4 100644 --- a/categories/Java/unit-test/index.html +++ b/categories/Java/unit-test/index.html @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git a/categories/Java/unit-test/mockito/index.html b/categories/Java/unit-test/mockito/index.html index 691249bf..1a63f433 100644 --- a/categories/Java/unit-test/mockito/index.html +++ b/categories/Java/unit-test/mockito/index.html @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/\345\216\237\347\220\206/index.html" "b/categories/Java/\345\216\237\347\220\206/index.html" index b875242c..0474414d 100644 --- "a/categories/Java/\345\216\237\347\220\206/index.html" +++ "b/categories/Java/\345\216\237\347\220\206/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/\345\217\215\345\260\204/index.html" "b/categories/Java/\345\217\215\345\260\204/index.html" index 017fc399..838bf626 100644 --- "a/categories/Java/\345\217\215\345\260\204/index.html" +++ "b/categories/Java/\345\217\215\345\260\204/index.html" @@ -636,6 +636,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" index 07bd3d32..3376896a 100644 --- "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" @@ -636,6 +636,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/\345\271\266\345\217\221/index.html" "b/categories/Java/\345\271\266\345\217\221/index.html" index d363413f..01bbc4ff 100644 --- "a/categories/Java/\345\271\266\345\217\221/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/index.html" @@ -662,6 +662,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" index 6a04d60b..c8eea8fd 100644 --- "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/\345\274\202\346\255\245/index.html" "b/categories/Java/\345\274\202\346\255\245/index.html" index b5342cdc..750c2a5a 100644 --- "a/categories/Java/\345\274\202\346\255\245/index.html" +++ "b/categories/Java/\345\274\202\346\255\245/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" index 832184a8..16800b32 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 25c2303c..d6eaf39b 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" index 69f68850..255bfc5d 100644 --- "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" +++ "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" @@ -636,6 +636,10 @@

荷戟独彷徨 + + diff --git "a/categories/Java/\351\207\215\346\236\204/index.html" "b/categories/Java/\351\207\215\346\236\204/index.html" index 66739461..dae4babf 100644 --- "a/categories/Java/\351\207\215\346\236\204/index.html" +++ "b/categories/Java/\351\207\215\346\236\204/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/Linux\347\254\224\350\256\260/index.html" "b/categories/Linux\347\254\224\350\256\260/index.html" index 566c9dd7..fdc52ae2 100644 --- "a/categories/Linux\347\254\224\350\256\260/index.html" +++ "b/categories/Linux\347\254\224\350\256\260/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git a/categories/index.html b/categories/index.html index 2c039af9..73f6d7e5 100644 --- a/categories/index.html +++ b/categories/index.html @@ -601,6 +601,10 @@

荷戟独彷徨 + + diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" index 55549f43..bda1d6a3 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 34630035..9278ff75 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -610,6 +610,10 @@

荷戟独彷徨 + + diff --git a/css/main.css b/css/main.css index db5f78de..227b5d24 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #2fa2bd; + background: #ff6078; } .links-of-blogroll { font-size: 13px; diff --git a/index.html b/index.html index 7dd6e9c6..2aa1a8f3 100644 --- a/index.html +++ b/index.html @@ -2660,6 +2660,10 @@

前言荷戟独彷徨 + + diff --git a/page/2/index.html b/page/2/index.html index 10a234ca..2804e4d6 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -2652,6 +2652,10 @@

荷戟独彷徨 + + diff --git a/page/3/index.html b/page/3/index.html index 1c53f72d..c8e8f53d 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -1999,6 +1999,10 @@

荷戟独彷徨 + + diff --git a/post/102cd3d9.html b/post/102cd3d9.html index 272c5e4b..ba54d588 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -1070,6 +1070,10 @@

总结荷戟独彷徨 + + diff --git a/post/11cb7677.html b/post/11cb7677.html index b9f13aa9..8d629673 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -921,6 +921,10 @@

总结荷戟独彷徨 + + diff --git a/post/192cb539.html b/post/192cb539.html index 40c57607..54390332 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -985,6 +985,10 @@

荷戟独彷徨 + + diff --git a/post/24042edf.html b/post/24042edf.html index d033a396..772c74e8 100644 --- a/post/24042edf.html +++ b/post/24042edf.html @@ -993,6 +993,10 @@

总结荷戟独彷徨 + + diff --git a/post/34755d6c.html b/post/34755d6c.html index 0338c358..3925b2b1 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -900,6 +900,10 @@

总结荷戟独彷徨 + + diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index caeced70..7ffbef05 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -967,6 +967,10 @@

总结荷戟独彷徨 + + diff --git a/post/4615256d.html b/post/4615256d.html index db48e21b..b6e0f929 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -976,6 +976,10 @@

荷戟独彷徨 + + diff --git a/post/4b00e13c.html b/post/4b00e13c.html index bf1951b1..9a256371 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -1071,6 +1071,10 @@

总结荷戟独彷徨 + + diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index 612ca464..e68d8342 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -908,6 +908,10 @@

总结荷戟独彷徨 + + diff --git a/post/51e5bd99.html b/post/51e5bd99.html index 18e50204..32f611ab 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -949,6 +949,10 @@

荷戟独彷徨 + + diff --git a/post/710bd10b.html b/post/710bd10b.html index 0da8a382..6fc9e60e 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -955,6 +955,10 @@

总结荷戟独彷徨 + + diff --git a/post/7528c810.html b/post/7528c810.html index cba61837..41e96702 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -938,6 +938,10 @@

总结荷戟独彷徨 + + diff --git a/post/7b9ead86.html b/post/7b9ead86.html index 5d52e984..a5b25325 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -938,6 +938,10 @@

总结荷戟独彷徨 + + diff --git a/post/7eb2637f.html b/post/7eb2637f.html index d10f4af9..b19d2db9 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -977,6 +977,10 @@

荷戟独彷徨 + + diff --git a/post/817c7d82.html b/post/817c7d82.html index 498259b4..8beb9c7d 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1546,6 +1546,10 @@

荷戟独彷徨 + + diff --git a/post/8a061473.html b/post/8a061473.html index 2f7c2515..1b1b7c1f 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -1014,6 +1014,10 @@
荷戟独彷徨 + + diff --git a/post/8bd965a0.html b/post/8bd965a0.html index 38932c37..3c062480 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -937,6 +937,10 @@

荷戟独彷徨 + + diff --git a/post/99ea2970.html b/post/99ea2970.html index d043ecdc..8a6221da 100644 --- a/post/99ea2970.html +++ b/post/99ea2970.html @@ -933,6 +933,10 @@

荷戟独彷徨 + + diff --git a/post/a38c0645.html b/post/a38c0645.html index 0a6d7a3d..e46d02cb 100644 --- a/post/a38c0645.html +++ b/post/a38c0645.html @@ -917,6 +917,10 @@

总结荷戟独彷徨 + + diff --git a/post/ab706eb5.html b/post/ab706eb5.html index 99e48f6b..aa0991dd 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -920,6 +920,10 @@

总结荷戟独彷徨 + + diff --git a/post/b1d4025b.html b/post/b1d4025b.html index da317b0d..d5a48a48 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -850,6 +850,10 @@

hello world

荷戟独彷徨 + + diff --git a/post/bc557e1a.html b/post/bc557e1a.html index 10333621..86812f53 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -985,6 +985,10 @@
荷戟独彷徨 + + diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index 4c068f1c..5b997c1c 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -937,6 +937,10 @@

荷戟独彷徨 + + diff --git a/post/e09f0428.html b/post/e09f0428.html index 0b7f4553..d46242ee 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -907,6 +907,10 @@

荷戟独彷徨 + + diff --git a/post/ee27c07f.html b/post/ee27c07f.html index a8d8035d..d68819bb 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -900,6 +900,10 @@

荷戟独彷徨 + + diff --git a/post/f440d00b.html b/post/f440d00b.html index 10ab8764..40879e4b 100644 --- a/post/f440d00b.html +++ b/post/f440d00b.html @@ -936,6 +936,10 @@

总结荷戟独彷徨 + + diff --git a/post/fe76043.html b/post/fe76043.html index 5f76a8d9..f7fc2132 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -903,6 +903,10 @@

总结荷戟独彷徨 + + diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index a9c14e24..f46f39fb 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index 205aaa62..47c8a548 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index 39eb902f..dd833361 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git a/tags/GC/index.html b/tags/GC/index.html index 7dd6244b..09183944 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git a/tags/Guava/index.html b/tags/Guava/index.html index b5751298..8a4d2b46 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index 1a83759c..4f41a332 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index 573b3ee7..048e88fb 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git a/tags/JDK/index.html b/tags/JDK/index.html index 3b94acb9..cf8194cb 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git a/tags/JVM/index.html b/tags/JVM/index.html index c46bb320..e7fc6395 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -635,6 +635,10 @@

荷戟独彷徨 + + diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index dc5d9737..9a9d33cd 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index 96dc1233..a80a6019 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git a/tags/Java/index.html b/tags/Java/index.html index c9a2683f..8138bda9 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -847,6 +847,10 @@

荷戟独彷徨 + + diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index ce6df622..67217a5e 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -847,6 +847,10 @@

荷戟独彷徨 + + diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index 37a32dea..94b55180 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -665,6 +665,10 @@

荷戟独彷徨 + + diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index ca431d3e..2e8a6ef0 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git a/tags/String/index.html b/tags/String/index.html index e98c2ea4..e96a2ef6 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git a/tags/index.html b/tags/index.html index d2d170b3..f733ba49 100644 --- a/tags/index.html +++ b/tags/index.html @@ -601,6 +601,10 @@

荷戟独彷徨 + + diff --git a/tags/mockito/index.html b/tags/mockito/index.html index 4ce068b7..43a44bf2 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git a/tags/test/index.html b/tags/test/index.html index 85d4a980..affa3bd9 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index e1abbc01..9c31d549 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index 90a6a70f..5819623d 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -635,6 +635,10 @@

荷戟独彷徨 + + diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 7f057748..6fee346f 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -635,6 +635,10 @@

荷戟独彷徨 + + diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index 29475f40..ddb5e1bc 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index 48e44134..42e0e619 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -635,6 +635,10 @@

荷戟独彷徨 + + diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index e3d8c2bf..8b0bf32f 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 0d482ff2..a61a0f29 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 94e64c7a..5c88c78a 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index 3b26a729..e2aa7a2f 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -609,6 +609,10 @@

荷戟独彷徨 + + From a84b3ef061dfd573c41d114410b1b61358838fb7 Mon Sep 17 00:00:00 2001 From: maguihai Date: Sat, 18 Jul 2020 17:40:38 +0800 Subject: [PATCH 04/19] Site updated: 2020-07-18 17:40:37 --- about/index.html | 6 +- archives/2019/10/index.html | 8 +- archives/2019/11/index.html | 8 +- archives/2019/12/index.html | 8 +- archives/2019/index.html | 8 +- archives/2019/page/2/index.html | 8 +- archives/2020/01/index.html | 8 +- archives/2020/02/index.html | 8 +- archives/2020/03/index.html | 8 +- archives/2020/04/index.html | 8 +- archives/2020/05/index.html | 8 +- archives/2020/06/index.html | 8 +- archives/2020/07/index.html | 1273 +++++++++++++ archives/2020/index.html | 78 +- archives/2020/page/2/index.html | 43 +- archives/index.html | 78 +- archives/page/2/index.html | 78 +- archives/page/3/index.html | 43 +- atom.xml | 62 +- baidusitemap.xml | 3 + categories/JDK/Java/index.html | 6 +- .../index.html" | 6 +- categories/JDK/index.html | 6 +- categories/Java/Bloom-filter/index.html | 6 +- categories/Java/GC/index.html | 6 +- categories/Java/Guava/String/index.html | 6 +- categories/Java/Guava/index.html | 6 +- categories/Java/IDEA/index.html | 6 +- .../IDEA/\345\267\245\345\205\267/index.html" | 6 +- .../IO\346\250\241\345\236\213/index.html" | 6 +- categories/Java/JVM/index.html | 6 +- categories/Java/index.html | 6 +- categories/Java/page/2/index.html | 6 +- categories/Java/page/3/index.html | 6 +- categories/Java/unit-test/index.html | 6 +- categories/Java/unit-test/mockito/index.html | 6 +- .../Java/\345\216\237\347\220\206/index.html" | 6 +- .../Java/\345\217\215\345\260\204/index.html" | 6 +- .../index.html" | 6 +- .../Java/\345\271\266\345\217\221/index.html" | 6 +- .../\350\277\233\351\230\266/index.html" | 6 +- .../Java/\345\274\202\346\255\245/index.html" | 6 +- .../Eureka/index.html" | 6 +- .../index.html" | 6 +- .../index.html" | 6 +- .../Java/\351\207\215\346\236\204/index.html" | 6 +- .../Linux\347\254\224\350\256\260/index.html" | 6 +- categories/RabbitMQ/Java/index.html | 1254 +++++++++++++ categories/RabbitMQ/index.html | 1254 +++++++++++++ categories/index.html | 10 +- .../CAP\345\256\232\347\220\206/index.html" | 6 +- .../index.html" | 6 +- css/main.css | 2 +- index.html | 336 ++-- page/2/index.html | 410 ++-- page/3/index.html | 215 ++- post/102cd3d9.html | 6 +- post/11cb7677.html | 6 +- post/192cb539.html | 6 +- post/24042edf.html | 6 +- post/34755d6c.html | 6 +- post/3ae0ff4e.html | 6 +- post/4615256d.html | 6 +- post/4b00e13c.html | 10 +- post/4ea48fa7.html | 6 +- post/51e5bd99.html | 6 +- post/710bd10b.html | 6 +- post/7528c810.html | 6 +- post/7b9ead86.html | 6 +- post/7eb2637f.html | 6 +- post/817c7d82.html | 6 +- post/8a061473.html | 6 +- post/8bd965a0.html | 6 +- post/99ea2970.html | 6 +- post/a38c0645.html | 6 +- post/ab706eb5.html | 6 +- post/b1d4025b.html | 6 +- post/bc557e1a.html | 6 +- post/bfcdfeaf.html | 6 +- post/c34b451f.html | 1648 +++++++++++++++++ post/e09f0428.html | 6 +- post/ee27c07f.html | 6 +- post/f440d00b.html | 6 +- post/fe76043.html | 6 +- search.xml | 13 + sitemap.xml | 7 + tags/Bloom-filter/index.html | 6 +- "tags/CAP\345\256\232\347\220\206/index.html" | 6 +- tags/Eureka/index.html | 6 +- tags/GC/index.html | 6 +- tags/Guava/index.html | 6 +- tags/IDEA/index.html | 6 +- "tags/IO\346\250\241\345\236\213/index.html" | 6 +- tags/JDK/index.html | 6 +- tags/JVM/index.html | 6 +- .../Java-\345\216\237\347\220\206/index.html" | 6 +- .../Java-\345\271\266\345\217\221/index.html" | 6 +- tags/Java/index.html | 58 +- tags/Java/page/2/index.html | 58 +- tags/Java/page/3/index.html | 32 +- .../Linux\347\254\224\350\256\260/index.html" | 6 +- tags/RabbitMQ/index.html | 1253 +++++++++++++ tags/String/index.html | 6 +- tags/index.html | 10 +- tags/mockito/index.html | 6 +- tags/test/index.html | 6 +- .../index.html" | 6 +- "tags/\345\217\215\345\260\204/index.html" | 6 +- .../index.html" | 6 +- "tags/\345\267\245\345\205\267/index.html" | 6 +- "tags/\345\271\266\345\217\221/index.html" | 6 +- "tags/\345\274\202\346\255\245/index.html" | 6 +- .../index.html" | 6 +- .../index.html" | 6 +- "tags/\351\207\215\346\236\204/index.html" | 6 +- 115 files changed, 7900 insertions(+), 896 deletions(-) create mode 100644 archives/2020/07/index.html create mode 100644 categories/RabbitMQ/Java/index.html create mode 100644 categories/RabbitMQ/index.html create mode 100644 post/c34b451f.html create mode 100644 tags/RabbitMQ/index.html diff --git a/about/index.html b/about/index.html index 341d6cf9..a76302eb 100644 --- a/about/index.html +++ b/about/index.html @@ -408,7 +408,7 @@

- 27 + 28 日志 @@ -419,7 +419,7 @@

- 27 + 29 分类 @@ -430,7 +430,7 @@

- 25 + 26 标签 diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html index 7fa411c1..08295829 100644 --- a/archives/2019/10/index.html +++ b/archives/2019/10/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -546,7 +546,7 @@

- 27 + 28 日志 @@ -557,7 +557,7 @@

@@ -568,7 +568,7 @@

diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html index 1ea87e08..96894eb9 100644 --- a/archives/2019/11/index.html +++ b/archives/2019/11/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 27 + 28 日志 @@ -522,7 +522,7 @@

@@ -533,7 +533,7 @@

diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html index f64ecc17..508edbd6 100644 --- a/archives/2019/12/index.html +++ b/archives/2019/12/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 27 + 28 日志 @@ -522,7 +522,7 @@

@@ -533,7 +533,7 @@

diff --git a/archives/2019/index.html b/archives/2019/index.html index ab53c4d4..3582bb1d 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -725,7 +725,7 @@

- 27 + 28 日志 @@ -736,7 +736,7 @@

@@ -747,7 +747,7 @@

diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html index f7b580d4..07fe2b26 100644 --- a/archives/2019/page/2/index.html +++ b/archives/2019/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -480,7 +480,7 @@

- 27 + 28 日志 @@ -491,7 +491,7 @@

@@ -502,7 +502,7 @@

diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html index 898d99b2..5ff2cab7 100644 --- a/archives/2020/01/index.html +++ b/archives/2020/01/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -441,7 +441,7 @@

- 27 + 28 日志 @@ -452,7 +452,7 @@

@@ -463,7 +463,7 @@

diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html index 32e4a94c..fcbbc696 100644 --- a/archives/2020/02/index.html +++ b/archives/2020/02/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -406,7 +406,7 @@

- 27 + 28 日志 @@ -417,7 +417,7 @@

@@ -428,7 +428,7 @@

diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index 7563cfad..e0d1bee1 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 27 + 28 日志 @@ -522,7 +522,7 @@

@@ -533,7 +533,7 @@

diff --git a/archives/2020/04/index.html b/archives/2020/04/index.html index 56011a90..0f75ee38 100644 --- a/archives/2020/04/index.html +++ b/archives/2020/04/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 27 + 28 日志 @@ -522,7 +522,7 @@

@@ -533,7 +533,7 @@

diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index ed8d2338..56d35f22 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -441,7 +441,7 @@

- 27 + 28 日志 @@ -452,7 +452,7 @@

@@ -463,7 +463,7 @@

diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html index 88186420..e52279bd 100644 --- a/archives/2020/06/index.html +++ b/archives/2020/06/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -406,7 +406,7 @@

- 27 + 28 日志 @@ -417,7 +417,7 @@

@@ -428,7 +428,7 @@

diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html new file mode 100644 index 00000000..1a3a0be5 --- /dev/null +++ b/archives/2020/07/index.html @@ -0,0 +1,1273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/index.html b/archives/2020/index.html index b2dbd3d5..332807d5 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -633,41 +668,6 @@

- - - - - - - - - - - - - - - @@ -725,7 +725,7 @@

- 27 + 28 日志 @@ -736,7 +736,7 @@

@@ -747,7 +747,7 @@

diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html index 6fcdc6ae..0a408207 100644 --- a/archives/2020/page/2/index.html +++ b/archives/2020/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -515,7 +550,7 @@

- 27 + 28 日志 @@ -526,7 +561,7 @@

@@ -537,7 +572,7 @@

diff --git a/archives/index.html b/archives/index.html index f429856b..a29ae69e 100644 --- a/archives/index.html +++ b/archives/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -633,41 +668,6 @@

- - - - - - - - - - - - - - - @@ -725,7 +725,7 @@

- 27 + 28 日志 @@ -736,7 +736,7 @@

@@ -747,7 +747,7 @@

diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 7dd44849..c0636388 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -638,41 +673,6 @@

- - - - - - - - - - - - - - - @@ -730,7 +730,7 @@

- 27 + 28 日志 @@ -741,7 +741,7 @@

@@ -752,7 +752,7 @@

diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 7537d100..5f6ae2ab 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 27 篇日志。 继续努力。 + 嗯..! 目前共计 28 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2019

+ + + + + + + + + + + + + + +
@@ -620,7 +655,7 @@

- 27 + 28 日志 @@ -631,7 +666,7 @@

@@ -642,7 +677,7 @@

diff --git a/atom.xml b/atom.xml index 4c7720ab..64026fa3 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2020-06-13T10:59:03.430Z + 2020-07-18T09:39:48.484Z https://www.mghio.cn/ @@ -16,6 +16,34 @@ Hexo + + RabbitMQ 入门之基础概念 + + https://www.mghio.cn/post/c34b451f.html + 2020-07-18T09:00:51.000Z + 2020-07-18T09:39:48.484Z + + 什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作这份出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

RabbitMQ 的特点

RabbitMQ 是一个由 Relang 语言开发的 AMQP 的开源实现。AMQP(Advanced Message Queue:高级消息度列协议)它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。RabbitMQ 最初起源于消息系统,用于在分布式系统中存储转发消息,具体有如下一些特点:

  • 可靠性: RabbitMQ 使用一些机制来保证可靠性,比如持久化、传输确认机制(ack)和发布确认等。
  • 灵活的路由策略: 在消息进入队列之前,通过 Exchange 来路由消息,对于典型的路由功能,RabbitMQ 已经提供了一些内置的 Exchange 来实现。针对复杂的路由功能,可以将多个 Exchange 绑在一起,也通过插件机制实现自己的 Exchange。
  • 消息集群: 多个 RabbitMQ 服务器可以组成一个集群,形成一个逻辑 Broker。
  • 高可用: 队列可以在集群中的集群上进行镜像,使得在部分节点出问题的情况下队列仍然可用。
  • 多种协议: RabbitMQ 支持多种消息队列协议,比如 STOMP、MQTT 等。
  • 多语言客户端: RabbitMQ 几乎支持多有常用的语言,比如:Java、.NET 等
  • 管理界面: RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker 的许多方面。

RabbitMQ 安装(mac)和运行

1、安装
因为 RabbitMQ 依赖于 Erlang 语言,所以在安装 RabbitMQ 之前需要先安装 Erlang 环境,但是由于是 Mac 环境,可以使用 HomeBrew 安装,安装前先更新 brew:

1
brew update

接着安装 RabbitMQ 即可,安装过程中会自动安装其所依赖的 Erlang。

rabbitmq-base-7.jpeg

2、运行
RabbitMQ 的启动运行很简单,找到其安装目录后(使用 Homwbrew 安装的默认目录为:/usr/local/Cellar/rabbitmq),进入到目录的 sbin 目录下,可以看到有 6 个
以 rabbitmq 开头的可执行文件,直接执行 rabbitmq-server 即可。

rabbitmq-base-8.jpeg

启动正常的话可以看到启动过程的日志信息和最后的 completed with 6 plugins,这也说明启动的时候默认加载了 6 个插件。

rabbitmq-base-9.jpeg

此时通过浏览器访问 http://localhost:15672 可以看到其管理界面(默认用户名和密码都是 guest),可以在 admin 选项卡页面新增用户,管理界面如下:

rabbitmq-base-10.jpeg

PS: 以上方式不是后台启动,如果想让 RabbitMQ 后台守护进程的方式启动的话,可以在启动的时候加上 -detached 参数。

rabbitmq-base-11.jpeg

3、查询服务器状态
在安装目录的 sbin 下面有个可执行文件 rabbitmqctl ,它提供了 RabbitMQ 管理需要的几乎一站式解决方案,绝大部分的运维命令它都可以提供。查询 RabbitMQ 服务器的状态信息可以用参数 status。

rabbitmq-base-12.jpeg

RabbitMQ 中的基础概念

1、消息模型 几乎所有的 MQ 抽象来说都是一样的过程:消费者订阅某个队列,生产者生产消息,然后发布到队列中,最后将消息发送到监听该队列的消费者那里。如下图所示:

rabbitmq-base-1.jpeg

2、基本概念 上面上一个消息队列的抽象概述,具体到 RabbitMQ 有一些特有的概念,RabbitMQ 是 AMQP 协议的一个开源实现,其内部概念大都是 AMQP 协议的一些概念。

rabbitmq-base-2.jpeg

名称描述
Message 消息消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则是由一系列的可选属性组成,这些属性包括 routing-key(路由键)、priority(相对于其它消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。
Publisher 消息生产者一个向交换机发送消息的客户端应用程序。
Exchange 交换器用来接收生产者发送过来的消息,并将这些消息发送给服务器中的队列。
Binding 绑定用于消息队列和交换器之间的关联,一个绑定就是一个基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。
Queue 消息队列用来保存消息直到发送给消费者,它是消息的容器,也是消息的终点,一个消息可投入一个或多个队列,消息一直在队列里面,等待消费者连接到这个队列并将其取走。
Connection 网络连接比如一个 TCP 连接。
Channel 信道多路复用连接中的一条独立双向数据流通道,信道是建立在真实 TCP 连接内的虚拟连接,AMQP 命令都是通过信道发送出去的,不管是发布消息、订阅消息还是接收消息,这些动作都是通过信道完成的。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。
Consumer 消息的消费者一个从消息队列中获取消息的客户端应用程序。
Virtual Host 虚拟主机表示一批交换器、消息队列和相关对象。虚拟主机是共享相同身份认证和加密环境的对服务器域。每个 vhost 本质上是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。

3、AMQP 中的消息路由 AMQP 中消息路由过程和 Java 开发者熟悉的 JMS 存在一些差别,AMQP 中增加了 Exchange 和 Binding 的角色。生产者把消息发送到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发到哪个队列。

rabbitmq-base-3.jpeg

4、Exchange 类型 Exchange 分发消息时根据类型的不同分发策略略有区别,目前共有四种类型:direct、fanout、topic、headers。headers 匹配 AMQP 消息的 header 而不是路由键,此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了,所以直接看另外三种类型即可。

4.1、direct 类型

rabbitmq-base-4.jpeg

消息中的路由键(routing key)如果和 Binding 中的 binding key 一致,交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为 “dog”,则只转发 routing key 标记为 “dog” 的消息,不会转发 “dog.puppy”,也不会转发 “dog.guard” 等等。它是完全匹配、单播的模式。

4.2、fanout 类型

rabbitmq-base-5.jpeg

每个发到 fanout 类型交换机的消息都会发到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得一份复制的消息。fanout 类型转发消息是最快的。

3、topic 类型

rabbitmq-base-6.jpeg

topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上,它将路由键和绑定的字符串切分成单词,这些单词之间用点隔开。它同样也识别两个通配符:符号 “#” 和符号 “*”。# 符号匹配 0 个或多个单词,* 符号匹配不多不少一个单词。

总结

本文主要讲了关于 RabbitMQ 的安装以及基础概念的相关介绍,由于它是基于 Erlang 语言开发,可能对于部分 Java 开发者想了解其底层实现细节以及排查比较复杂的问题时不是很友好。

]]> + + + + <h4 id="什么是消息队列(MQ)"><a href="#什么是消息队列(MQ)" class="headerlink" title="什么是消息队列(MQ)"></a>什么是消息队列(MQ)</h4><p>消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。</p> +<h4 id="什么场景下考虑使用消息队列"><a href="#什么场景下考虑使用消息队列" class="headerlink" title="什么场景下考虑使用消息队列"></a>什么场景下考虑使用消息队列</h4><p>从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作这份出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。</p> + + + + + + + + + + + + + + + Java 中队列同步器 AQS(AbstractQueuedSynchronizer)实现原理 @@ -607,38 +635,6 @@ - - - - - - Java 线程池(一) - - https://www.mghio.cn/post/bc557e1a.html - 2019-11-23T10:35:30.000Z - 2019-11-24T03:07:56.046Z - - 线程池简介

使用线程池可以很好的提高性能,线程池在运行之初就会创建一定数量的空闲线程,我们将一个任务提交给线程池,线程池就会使用一个空闲的线程来执行这个任务,该任务执行完后,该线程不会死亡,而是再次变成空闲状态返回线程池,等待下一个任务的到来。在使用线程池时,我们把要执行的任务提交给整个线程池,而不是提交给某个线程,线程池拿到提交的任务后,会在内部寻找是否还有空闲的线程,如果有,就将这个任务提交给某个空闲的线程,虽然一个线程同一时刻只能执行一个任务,但是我们可以向线程池提交多个任务。合理使用线程池有以下几个优点:
降低资源消耗 多线程运行期间,系统不断的启动和关闭新线程,成本高,会过度消耗系统资源,通过重用存在的线程,减少对象创建、消亡的开销
提高响应速度 当有任务到达时,任务可以不需要等待线程的创建,可以直接从线程池中取出空闲的线程来执行任务
方便线程管理 线程对计算机来说是很稀缺的资源,如果让他无限制创建,它不仅消耗系统的资源,还会降低系统的稳定性,我们使用线程池后可以统一进行分配和监控
谈到线程池就会想到池化技术,核心思想就是把宝贵的资源放到一个池子中,每次要使用都从池子里面取,用完之后又放回池子让别人用。那么线程池在 Java 中是如何实现的呢?

Java 四种线程池

在 Java 中 Executors 工具类给我们提供了四种不同使用场景的线程池的创建方法,分别为:

  1. newSingleThreadExecutor 只有一个线程来执行任务,适用于有顺序的任务的应用场景。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,它可以保证任务按照指定顺序(FIFO,LIFO)执行,它还有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为
  2. newFixedThreadPool 固定线程数的线程池,只有核心线程,核心线程的即为最大的线程数量,没有非核心线程。每次提交一个任务就创建一个线程,直到达到线程池的最大大小。线程池一旦达到最大值就会保持不变,如果当中的某个线程因为异常而结束,那么线程池会新建一个线程加入到线程池中。它还可以控制线程的最大并发数,超出的线程会在阻塞队列(LinkedBlockingQueue)中等待,同样它也有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为。
  3. newCachedThreadPool 创建一个可缓存线程池,最大的线程个数为 2^31 - 1(Integer.MAX_VALUE),可以认为是无限大,若无可回收,则新建线程,如果线程池的大小超出了处理任务所需要的线程,那么就会回收部分空闲(60s 不执行任务)的线程。
  4. newScheduledThreadPool 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大(Integer.MAX_VALUE:2^31 - 1),适用于执行周期性的任务。

Java 线程池参数详解

上文说到的 Executors 工具类提供的四种适用于不同场景的线程池,通过查看源码可以发现最终都是调用 ThreadPoolExecutor 类来实现的,我们接下来深入了解这个类一些成员变量的具体含义。首先是ctl,其声明如下:

1
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

这个成员变量 ctl 主要用于存储线程池的工作状态以及线程池正在运行的线程数。很显然,要在一个整型变量中存储两部分数据,只能将其一分为二。其中的高 3bit 用于存储线程的状态,低 29bit 用于存储线程池中正在执行的线程数。

线程池的状态

ThreadPoolExecutor 定义了线程池的五种状态(注意,这里说的是线程池状态,不是池中的线程的状态),当创建一个线程池时的状态为 RUNNING

1
2
3
4
5
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
线程池状态含义
RUNNING允许提交并处理任务
SHUTDOWN不会处理新提交的任务,但会处理完已处理的任务
STOP不会处理新提交的任务,也不会处理阻塞队列中未执行的任务,并设置正在执行任务的中断标志位
TIDYING所有任务执行完毕,线程池中工作的线程数为 0,等待执行 terminated() 钩子方法
TERMINATEDterminated() 钩子方法执行完毕

调用线程池的 shutdown 方法,将线程池由 RUNNING 状态转为 SHUTDOWN 状态。调用 shutdownNow 方法,将线程池由 RUNNING 状态转为 STOP 状态。SHUTDOWN 状态和 STOP 状态都会先变为 TIDYING 状态,最终都会变为 TERMINATED 状态。用图表示为:

thread-pool-one.png

ThreadPoolExecutor 同时提供了以下三个方法来查看线程池的状态和池中正在执行的线程数

1
2
3
private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
ThreadPoolExecutor 的构造函数

该类参数最全的构造方法如下,这个方法决定了创建出来的线程池的各种属性:

1
2
3
4
5
6
7
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)

各个参数的含义:
corePoolSize 线程池中核心线程数的最大值
maximumPoolSize 线程池中最多能拥有的线程数
keepAliveTime 空闲线程存活时间
unit 空闲线程存活时间的单位
workQueue 用于存放任务的阻塞队列
threadFactory 创建线程工厂
handlerworkQueue 已满,并且池中的线程数达到 maximumPoolSize 时,线程池继续添加新任务时采取的策略

下面通过一张图来更形象的理解线程池的这几个参数:

thread-pool-two.png

corePoolSize、maximumPoolSize、workQueue 三者的关系,通过向线程池添加新的任务来说明着三者之间的关系:

  1. 如果没有空闲的线程执行该任务,并且池中运行的线程数小于corePoolSize时,则创建新的线程执行该任务
  2. 如果没有空闲的线程执行该任务,并且当池中正在执行的线程数大于corePoolSize时,新添加的任务进入workQueue排队(如果workQueue长度允许),等待空闲线程来执行
  3. 如果没有空闲的线程执行该任务,并且阻塞队列已满同时池中的线程数小于maximumPoolSize,则创建新的线程执行该任务
  4. 如果没有空闲的线程执行该任务,并且阻塞队列已满同时池中的线程数等于maximumPoolSize,则根据构造函数中的handler指定的策略来拒绝新添加的任务

在线程池中并没有标记出哪些线程是核心线程,哪些非核心线程,线程池它只关心核心线程的数量。下面这个是网上看到的一个形象的比喻:

如果把线程池比作一个单位的话,corePoolSize就表示正式工,线程就可以表示一个员工。当我们向单位委派一项工作时,如果单位发现正式工还没招满,单位就会招个正式工来完成这项工作。随着我们向这个单位委派的工作增多,即使正式工全部满了,工作还是干不完,那么单位只能按照我们新委派的工作按先后顺序将它们找个地方搁置起来,这个地方就是workQueue,等正式工完成了手上的工作,就到这里来取新的任务。如果不巧,年末了,各个部门都向这个单位委派任务,导致workQueue已经没有空位置放新的任务,于是单位决定招点临时工吧(临时工:又是我!)。临时工也不是想招多少就找多少,上级部门通过这个单位的maximumPoolSize确定了你这个单位的人数的最大值,换句话说最多招maximumPoolSize – corePoolSize个临时工。当然,在线程池中,谁是正式工,谁是临时工是没有区别,完全同工同酬。

keepAliveTime 和 unit 单位

keepAliveTime 表示那些超出corePoolSize数量之外的线程的空闲时间大于keepAliveTime后就被清除了。

workQueue 任务队列

workQueue决定了缓存任务的排队策略,对于不同的任务场景我们可以采取不同的策略,这个队列需要一个实现了BlockingQueue接口的任务等待队列。从ThreadPoolExecutor的文档中得知,官方一共给我们推荐了三种队列,分别是:SynchronousQueueLinkedBlockingQueueArrayBlockingQueue。其中SynchronousQueueArrayBlockingQueue属于有限队列LinkedBlockingQueue属于无限队列,具体作用如下:

  1. SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等待另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
  2. ArrayBlockingQueue:有界阻塞队列。一个由数组支持的有界阻塞队列。此队列按FIFO(先进先出)原则对元素进行排序。新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素。这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞,试图从空队列中提取元素将导致类似阻塞。
  3. LinkedBlockingQueue:链表结构的阻塞队列,尾部插入元素,头部取出元素。LinkedBlockingQueue是我们在ThreadPoolExecutor线程池中常用的等待队列。它可以指定容量也可以不指定容量。由于它具有“无限容量”的特性,实际上任何无限容量的队列/栈都是有容量的,这个容量就是Integer.MAX_VALUELinkedBlockingQueue的实现是基于链表结构,而不是类似ArrayBlockingQueue那样的数组。但实际使用过程中,不需要关心它的内部实现,如果指定了LinkedBlockingQueue的容量大小,那么它反映出来的使用特性就和ArrayBlockingQueue类似了。
threadFactory 创建线程的工厂

其实像ThreadPoolExecutor有的没有threadFactory参数的构造方法中使用的创建线程的工厂就是默认的工厂,比如下面这个构造方法:

1
2
3
4
5
6
7
8
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}

在这个构造方法中,创建线程的工厂的方法使用Executors.defaultThreadFactory()的工厂和ThreadPoolExecutor中的defaultHandler默认抛弃策略。使用 Executors.defaultThreadFactory创建的线程同属于相同的线程组,具有同为Thread.NORM_PRIORITY的优先级,以及名为pool-poolNumber.getAndIncrement()-thread-的线程名(poolNumber.getAndIncrement() 为线程池顺序序号),且创建的线程都是非守护进程。

handler 拒绝策略

表示当workQueue已满,池中的线程数达到maximumPoolSize时,线程池拒绝添加新任务时采取的策略。从文档中得知,handler一般可以取以下四种值:

拒绝策略含义
AbortPolicy抛出 RejectedExecutionException 异常
CallerRunsPolicy由向线程池提交任务的线程来执行该任务
DiscardPolicy直接丢弃当前的任务
DiscardOldestPolicy抛弃最旧的任务(最先提交而没有得到执行的任务)

个人觉得最优雅的方式还是AbortPolicy提供的处理方式:抛出异常,由开发人员进行处理。ThreadPoolExecutor默认的拒绝方式defaultHandler就是ThreadPoolExecutor.AbortPolicy

合理配置线程池

最后,我们要想合理的配置线程池,就必须首先分析任务特性,可以从以下几个角度来进行分析:

任务的性质

任务性质不同的任务可以用不同规模的线程池分开处理。CPU密集型任务配置尽可能少的线程数量,如配置Ncpu+1个线程的线程池。IO 密集型任务则由于需要等待 IO 操作,线程并不是一直在执行任务,则配置尽可能多的线程,如2*Ncpu。混合型的任务,如果可以拆分,则将其拆分成一个 CPU 密集型任务和一个 IO 密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大,则没必要进行分解。我们可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的 CPU 个数。

任务的优先级

优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。它可以让优先级高的任务先得到执行,需要注意的是如果一直有优先级高的任务提交到队列里,那么优先级低的任务可能永远不能执行。

任务的执行时间

执行时间不同的任务可以交给不同规模的线程池来处理,或者也可以使用优先级队列,让执行时间短的任务先执行。

任务的依赖性

依赖数据库连接池的任务,因为线程提交 SQL 后需要等待数据库返回结果,如果等待的时间越长 CPU 空闲时间就越长,那么线程数应该设置越大,这样才能更好的利用 CPU。建议使用有界队列,有界队列能增加系统的稳定性和预警能力,可以根据需要设大一点,比如几千。有一次我们组使用的后台任务线程池的队列和线程池全满了,不断的抛出抛弃任务的异常,通过排查发现是数据库出现了问题,导致执行 SQL 变得非常缓慢,因为后台任务线程池里的任务全是需要向数据库查询和插入数据的,所以导致线程池里的工作线程全部阻塞住,任务积压在线程池里。如果当时我们设置成无界队列,线程池的队列就会越来越多,有可能会撑满内存,导致整个系统不可用,而不只是后台任务出现问题。当然我们的系统所有的任务是用的单独的服务器部署的,而我们使用不同规模的线程池跑不同类型的任务,但是出现这样问题时也会影响到其他任务。


参考文章:
JAVA 线程池的分析和使用
ThreadPoolExecutor 的 workQueue 任务队列详解

]]> - - - - <h4 id="线程池简介"><a href="#线程池简介" class="headerlink" title="线程池简介"></a>线程池简介</h4><p>使用线程池可以很好的提高性能,线程池在运行之初就会创建一定数量的空闲线程,我们将一个任务提交给线程池,线程池就会使用一个空闲的线程来执行这个任务,该任务执行完后,该线程不会死亡,<code>而是再次变成空闲状态返回线程池,等待下一个任务的到来</code>。在使用线程池时,我们把要执行的任务提交给整个线程池,而不是提交给某个线程,线程池拿到提交的任务后,会在内部寻找是否还有空闲的线程,如果有,就将这个任务提交给某个空闲的线程,虽然一个线程同一时刻只能执行一个任务,但是我们可以向线程池提交多个任务。合理使用线程池有以下几个优点:<br>① <strong>降低资源消耗</strong> 多线程运行期间,系统不断的启动和关闭新线程,成本高,会过度消耗系统资源,通过<code>重用</code>存在的线程,减少对象创建、消亡的开销<br>② <strong>提高响应速度</strong> 当有任务到达时,任务可以不需要等待线程的创建,可以直接从线程池中取出空闲的线程来执行任务<br>③ <strong>方便线程管理</strong> 线程对计算机来说是很稀缺的资源,如果让他无限制创建,它不仅消耗系统的资源,还会降低系统的稳定性,我们使用线程池后可以统一进行分配和监控<br>谈到线程池就会想到<code>池化</code>技术,核心思想就是<code>把宝贵的资源放到一个池子中</code>,每次要使用都从池子里面取,用完之后又放回池子让别人用。那么线程池在 Java 中是如何实现的呢?</p> -<h4 id="Java-四种线程池"><a href="#Java-四种线程池" class="headerlink" title="Java 四种线程池"></a>Java 四种线程池</h4><p>在 Java 中 Executors 工具类给我们提供了四种不同使用场景的线程池的创建方法,分别为:</p> -<ol> -<li><code>newSingleThreadExecutor</code> 只有一个线程来执行任务,适用于有顺序的任务的应用场景。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,它可以保证任务按照指定顺序(FIFO,LIFO)执行,它还有可以指定线程工厂(<code>ThreadFactory</code>)的重载方法,可以自定义线程的创建行为</li> -<li><code>newFixedThreadPool</code> 固定线程数的线程池,只有核心线程,核心线程的即为最大的线程数量,没有非核心线程。每次提交一个任务就创建一个线程,直到达到线程池的最大大小。线程池一旦达到最大值就会保持不变,如果当中的某个线程因为异常而结束,那么线程池会新建一个线程加入到线程池中。它还可以控制线程的最大并发数,超出的线程会在阻塞队列(<code>LinkedBlockingQueue</code>)中等待,同样它也有可以指定线程工厂(<code>ThreadFactory</code>)的重载方法,可以自定义线程的创建行为。</li> -<li><code>newCachedThreadPool</code> 创建一个可缓存线程池,最大的线程个数为 <code>2^31 - 1(Integer.MAX_VALUE)</code>,可以认为是无限大,若无可回收,则新建线程,如果线程池的大小超出了处理任务所需要的线程,那么就会回收部分空闲(60s 不执行任务)的线程。</li> -<li><code>newScheduledThreadPool</code> 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大(<code>Integer.MAX_VALUE:2^31 - 1</code>),适用于执行周期性的任务。</li> -</ol> - - - - - - - - - diff --git a/baidusitemap.xml b/baidusitemap.xml index 09d18dfb..ced97985 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -1,6 +1,9 @@ + https://www.mghio.cn/post/c34b451f.html + 2020-07-18 + https://www.mghio.cn/post/4b00e13c.html 2020-06-13 diff --git a/categories/JDK/Java/index.html b/categories/JDK/Java/index.html index bcb4bf6b..7d87ce06 100644 --- a/categories/JDK/Java/index.html +++ b/categories/JDK/Java/index.html @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 22f189c5..d91336fe 100644 --- "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/JDK/index.html b/categories/JDK/index.html index 938afddf..cadd2a97 100644 --- a/categories/JDK/index.html +++ b/categories/JDK/index.html @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/Bloom-filter/index.html b/categories/Java/Bloom-filter/index.html index bc3ed1c7..9f99311c 100644 --- a/categories/Java/Bloom-filter/index.html +++ b/categories/Java/Bloom-filter/index.html @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/GC/index.html b/categories/Java/GC/index.html index 9ad67249..339b53b6 100644 --- a/categories/Java/GC/index.html +++ b/categories/Java/GC/index.html @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/Guava/String/index.html b/categories/Java/Guava/String/index.html index 9339c24f..5694c32e 100644 --- a/categories/Java/Guava/String/index.html +++ b/categories/Java/Guava/String/index.html @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/Guava/index.html b/categories/Java/Guava/index.html index 0c091e28..883da6f7 100644 --- a/categories/Java/Guava/index.html +++ b/categories/Java/Guava/index.html @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/IDEA/index.html b/categories/Java/IDEA/index.html index c3a20a29..30850c1c 100644 --- a/categories/Java/IDEA/index.html +++ b/categories/Java/IDEA/index.html @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" index 649072ac..667289cb 100644 --- "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" +++ "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/IO\346\250\241\345\236\213/index.html" "b/categories/Java/IO\346\250\241\345\236\213/index.html" index 6f11b67b..f41d21fa 100644 --- "a/categories/Java/IO\346\250\241\345\236\213/index.html" +++ "b/categories/Java/IO\346\250\241\345\236\213/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/JVM/index.html b/categories/Java/JVM/index.html index a0a2a86d..dd2c2657 100644 --- a/categories/Java/JVM/index.html +++ b/categories/Java/JVM/index.html @@ -413,7 +413,7 @@

- 27 + 28 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git a/categories/Java/index.html b/categories/Java/index.html index db636802..907d726b 100644 --- a/categories/Java/index.html +++ b/categories/Java/index.html @@ -625,7 +625,7 @@

- 27 + 28 日志 @@ -636,7 +636,7 @@

@@ -647,7 +647,7 @@

diff --git a/categories/Java/page/2/index.html b/categories/Java/page/2/index.html index c02a6c34..3cbac204 100644 --- a/categories/Java/page/2/index.html +++ b/categories/Java/page/2/index.html @@ -625,7 +625,7 @@

- 27 + 28 日志 @@ -636,7 +636,7 @@

@@ -647,7 +647,7 @@

diff --git a/categories/Java/page/3/index.html b/categories/Java/page/3/index.html index 0e00da3a..ebc732a3 100644 --- a/categories/Java/page/3/index.html +++ b/categories/Java/page/3/index.html @@ -469,7 +469,7 @@

- 27 + 28 日志 @@ -480,7 +480,7 @@

@@ -491,7 +491,7 @@

diff --git a/categories/Java/unit-test/index.html b/categories/Java/unit-test/index.html index 5553efc4..309bf701 100644 --- a/categories/Java/unit-test/index.html +++ b/categories/Java/unit-test/index.html @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/unit-test/mockito/index.html b/categories/Java/unit-test/mockito/index.html index 1a63f433..7ee4d542 100644 --- a/categories/Java/unit-test/mockito/index.html +++ b/categories/Java/unit-test/mockito/index.html @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\345\216\237\347\220\206/index.html" "b/categories/Java/\345\216\237\347\220\206/index.html" index 0474414d..ae3374b9 100644 --- "a/categories/Java/\345\216\237\347\220\206/index.html" +++ "b/categories/Java/\345\216\237\347\220\206/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\345\217\215\345\260\204/index.html" "b/categories/Java/\345\217\215\345\260\204/index.html" index 838bf626..9f7bf73f 100644 --- "a/categories/Java/\345\217\215\345\260\204/index.html" +++ "b/categories/Java/\345\217\215\345\260\204/index.html" @@ -413,7 +413,7 @@

- 27 + 28 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" index 3376896a..663948d8 100644 --- "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" @@ -413,7 +413,7 @@

- 27 + 28 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git "a/categories/Java/\345\271\266\345\217\221/index.html" "b/categories/Java/\345\271\266\345\217\221/index.html" index 01bbc4ff..4a5d45e0 100644 --- "a/categories/Java/\345\271\266\345\217\221/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/index.html" @@ -439,7 +439,7 @@

- 27 + 28 日志 @@ -450,7 +450,7 @@

@@ -461,7 +461,7 @@

diff --git "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" index c8eea8fd..e6a8b45b 100644 --- "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\345\274\202\346\255\245/index.html" "b/categories/Java/\345\274\202\346\255\245/index.html" index 750c2a5a..9c449eeb 100644 --- "a/categories/Java/\345\274\202\346\255\245/index.html" +++ "b/categories/Java/\345\274\202\346\255\245/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" index 16800b32..a5b2e7cf 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index d6eaf39b..17e475f6 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" index 255bfc5d..0b2e70b7 100644 --- "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" +++ "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" @@ -413,7 +413,7 @@

- 27 + 28 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git "a/categories/Java/\351\207\215\346\236\204/index.html" "b/categories/Java/\351\207\215\346\236\204/index.html" index dae4babf..f9844d2d 100644 --- "a/categories/Java/\351\207\215\346\236\204/index.html" +++ "b/categories/Java/\351\207\215\346\236\204/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Linux\347\254\224\350\256\260/index.html" "b/categories/Linux\347\254\224\350\256\260/index.html" index fdc52ae2..7f28df0f 100644 --- "a/categories/Linux\347\254\224\350\256\260/index.html" +++ "b/categories/Linux\347\254\224\350\256\260/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/RabbitMQ/Java/index.html b/categories/RabbitMQ/Java/index.html new file mode 100644 index 00000000..a9833f72 --- /dev/null +++ b/categories/RabbitMQ/Java/index.html @@ -0,0 +1,1254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: Java | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/RabbitMQ/index.html b/categories/RabbitMQ/index.html new file mode 100644 index 00000000..106e8484 --- /dev/null +++ b/categories/RabbitMQ/index.html @@ -0,0 +1,1254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: RabbitMQ | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/index.html b/categories/index.html index 73f6d7e5..517aa584 100644 --- a/categories/index.html +++ b/categories/index.html @@ -317,10 +317,10 @@

@@ -378,7 +378,7 @@

- 27 + 28 日志 @@ -389,7 +389,7 @@

@@ -400,7 +400,7 @@

diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" index bda1d6a3..4ab6fdad 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 9278ff75..cf1c24d6 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -387,7 +387,7 @@

- 27 + 28 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/css/main.css b/css/main.css index 227b5d24..e30a6646 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #ff6078; + background: #95fabe; } .links-of-blogroll { font-size: 13px; diff --git a/index.html b/index.html index 2aa1a8f3..137f5ab7 100644 --- a/index.html +++ b/index.html @@ -310,7 +310,7 @@

Java 搬运工 & 终身学习
- +

@@ -467,10 +456,11 @@

-

前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

+

什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

+

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作这份出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

- + 阅读全文 »
@@ -523,7 +513,7 @@

前言 - +

@@ -680,10 +670,10 @@

-

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

+

前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

- + 阅读全文 »
@@ -736,7 +726,7 @@

前言 - +

@@ -893,10 +883,10 @@

-

前言

对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

+

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

- + 阅读全文 »
@@ -949,7 +939,7 @@

前言 - +

@@ -1095,11 +1096,10 @@

-

前言

在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

-

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

+

前言

对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

- + 阅读全文 »
@@ -1152,7 +1152,7 @@

- +

-

+

@@ -1298,14 +1298,11 @@

-

前言

在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

-

原理

布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

-
-

A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

-
+

前言

在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

+

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

- + 阅读全文 »
@@ -1358,7 +1355,7 @@

原理 - +

@@ -1515,15 +1501,14 @@

-

前言

Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

-

如何使用

Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

-
1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
- -

对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

-
1
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
+

前言

在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

+

原理

布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

+
+

A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

+
- + 阅读全文 »
@@ -1576,7 +1561,7 @@

- +

-

+

@@ -1722,11 +1718,15 @@

-

前言

在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

-

什么是 CompletableFuture

CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

+

前言

Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

+

如何使用

Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

+
1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
+ +

对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

+
1
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
- + 阅读全文 »
@@ -1779,7 +1779,7 @@

- +

-

+

@@ -1925,11 +1925,11 @@

-

前言

在日常生活中,当我们买的水果放久了之后会发出一种难闻的气味(“坏味道”),这个时候我们就应该把它扔掉。同样,代码也有“坏味道”,当然确定什么是和不是代码“坏味道”是主观的,它会随语言、开发人员和开发方法的不同而不同。在工作当中,很多时候都是在维护之前的项目和在此基础上增加一些新功能,为了能让项目代码易于理解和维护,要时刻注意代码中的“坏味道”,当发现代码如果有坏味道了,要及时去重构它使其变成优秀的整洁的代码。本文列举代码中一些常见的“坏味道”和相应的重构方案。

-

过长方法 (Long Method)

这种“坏味道”表现为方法代码行数过长,方法行数越长,就越难以理解和维护它。一个比较有用的方案就是当你觉得需要对方法中的内容加注释的时候,你应该将这个代码段作为一个新方法提取出来,哪怕有时候仅仅是一行代码也可以这么做,而且方法的命名要尽量做到见名知意,如果局部变量和参数干扰到方法的提取,则可以使用引入参数对象来进行提取。一般情况下,方法中条件运算符和循环是可以将代码移至单独方法的一个很好的代码段,对于条件运算符,可以尝试分解条件,如果方法出现循环,可以尝试提取方法。

+

前言

在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

+

什么是 CompletableFuture

CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

- + 阅读全文 »
@@ -1982,7 +1982,7 @@

- +

-

+

@@ -2459,7 +2449,7 @@

前言 - 25 + 26 标签 diff --git a/page/2/index.html b/page/2/index.html index 2804e4d6..d5f36c2f 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -310,7 +310,7 @@

Java 搬运工 & 终身学习
- +

@@ -456,11 +467,10 @@

-

前言

做过 Java 开发的同学都知道,JVM(Java 虚拟机)Java 实现的基础,虽然在平时工作中真正运用到的时候可能并不多,但是一个程序员想要上升到高级层次,那就必须知道 Java 到底是怎么运行的,这就有必要去学习了解 JVM 的相关知识了。学习 JVM 可以能更深入的理解 Java 这门语言,可以清楚知道Java程序是如何执行的以及为未来排查线上问题打下坚实的基础。接下来我们看看 2020 年的 JVM 生态报告和最新趋势,值得我们每个 Java 开发者去关注了解。

-

JDK 厂商占比

Oracle JDKOpen JDK 加起来占比将近 60%,其中 Oracle JDK 占比略多一些,Oracle JDKOpen JDK 都是市场上的热门选择,我们看看二者之间的一些差异。Oracle JDK 更多的关注稳定性,更适合企业级用户,而 Open JDK 相对而言没有那么稳定,它会经常发布一些新特性。Oracle JDK 支持长期发布的更改,而 Open JDK 仅支持计划和完成下一个发行版,还有一个就是 Oracle JDK 是根据 二进制代码许可协议 获得许可,而 Open JDK 是根据 GPL v2 许可获得许可。使用 Oracle 平台时会产生一些许可影响。如 Oracle 宣布的那样,在没有商业许可的情况下,在 2019 年 1 月之后发布的 Oracle Java SE 8 的公开更新将无法用于商业,商业或生产用途。但是,Open JDK 是完全开源的,可以自由使用。

+

前言

现在流行的微服务体系结构正在改变我们构建应用程序的方式,从单一的单体服务转变为越来越小的可单独部署的服务(称为微服务),共同构成了我们的应用程序。当进行一个业务时不可避免就会存在多个服务之间调用,假如一个服务 A 要访问在另一台服务器部署的服务 B,那么前提是服务 A 要知道服务 B 所在机器的 IP 地址和服务对应的端口,最简单的方式就是让服务 A 自己去维护一份服务 B 的配置(包含 IP 地址和端口等信息),但是这种方式有几个明显的缺点:随着我们调用服务数量的增加,配置文件该如何维护;缺乏灵活性,如果服务 B 改变 IP 地址或者端口,服务 A 也要修改相应的文件配置;还有一个就是进行服务的动态扩容或缩小不方便。
一个比较好的解决方案就是 服务发现(Service Discovery)。它抽象出来了一个注册中心,当一个新的服务上线时,它会将自己的 IP 和端口注册到注册中心去,会对注册的服务进行定期的心跳检测,当发现服务状态异常时将其从注册中心剔除下线。服务 A 只要从注册中心中获取服务 B 的信息即可,即使当服务 B 的 IP 或者端口变更了,服务 A 也无需修改,从一定程度上解耦了服务。服务发现目前业界有很多开源的实现,比如 apachezookeeperNetflixeurekahashicorpconsulCoreOSetcd

- + 阅读全文 »
@@ -513,7 +523,7 @@

- +

-

+

@@ -659,14 +669,11 @@

-

前言

在互联网时代,我们的应用都是分布式系统,部署在 N 台机器上。说到分布式系统我们就不得不说分布式系统的祖先——集中式系统。它和分布式系统是两个完全相反的概念,集中式系统就是把所有的程序和功能都放到一台主机上,从而对外提供服务。集中式系统的优点就是容易理解、维护方便,它的的弊端也很明显,如果这个主机出故障了那么整个系统就崩溃了。著名投资家巴菲特有个关于投资的名言:

-
-

不要把鸡蛋放在一个篮子里

-
-

对于我们的系统而言也是如此,我们不可能保证主机永远不坏、也无法保证自己的程序永远不会出 bug,所以问题是无法避免的,我们只能把“鸡蛋”分散到不同的“篮子”里,降低系统出故障的风险,这就是我们为什么需要分布式系统的原因之一。使用分布式系统的另一个理由就是扩展性,毕竟单台主机都会有性能的极限,分布式系统可以通过增加主机数量来实现横向水平性能的扩展。接下来我们看看分布式系统中的一个基本定理——CAP定理

+

前言

做过 Java 开发的同学都知道,JVM(Java 虚拟机)Java 实现的基础,虽然在平时工作中真正运用到的时候可能并不多,但是一个程序员想要上升到高级层次,那就必须知道 Java 到底是怎么运行的,这就有必要去学习了解 JVM 的相关知识了。学习 JVM 可以能更深入的理解 Java 这门语言,可以清楚知道Java程序是如何执行的以及为未来排查线上问题打下坚实的基础。接下来我们看看 2020 年的 JVM 生态报告和最新趋势,值得我们每个 Java 开发者去关注了解。

+

JDK 厂商占比

Oracle JDKOpen JDK 加起来占比将近 60%,其中 Oracle JDK 占比略多一些,Oracle JDKOpen JDK 都是市场上的热门选择,我们看看二者之间的一些差异。Oracle JDK 更多的关注稳定性,更适合企业级用户,而 Open JDK 相对而言没有那么稳定,它会经常发布一些新特性。Oracle JDK 支持长期发布的更改,而 Open JDK 仅支持计划和完成下一个发行版,还有一个就是 Oracle JDK 是根据 二进制代码许可协议 获得许可,而 Open JDK 是根据 GPL v2 许可获得许可。使用 Oracle 平台时会产生一些许可影响。如 Oracle 宣布的那样,在没有商业许可的情况下,在 2019 年 1 月之后发布的 Oracle Java SE 8 的公开更新将无法用于商业,商业或生产用途。但是,Open JDK 是完全开源的,可以自由使用。

- + 阅读全文 »
@@ -719,7 +726,7 @@

前言 - +

@@ -876,11 +872,14 @@

-

前言

相信做 Java 开发的朋友们绝大部分人应该都是用 IntelliJ IDEA 作为开发工具,没用过的朋友们建议将你的开发工具换成这个,关于它的优点可以去 Google 一下,我之前都是用 Eclipse 作为开发工具,自从用过一次 IDEA 之后就再也回不去了。。。今天早上更新(作死)了一下 IDEA 到最新版(2019.3.1),安装完毕之后进入就提示说之前的激活码失效了,经过一顿搜索之后终于成功激活了,在此记录一下激活过程。

-

start_welcome.png

+

前言

在互联网时代,我们的应用都是分布式系统,部署在 N 台机器上。说到分布式系统我们就不得不说分布式系统的祖先——集中式系统。它和分布式系统是两个完全相反的概念,集中式系统就是把所有的程序和功能都放到一台主机上,从而对外提供服务。集中式系统的优点就是容易理解、维护方便,它的的弊端也很明显,如果这个主机出故障了那么整个系统就崩溃了。著名投资家巴菲特有个关于投资的名言:

+
+

不要把鸡蛋放在一个篮子里

+
+

对于我们的系统而言也是如此,我们不可能保证主机永远不坏、也无法保证自己的程序永远不会出 bug,所以问题是无法避免的,我们只能把“鸡蛋”分散到不同的“篮子”里,降低系统出故障的风险,这就是我们为什么需要分布式系统的原因之一。使用分布式系统的另一个理由就是扩展性,毕竟单台主机都会有性能的极限,分布式系统可以通过增加主机数量来实现横向水平性能的扩展。接下来我们看看分布式系统中的一个基本定理——CAP定理

- + 阅读全文 »
@@ -933,7 +932,7 @@

前言 - +

@@ -1079,14 +1089,11 @@

-

前言

在上篇 Java 反射机制(一) 介绍了一些 Java 反射相关的常用 API ,在知道了如何去使用反射之后,作为一个合格的工程师,下一步肯定是要去了解它的如何实现的,我们今天就来看看在 JDK 源码中是如何去实现反射的(PS:以下源码分析基于 JDK1.8)。

-

Field 类 set 方法的实现

Field 类的 set 方法是在运行时用来动态修改一个类的属性的值,进入到 Field 类的 set 方法的源码如下:

-
1
2
3
4
5
6
7
8
9
10
11
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
getFieldAccessor(obj).set(obj, value);
}
- -

首先根据 override 判断是否需要检查字段的访问权限,然后通过 getFieldAccessor 方法获得一个 FieldAccessor 字段访问者对象,最后调用的是 FieldAccessor 类的 set 方法进行下一步操作的,FieldAccessor 是一个接口,定义了对字段的一些操作,该接口有如下一些实现类:

+

前言

相信做 Java 开发的朋友们绝大部分人应该都是用 IntelliJ IDEA 作为开发工具,没用过的朋友们建议将你的开发工具换成这个,关于它的优点可以去 Google 一下,我之前都是用 Eclipse 作为开发工具,自从用过一次 IDEA 之后就再也回不去了。。。今天早上更新(作死)了一下 IDEA 到最新版(2019.3.1),安装完毕之后进入就提示说之前的激活码失效了,经过一顿搜索之后终于成功激活了,在此记录一下激活过程。

+

start_welcome.png

- + 阅读全文 »
@@ -1139,7 +1146,7 @@

- +

-

+

@@ -1285,11 +1292,14 @@

-

前言

Java 中有两种方式可以让我们在运行时识别对象和类的信息。一种是 RTTI(运行时类型识别:Run-Time Type Identification),它假定了我们在编译时已经知道了所有的类型;另一种是我们本文要说的反射机制,它允许我们在运行时获取和使用类的信息。无论是 RTTI 还是反射,其本质都是一样的,都是去动态的获取类的信息。它们唯一不同的是,RTTI 在编译时期知道要解析的类型,而反射是在运行时才知道要解析的类型。

-

反射概述

反射就是把 Java 类中的各个部分(属性、方法、构造方法等)映射成一个个对象。Class 类与 java.lang.reflect 类库一起对反射的概念提供了支持,类库中包含了 FieldMethodConstructor 类,每个类都实现了 Member 接口。这些类型的对象都是由 JVM 运行时创建的,用来表示未知类里对应的成员。这样我们就可以使用 Constructor 创建新的对象,用 getset 方法读取和修改类中与 Field 对象关联的字段,用 invoke 方法调用类中与 Method 对象关联的方法等。
Java 反射机制是在运行状态中的,对于任意一个类我们可以通过反射获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。重要的是,要认识到反射机制并没有什么特别之处,当我们通过反射和一个未知类型的对象打交道时,JVM 只是简单的对这个对象做检查,看它属于哪个类,在用它做其它事情之前必须先加载那个类 Class 对象。所以那个类的字节码文件对象对于 JVM 来说必须是可获取的,要么在本地机器上,要么通过网络获取。

+

前言

在上篇 Java 反射机制(一) 介绍了一些 Java 反射相关的常用 API ,在知道了如何去使用反射之后,作为一个合格的工程师,下一步肯定是要去了解它的如何实现的,我们今天就来看看在 JDK 源码中是如何去实现反射的(PS:以下源码分析基于 JDK1.8)。

+

Field 类 set 方法的实现

Field 类的 set 方法是在运行时用来动态修改一个类的属性的值,进入到 Field 类的 set 方法的源码如下:

+
1
2
3
4
5
6
7
8
9
10
11
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
getFieldAccessor(obj).set(obj, value);
}
+ +

首先根据 override 判断是否需要检查字段的访问权限,然后通过 getFieldAccessor 方法获得一个 FieldAccessor 字段访问者对象,最后调用的是 FieldAccessor 类的 set 方法进行下一步操作的,FieldAccessor 是一个接口,定义了对字段的一些操作,该接口有如下一些实现类:

- + 阅读全文 »
@@ -1342,7 +1352,7 @@

- +

-

+

@@ -1477,47 +1498,11 @@

-

1.1 前言

作为 Java 后端开发的我们,开发的项目绝大部分都是部署在 Linux 系统上的,因此熟练使用一些常用的 Linux 命令不管是对于日常开发、服务部署或者查找问题都非常有用。以下整理了一些常用的 Linux 常用命令。

-

1.2 文件管理

1.2.1 ls 命令

ls 命令是 Linux 最常用的命令之一,其功能是列出指定目录下的内容及其相关属性信息。默认状态下,ls 命令会列出当前目录的内容,它也可以带上一些参数来实现更多的功能。
语法格式:ls [选项] [文件]
常用参数

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
参数描述
-a显示所有文件及目录(包括以 . 开头的隐藏文件)
-l使用长格式列出文件及目录
-r将文件以相反次序显示(默认按照英文字母次序)
-t根据最后的修改时间排序
-A-a,但是不列出 .(当前目录)以及 ..(父级目录)
-S根据文件大小排序
-R递归列出所有子目录
+

前言

Java 中有两种方式可以让我们在运行时识别对象和类的信息。一种是 RTTI(运行时类型识别:Run-Time Type Identification),它假定了我们在编译时已经知道了所有的类型;另一种是我们本文要说的反射机制,它允许我们在运行时获取和使用类的信息。无论是 RTTI 还是反射,其本质都是一样的,都是去动态的获取类的信息。它们唯一不同的是,RTTI 在编译时期知道要解析的类型,而反射是在运行时才知道要解析的类型。

+

反射概述

反射就是把 Java 类中的各个部分(属性、方法、构造方法等)映射成一个个对象。Class 类与 java.lang.reflect 类库一起对反射的概念提供了支持,类库中包含了 FieldMethodConstructor 类,每个类都实现了 Member 接口。这些类型的对象都是由 JVM 运行时创建的,用来表示未知类里对应的成员。这样我们就可以使用 Constructor 创建新的对象,用 getset 方法读取和修改类中与 Field 对象关联的字段,用 invoke 方法调用类中与 Method 对象关联的方法等。
Java 反射机制是在运行状态中的,对于任意一个类我们可以通过反射获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。重要的是,要认识到反射机制并没有什么特别之处,当我们通过反射和一个未知类型的对象打交道时,JVM 只是简单的对这个对象做检查,看它属于哪个类,在用它做其它事情之前必须先加载那个类 Class 对象。所以那个类的字节码文件对象对于 JVM 来说必须是可获取的,要么在本地机器上,要么通过网络获取。

- + 阅读全文 »
@@ -1570,7 +1555,7 @@

- +

-

+

@@ -1716,11 +1690,47 @@

-

简介

在上篇 Java 多线程基础(一) 我们提到了一些线程的常用方法,这篇我们具体看看其中一些方法的使用以及方法的区别,让我们在工作中更好的使用。

-

wait 方法与 notify 方法

Object 类中定义了 wait 方法和 notify 方法,wait 方法的作用是让当前线程进入等待状态,将当前线程置入 预执行队列,会在 wait 方法所在代码处停止执行,直到被通知或者被中断,在调用 wait 方法之前,线程必须获取该对象的锁,因此只能在同步方法或者同步代码块中调用 wait 方法,并且该方法会释放当前线程锁持有的锁。notify 方法是唤醒在当前对象上等待的单个线程,如果有多个线程等待,那么线程调度器会挑出一个 wait 的线程,对其发出 notify ,并使它等待获取该对象的对象锁,这意味着,即使收到了通知,线程也不会立即获取到对象锁,必须等待 notify 方法的线程释放锁才可以。和 wait 方法一样,notify 方法也只能在同步方法或者同步代码块中调用。它还有个相似的方法 notifyAll,它的作用是唤醒在当前对象上等待的所有线程

+

1.1 前言

作为 Java 后端开发的我们,开发的项目绝大部分都是部署在 Linux 系统上的,因此熟练使用一些常用的 Linux 命令不管是对于日常开发、服务部署或者查找问题都非常有用。以下整理了一些常用的 Linux 常用命令。

+

1.2 文件管理

1.2.1 ls 命令

ls 命令是 Linux 最常用的命令之一,其功能是列出指定目录下的内容及其相关属性信息。默认状态下,ls 命令会列出当前目录的内容,它也可以带上一些参数来实现更多的功能。
语法格式:ls [选项] [文件]
常用参数

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数描述
-a显示所有文件及目录(包括以 . 开头的隐藏文件)
-l使用长格式列出文件及目录
-r将文件以相反次序显示(默认按照英文字母次序)
-t根据最后的修改时间排序
-A-a,但是不列出 .(当前目录)以及 ..(父级目录)
-S根据文件大小排序
-R递归列出所有子目录
- + 阅读全文 »
@@ -1773,7 +1783,7 @@

- +

-

+

@@ -1919,12 +1929,11 @@

-

简介

在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

-

进程与线程的区别

进程

进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

-
线程

线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

+

简介

在上篇 Java 多线程基础(一) 我们提到了一些线程的常用方法,这篇我们具体看看其中一些方法的使用以及方法的区别,让我们在工作中更好的使用。

+

wait 方法与 notify 方法

Object 类中定义了 wait 方法和 notify 方法,wait 方法的作用是让当前线程进入等待状态,将当前线程置入 预执行队列,会在 wait 方法所在代码处停止执行,直到被通知或者被中断,在调用 wait 方法之前,线程必须获取该对象的锁,因此只能在同步方法或者同步代码块中调用 wait 方法,并且该方法会释放当前线程锁持有的锁。notify 方法是唤醒在当前对象上等待的单个线程,如果有多个线程等待,那么线程调度器会挑出一个 wait 的线程,对其发出 notify ,并使它等待获取该对象的对象锁,这意味着,即使收到了通知,线程也不会立即获取到对象锁,必须等待 notify 方法的线程释放锁才可以。和 wait 方法一样,notify 方法也只能在同步方法或者同步代码块中调用。它还有个相似的方法 notifyAll,它的作用是唤醒在当前对象上等待的所有线程

- + 阅读全文 »
@@ -1977,7 +1986,7 @@
线程 - +
@@ -2123,12 +2132,12 @@

-

简介

在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

-

线程池如何处理提交的任务

我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
+

简介

在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

+

进程与线程的区别

进程

进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

+
线程

线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

- + 阅读全文 »
@@ -2181,7 +2190,7 @@

- +

-

+

@@ -2327,17 +2336,12 @@

-

线程池简介

使用线程池可以很好的提高性能,线程池在运行之初就会创建一定数量的空闲线程,我们将一个任务提交给线程池,线程池就会使用一个空闲的线程来执行这个任务,该任务执行完后,该线程不会死亡,而是再次变成空闲状态返回线程池,等待下一个任务的到来。在使用线程池时,我们把要执行的任务提交给整个线程池,而不是提交给某个线程,线程池拿到提交的任务后,会在内部寻找是否还有空闲的线程,如果有,就将这个任务提交给某个空闲的线程,虽然一个线程同一时刻只能执行一个任务,但是我们可以向线程池提交多个任务。合理使用线程池有以下几个优点:
降低资源消耗 多线程运行期间,系统不断的启动和关闭新线程,成本高,会过度消耗系统资源,通过重用存在的线程,减少对象创建、消亡的开销
提高响应速度 当有任务到达时,任务可以不需要等待线程的创建,可以直接从线程池中取出空闲的线程来执行任务
方便线程管理 线程对计算机来说是很稀缺的资源,如果让他无限制创建,它不仅消耗系统的资源,还会降低系统的稳定性,我们使用线程池后可以统一进行分配和监控
谈到线程池就会想到池化技术,核心思想就是把宝贵的资源放到一个池子中,每次要使用都从池子里面取,用完之后又放回池子让别人用。那么线程池在 Java 中是如何实现的呢?

-

Java 四种线程池

在 Java 中 Executors 工具类给我们提供了四种不同使用场景的线程池的创建方法,分别为:

-
    -
  1. newSingleThreadExecutor 只有一个线程来执行任务,适用于有顺序的任务的应用场景。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,它可以保证任务按照指定顺序(FIFO,LIFO)执行,它还有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为
  2. -
  3. newFixedThreadPool 固定线程数的线程池,只有核心线程,核心线程的即为最大的线程数量,没有非核心线程。每次提交一个任务就创建一个线程,直到达到线程池的最大大小。线程池一旦达到最大值就会保持不变,如果当中的某个线程因为异常而结束,那么线程池会新建一个线程加入到线程池中。它还可以控制线程的最大并发数,超出的线程会在阻塞队列(LinkedBlockingQueue)中等待,同样它也有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为。
  4. -
  5. newCachedThreadPool 创建一个可缓存线程池,最大的线程个数为 2^31 - 1(Integer.MAX_VALUE),可以认为是无限大,若无可回收,则新建线程,如果线程池的大小超出了处理任务所需要的线程,那么就会回收部分空闲(60s 不执行任务)的线程。
  6. -
  7. newScheduledThreadPool 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大(Integer.MAX_VALUE:2^31 - 1),适用于执行周期性的任务。
  8. -
+

简介

在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

+

线程池如何处理提交的任务

我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
- + 阅读全文 »
@@ -2429,7 +2433,7 @@

- 27 + 28 日志 @@ -2440,7 +2444,7 @@

- 27 + 29 分类 @@ -2451,7 +2455,7 @@

- 25 + 26 标签 diff --git a/page/3/index.html b/page/3/index.html index c8e8f53d..cc1c97d3 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -305,6 +305,215 @@

Java 搬运工 & 终身学习 +
+ + + +
+ + + + + + + +
+ + + +

+ +

+ + + +
+ + + + + +
+ + + + + + +

线程池简介

使用线程池可以很好的提高性能,线程池在运行之初就会创建一定数量的空闲线程,我们将一个任务提交给线程池,线程池就会使用一个空闲的线程来执行这个任务,该任务执行完后,该线程不会死亡,而是再次变成空闲状态返回线程池,等待下一个任务的到来。在使用线程池时,我们把要执行的任务提交给整个线程池,而不是提交给某个线程,线程池拿到提交的任务后,会在内部寻找是否还有空闲的线程,如果有,就将这个任务提交给某个空闲的线程,虽然一个线程同一时刻只能执行一个任务,但是我们可以向线程池提交多个任务。合理使用线程池有以下几个优点:
降低资源消耗 多线程运行期间,系统不断的启动和关闭新线程,成本高,会过度消耗系统资源,通过重用存在的线程,减少对象创建、消亡的开销
提高响应速度 当有任务到达时,任务可以不需要等待线程的创建,可以直接从线程池中取出空闲的线程来执行任务
方便线程管理 线程对计算机来说是很稀缺的资源,如果让他无限制创建,它不仅消耗系统的资源,还会降低系统的稳定性,我们使用线程池后可以统一进行分配和监控
谈到线程池就会想到池化技术,核心思想就是把宝贵的资源放到一个池子中,每次要使用都从池子里面取,用完之后又放回池子让别人用。那么线程池在 Java 中是如何实现的呢?

+

Java 四种线程池

在 Java 中 Executors 工具类给我们提供了四种不同使用场景的线程池的创建方法,分别为:

+
    +
  1. newSingleThreadExecutor 只有一个线程来执行任务,适用于有顺序的任务的应用场景。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,它可以保证任务按照指定顺序(FIFO,LIFO)执行,它还有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为
  2. +
  3. newFixedThreadPool 固定线程数的线程池,只有核心线程,核心线程的即为最大的线程数量,没有非核心线程。每次提交一个任务就创建一个线程,直到达到线程池的最大大小。线程池一旦达到最大值就会保持不变,如果当中的某个线程因为异常而结束,那么线程池会新建一个线程加入到线程池中。它还可以控制线程的最大并发数,超出的线程会在阻塞队列(LinkedBlockingQueue)中等待,同样它也有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为。
  4. +
  5. newCachedThreadPool 创建一个可缓存线程池,最大的线程个数为 2^31 - 1(Integer.MAX_VALUE),可以认为是无限大,若无可回收,则新建线程,如果线程池的大小超出了处理任务所需要的线程,那么就会回收部分空闲(60s 不执行任务)的线程。
  6. +
  7. newScheduledThreadPool 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大(Integer.MAX_VALUE:2^31 - 1),适用于执行周期性的任务。
  8. +
+ +
+ + 阅读全文 » + +
+ + + +
+ + + + + + + + + + + + +
+ + + + + + + + +
+ +
+
+ + + +
+ + + + + + + + + + +
@@ -1776,7 +1985,7 @@

- 27 + 28 日志 @@ -1787,7 +1996,7 @@

@@ -1798,7 +2007,7 @@

diff --git a/post/102cd3d9.html b/post/102cd3d9.html index ba54d588..35bf1c11 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -847,7 +847,7 @@

总结 - 27 + 28 日志 @@ -858,7 +858,7 @@

总结 - 27 + 29 分类 @@ -869,7 +869,7 @@

总结 - 25 + 26 标签 diff --git a/post/11cb7677.html b/post/11cb7677.html index 8d629673..764b9c81 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -698,7 +698,7 @@

总结 - 27 + 28 日志 @@ -709,7 +709,7 @@

总结 - 27 + 29 分类 @@ -720,7 +720,7 @@

总结 - 25 + 26 标签 diff --git a/post/192cb539.html b/post/192cb539.html index 54390332..cb96d9ea 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -762,7 +762,7 @@

- 27 + 28 日志 @@ -773,7 +773,7 @@

@@ -784,7 +784,7 @@

diff --git a/post/24042edf.html b/post/24042edf.html index 772c74e8..bb2f92cb 100644 --- a/post/24042edf.html +++ b/post/24042edf.html @@ -770,7 +770,7 @@

总结 - 27 + 28 日志 @@ -781,7 +781,7 @@

总结 - 27 + 29 分类 @@ -792,7 +792,7 @@

总结 - 25 + 26 标签 diff --git a/post/34755d6c.html b/post/34755d6c.html index 3925b2b1..733180db 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -677,7 +677,7 @@

总结 - 27 + 28 日志 @@ -688,7 +688,7 @@

总结 - 27 + 29 分类 @@ -699,7 +699,7 @@

总结 - 25 + 26 标签 diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index 7ffbef05..065cbac5 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -744,7 +744,7 @@

总结 - 27 + 28 日志 @@ -755,7 +755,7 @@

总结 - 27 + 29 分类 @@ -766,7 +766,7 @@

总结 - 25 + 26 标签 diff --git a/post/4615256d.html b/post/4615256d.html index b6e0f929..8d96d47c 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -753,7 +753,7 @@

- 27 + 28 日志 @@ -764,7 +764,7 @@

- 27 + 29 分类 @@ -775,7 +775,7 @@

- 25 + 26 标签 diff --git a/post/4b00e13c.html b/post/4b00e13c.html index 9a256371..61522fea 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -761,6 +761,10 @@

总结 + + @@ -848,7 +852,7 @@

总结 - 27 + 28 日志 @@ -859,7 +863,7 @@

总结 - 27 + 29 分类 @@ -870,7 +874,7 @@

总结 - 25 + 26 标签 diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index e68d8342..e5341103 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -685,7 +685,7 @@

总结 - 27 + 28 日志 @@ -696,7 +696,7 @@

总结 - 27 + 29 分类 @@ -707,7 +707,7 @@

总结 - 25 + 26 标签 diff --git a/post/51e5bd99.html b/post/51e5bd99.html index 32f611ab..54ca8908 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -726,7 +726,7 @@

- 27 + 28 日志 @@ -737,7 +737,7 @@

- 27 + 29 分类 @@ -748,7 +748,7 @@

- 25 + 26 标签 diff --git a/post/710bd10b.html b/post/710bd10b.html index 6fc9e60e..574d8211 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -732,7 +732,7 @@

总结 - 27 + 28 日志 @@ -743,7 +743,7 @@

总结 - 27 + 29 分类 @@ -754,7 +754,7 @@

总结 - 25 + 26 标签 diff --git a/post/7528c810.html b/post/7528c810.html index 41e96702..2a9f9e80 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -715,7 +715,7 @@

总结 - 27 + 28 日志 @@ -726,7 +726,7 @@

总结 - 27 + 29 分类 @@ -737,7 +737,7 @@

总结 - 25 + 26 标签 diff --git a/post/7b9ead86.html b/post/7b9ead86.html index a5b25325..9c9372cf 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -715,7 +715,7 @@

总结 - 27 + 28 日志 @@ -726,7 +726,7 @@

总结 - 27 + 29 分类 @@ -737,7 +737,7 @@

总结 - 25 + 26 标签 diff --git a/post/7eb2637f.html b/post/7eb2637f.html index b19d2db9..d7281c57 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -754,7 +754,7 @@

- 27 + 28 日志 @@ -765,7 +765,7 @@

- 27 + 29 分类 @@ -776,7 +776,7 @@

- 25 + 26 标签 diff --git a/post/817c7d82.html b/post/817c7d82.html index 8beb9c7d..a1b9c49f 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1323,7 +1323,7 @@

- 27 + 28 日志 @@ -1334,7 +1334,7 @@
- 27 + 29 分类 @@ -1345,7 +1345,7 @@
- 25 + 26 标签 diff --git a/post/8a061473.html b/post/8a061473.html index 1b1b7c1f..4bf9da9b 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -791,7 +791,7 @@
- 27 + 28 日志 @@ -802,7 +802,7 @@
- 27 + 29 分类 @@ -813,7 +813,7 @@
- 25 + 26 标签 diff --git a/post/8bd965a0.html b/post/8bd965a0.html index 3c062480..bc80c43c 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -714,7 +714,7 @@

- 27 + 28 日志 @@ -725,7 +725,7 @@

@@ -736,7 +736,7 @@

diff --git a/post/99ea2970.html b/post/99ea2970.html index 8a6221da..f2083271 100644 --- a/post/99ea2970.html +++ b/post/99ea2970.html @@ -710,7 +710,7 @@

- 27 + 28 日志 @@ -721,7 +721,7 @@

@@ -732,7 +732,7 @@

diff --git a/post/a38c0645.html b/post/a38c0645.html index e46d02cb..8a247fd6 100644 --- a/post/a38c0645.html +++ b/post/a38c0645.html @@ -694,7 +694,7 @@

总结 - 27 + 28 日志 @@ -705,7 +705,7 @@

总结 - 27 + 29 分类 @@ -716,7 +716,7 @@

总结 - 25 + 26 标签 diff --git a/post/ab706eb5.html b/post/ab706eb5.html index aa0991dd..c24a6c12 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -697,7 +697,7 @@

总结 - 27 + 28 日志 @@ -708,7 +708,7 @@

总结 - 27 + 29 分类 @@ -719,7 +719,7 @@

总结 - 25 + 26 标签 diff --git a/post/b1d4025b.html b/post/b1d4025b.html index d5a48a48..fe2417f6 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -627,7 +627,7 @@

hello world

- 27 + 28 日志 @@ -638,7 +638,7 @@

hello world

@@ -649,7 +649,7 @@

hello world

diff --git a/post/bc557e1a.html b/post/bc557e1a.html index 86812f53..1aeb2ca0 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -762,7 +762,7 @@
- 27 + 28 日志 @@ -773,7 +773,7 @@
- 27 + 29 分类 @@ -784,7 +784,7 @@
- 25 + 26 标签 diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index 5b997c1c..529bb949 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -714,7 +714,7 @@

- 27 + 28 日志 @@ -725,7 +725,7 @@

@@ -736,7 +736,7 @@

diff --git a/post/c34b451f.html b/post/c34b451f.html new file mode 100644 index 00000000..a61d3d3b --- /dev/null +++ b/post/c34b451f.html @@ -0,0 +1,1648 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RabbitMQ 入门之基础概念 | mghio + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

RabbitMQ 入门之基础概念

+ + + +
+ + + + + +
+ + + + + +

什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

+

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作这份出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

+ +

RabbitMQ 的特点

RabbitMQ 是一个由 Relang 语言开发的 AMQP 的开源实现。AMQP(Advanced Message Queue:高级消息度列协议)它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。RabbitMQ 最初起源于消息系统,用于在分布式系统中存储转发消息,具体有如下一些特点:

+
    +
  • 可靠性: RabbitMQ 使用一些机制来保证可靠性,比如持久化、传输确认机制(ack)和发布确认等。
  • +
  • 灵活的路由策略: 在消息进入队列之前,通过 Exchange 来路由消息,对于典型的路由功能,RabbitMQ 已经提供了一些内置的 Exchange 来实现。针对复杂的路由功能,可以将多个 Exchange 绑在一起,也通过插件机制实现自己的 Exchange。
  • +
  • 消息集群: 多个 RabbitMQ 服务器可以组成一个集群,形成一个逻辑 Broker。
  • +
  • 高可用: 队列可以在集群中的集群上进行镜像,使得在部分节点出问题的情况下队列仍然可用。
  • +
  • 多种协议: RabbitMQ 支持多种消息队列协议,比如 STOMP、MQTT 等。
  • +
  • 多语言客户端: RabbitMQ 几乎支持多有常用的语言,比如:Java、.NET 等
  • +
  • 管理界面: RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker 的许多方面。
  • +
+

RabbitMQ 安装(mac)和运行

1、安装
因为 RabbitMQ 依赖于 Erlang 语言,所以在安装 RabbitMQ 之前需要先安装 Erlang 环境,但是由于是 Mac 环境,可以使用 HomeBrew 安装,安装前先更新 brew:

+
1
brew update
+ +

接着安装 RabbitMQ 即可,安装过程中会自动安装其所依赖的 Erlang。

+

rabbitmq-base-7.jpeg

+

2、运行
RabbitMQ 的启动运行很简单,找到其安装目录后(使用 Homwbrew 安装的默认目录为:/usr/local/Cellar/rabbitmq),进入到目录的 sbin 目录下,可以看到有 6 个
以 rabbitmq 开头的可执行文件,直接执行 rabbitmq-server 即可。

+

rabbitmq-base-8.jpeg

+

启动正常的话可以看到启动过程的日志信息和最后的 completed with 6 plugins,这也说明启动的时候默认加载了 6 个插件。

+

rabbitmq-base-9.jpeg

+

此时通过浏览器访问 http://localhost:15672 可以看到其管理界面(默认用户名和密码都是 guest),可以在 admin 选项卡页面新增用户,管理界面如下:

+

rabbitmq-base-10.jpeg

+

PS: 以上方式不是后台启动,如果想让 RabbitMQ 后台守护进程的方式启动的话,可以在启动的时候加上 -detached 参数。

+

rabbitmq-base-11.jpeg

+

3、查询服务器状态
在安装目录的 sbin 下面有个可执行文件 rabbitmqctl ,它提供了 RabbitMQ 管理需要的几乎一站式解决方案,绝大部分的运维命令它都可以提供。查询 RabbitMQ 服务器的状态信息可以用参数 status。

+

rabbitmq-base-12.jpeg

+

RabbitMQ 中的基础概念

1、消息模型 几乎所有的 MQ 抽象来说都是一样的过程:消费者订阅某个队列,生产者生产消息,然后发布到队列中,最后将消息发送到监听该队列的消费者那里。如下图所示:

+

rabbitmq-base-1.jpeg

+

2、基本概念 上面上一个消息队列的抽象概述,具体到 RabbitMQ 有一些特有的概念,RabbitMQ 是 AMQP 协议的一个开源实现,其内部概念大都是 AMQP 协议的一些概念。

+

rabbitmq-base-2.jpeg

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
名称描述
Message 消息消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则是由一系列的可选属性组成,这些属性包括 routing-key(路由键)、priority(相对于其它消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。
Publisher 消息生产者一个向交换机发送消息的客户端应用程序。
Exchange 交换器用来接收生产者发送过来的消息,并将这些消息发送给服务器中的队列。
Binding 绑定用于消息队列和交换器之间的关联,一个绑定就是一个基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。
Queue 消息队列用来保存消息直到发送给消费者,它是消息的容器,也是消息的终点,一个消息可投入一个或多个队列,消息一直在队列里面,等待消费者连接到这个队列并将其取走。
Connection 网络连接比如一个 TCP 连接。
Channel 信道多路复用连接中的一条独立双向数据流通道,信道是建立在真实 TCP 连接内的虚拟连接,AMQP 命令都是通过信道发送出去的,不管是发布消息、订阅消息还是接收消息,这些动作都是通过信道完成的。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。
Consumer 消息的消费者一个从消息队列中获取消息的客户端应用程序。
Virtual Host 虚拟主机表示一批交换器、消息队列和相关对象。虚拟主机是共享相同身份认证和加密环境的对服务器域。每个 vhost 本质上是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。
+

3、AMQP 中的消息路由 AMQP 中消息路由过程和 Java 开发者熟悉的 JMS 存在一些差别,AMQP 中增加了 Exchange 和 Binding 的角色。生产者把消息发送到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发到哪个队列。

+

rabbitmq-base-3.jpeg

+

4、Exchange 类型 Exchange 分发消息时根据类型的不同分发策略略有区别,目前共有四种类型:direct、fanout、topic、headers。headers 匹配 AMQP 消息的 header 而不是路由键,此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了,所以直接看另外三种类型即可。

+

4.1、direct 类型

+

rabbitmq-base-4.jpeg

+

消息中的路由键(routing key)如果和 Binding 中的 binding key 一致,交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为 “dog”,则只转发 routing key 标记为 “dog” 的消息,不会转发 “dog.puppy”,也不会转发 “dog.guard” 等等。它是完全匹配、单播的模式。

+

4.2、fanout 类型

+

rabbitmq-base-5.jpeg

+

每个发到 fanout 类型交换机的消息都会发到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得一份复制的消息。fanout 类型转发消息是最快的。

+

3、topic 类型

+

rabbitmq-base-6.jpeg

+

topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上,它将路由键和绑定的字符串切分成单词,这些单词之间用点隔开。它同样也识别两个通配符:符号 “#” 和符号 “*”。# 符号匹配 0 个或多个单词,* 符号匹配不多不少一个单词。

+

总结

本文主要讲了关于 RabbitMQ 的安装以及基础概念的相关介绍,由于它是基于 Erlang 语言开发,可能对于部分 Java 开发者想了解其底层实现细节以及排查比较复杂的问题时不是很友好。

+ + +
+ + + + + +
+
-------------本文结束感谢您的阅读-------------
+
+ + + +
+
+ mghio wechat +
微信公众号「mghio」
+
+ +
+ + + +
+
+
请我吃🍗
+ + +
+ +
+ + + +
+ +
+ + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ +
+
+ + + + + +
+ + + + + + + + + +
+
+ +
+ +
+ + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/post/e09f0428.html b/post/e09f0428.html index d46242ee..0391a2bb 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -684,7 +684,7 @@

- 27 + 28 日志 @@ -695,7 +695,7 @@

- 27 + 29 分类 @@ -706,7 +706,7 @@

- 25 + 26 标签 diff --git a/post/ee27c07f.html b/post/ee27c07f.html index d68819bb..6e4aa7c0 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -677,7 +677,7 @@

- 27 + 28 日志 @@ -688,7 +688,7 @@

@@ -699,7 +699,7 @@

diff --git a/post/f440d00b.html b/post/f440d00b.html index 40879e4b..767ec228 100644 --- a/post/f440d00b.html +++ b/post/f440d00b.html @@ -713,7 +713,7 @@

总结 - 27 + 28 日志 @@ -724,7 +724,7 @@

总结 - 27 + 29 分类 @@ -735,7 +735,7 @@

总结 - 25 + 26 标签 diff --git a/post/fe76043.html b/post/fe76043.html index f7fc2132..3976d3bf 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -680,7 +680,7 @@

总结 - 27 + 28 日志 @@ -691,7 +691,7 @@

总结 - 27 + 29 分类 @@ -702,7 +702,7 @@

总结 - 25 + 26 标签 diff --git a/search.xml b/search.xml index 6c539a58..877fc10c 100644 --- a/search.xml +++ b/search.xml @@ -1,5 +1,18 @@ + + <![CDATA[RabbitMQ 入门之基础概念]]> + %2Fpost%2Fc34b451f.html + + + RabbitMQ + Java + + + Java + RabbitMQ + + <![CDATA[Java 中队列同步器 AQS(AbstractQueuedSynchronizer)实现原理]]> %2Fpost%2F4b00e13c.html diff --git a/sitemap.xml b/sitemap.xml index abeac4cb..0de9bbff 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,13 @@ + + https://www.mghio.cn/post/c34b451f.html + + 2020-07-18T09:39:48.484Z + + + https://www.mghio.cn/post/4b00e13c.html diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index f46f39fb..283edda4 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index 47c8a548..eb2a978f 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index dd833361..e7ee1fd8 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/GC/index.html b/tags/GC/index.html index 09183944..5f6c2887 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/Guava/index.html b/tags/Guava/index.html index 8a4d2b46..6ebac23e 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index 4f41a332..2cff0b03 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index 048e88fb..5d01e900 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/JDK/index.html b/tags/JDK/index.html index cf8194cb..a27acbde 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/JVM/index.html b/tags/JVM/index.html index e7fc6395..9898210a 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -412,7 +412,7 @@

- 27 + 28 日志 @@ -423,7 +423,7 @@

@@ -434,7 +434,7 @@

diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index 9a9d33cd..f02fa11a 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index a80a6019..f3d4aab5 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/Java/index.html b/tags/Java/index.html index 8138bda9..b656117e 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -624,7 +624,7 @@

- 27 + 28 日志 @@ -635,7 +635,7 @@

@@ -646,7 +646,7 @@

diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index 67217a5e..fde425d6 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -624,7 +624,7 @@

- 27 + 28 日志 @@ -635,7 +635,7 @@

@@ -646,7 +646,7 @@

diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index 94b55180..6e74a781 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -442,7 +468,7 @@

- 27 + 28 日志 @@ -453,7 +479,7 @@

@@ -464,7 +490,7 @@

diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index 2e8a6ef0..45bdcf24 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/RabbitMQ/index.html b/tags/RabbitMQ/index.html new file mode 100644 index 00000000..a3acef55 --- /dev/null +++ b/tags/RabbitMQ/index.html @@ -0,0 +1,1253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: RabbitMQ | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/String/index.html b/tags/String/index.html index e96a2ef6..a16ab91b 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/index.html b/tags/index.html index f733ba49..2ec0c6b1 100644 --- a/tags/index.html +++ b/tags/index.html @@ -317,10 +317,10 @@

@@ -378,7 +378,7 @@

- 27 + 28 日志 @@ -389,7 +389,7 @@

@@ -400,7 +400,7 @@

diff --git a/tags/mockito/index.html b/tags/mockito/index.html index 43a44bf2..1205192b 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/test/index.html b/tags/test/index.html index affa3bd9..89d44377 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 9c31d549..ef875f20 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index 5819623d..d16c7944 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -412,7 +412,7 @@

- 27 + 28 日志 @@ -423,7 +423,7 @@

@@ -434,7 +434,7 @@

diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 6fee346f..764ba8f6 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -412,7 +412,7 @@

- 27 + 28 日志 @@ -423,7 +423,7 @@

@@ -434,7 +434,7 @@

diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index ddb5e1bc..72eb2533 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index 42e0e619..a179fb78 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -412,7 +412,7 @@

- 27 + 28 日志 @@ -423,7 +423,7 @@

@@ -434,7 +434,7 @@

diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index 8b0bf32f..5d7cebe6 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index a61a0f29..b372ef81 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 5c88c78a..a5943e90 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index e2aa7a2f..c8009660 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -386,7 +386,7 @@

- 27 + 28 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

From 0808cf5a26af9aed4d9fd2a3048557bad0feb559 Mon Sep 17 00:00:00 2001 From: maguihai Date: Sat, 18 Jul 2020 18:10:56 +0800 Subject: [PATCH 05/19] Site updated: 2020-07-18 18:10:56 --- atom.xml | 8 ++++---- css/main.css | 2 +- index.html | 2 +- post/c34b451f.html | 6 +++--- search.xml | 2 +- sitemap.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/atom.xml b/atom.xml index 64026fa3..e3a38101 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2020-07-18T09:39:48.484Z + 2020-07-18T10:10:37.869Z https://www.mghio.cn/ @@ -21,14 +21,14 @@ https://www.mghio.cn/post/c34b451f.html 2020-07-18T09:00:51.000Z - 2020-07-18T09:39:48.484Z + 2020-07-18T10:10:37.869Z - 什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作这份出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

RabbitMQ 的特点

RabbitMQ 是一个由 Relang 语言开发的 AMQP 的开源实现。AMQP(Advanced Message Queue:高级消息度列协议)它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。RabbitMQ 最初起源于消息系统,用于在分布式系统中存储转发消息,具体有如下一些特点:

  • 可靠性: RabbitMQ 使用一些机制来保证可靠性,比如持久化、传输确认机制(ack)和发布确认等。
  • 灵活的路由策略: 在消息进入队列之前,通过 Exchange 来路由消息,对于典型的路由功能,RabbitMQ 已经提供了一些内置的 Exchange 来实现。针对复杂的路由功能,可以将多个 Exchange 绑在一起,也通过插件机制实现自己的 Exchange。
  • 消息集群: 多个 RabbitMQ 服务器可以组成一个集群,形成一个逻辑 Broker。
  • 高可用: 队列可以在集群中的集群上进行镜像,使得在部分节点出问题的情况下队列仍然可用。
  • 多种协议: RabbitMQ 支持多种消息队列协议,比如 STOMP、MQTT 等。
  • 多语言客户端: RabbitMQ 几乎支持多有常用的语言,比如:Java、.NET 等
  • 管理界面: RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker 的许多方面。

RabbitMQ 安装(mac)和运行

1、安装
因为 RabbitMQ 依赖于 Erlang 语言,所以在安装 RabbitMQ 之前需要先安装 Erlang 环境,但是由于是 Mac 环境,可以使用 HomeBrew 安装,安装前先更新 brew:

1
brew update

接着安装 RabbitMQ 即可,安装过程中会自动安装其所依赖的 Erlang。

rabbitmq-base-7.jpeg

2、运行
RabbitMQ 的启动运行很简单,找到其安装目录后(使用 Homwbrew 安装的默认目录为:/usr/local/Cellar/rabbitmq),进入到目录的 sbin 目录下,可以看到有 6 个
以 rabbitmq 开头的可执行文件,直接执行 rabbitmq-server 即可。

rabbitmq-base-8.jpeg

启动正常的话可以看到启动过程的日志信息和最后的 completed with 6 plugins,这也说明启动的时候默认加载了 6 个插件。

rabbitmq-base-9.jpeg

此时通过浏览器访问 http://localhost:15672 可以看到其管理界面(默认用户名和密码都是 guest),可以在 admin 选项卡页面新增用户,管理界面如下:

rabbitmq-base-10.jpeg

PS: 以上方式不是后台启动,如果想让 RabbitMQ 后台守护进程的方式启动的话,可以在启动的时候加上 -detached 参数。

rabbitmq-base-11.jpeg

3、查询服务器状态
在安装目录的 sbin 下面有个可执行文件 rabbitmqctl ,它提供了 RabbitMQ 管理需要的几乎一站式解决方案,绝大部分的运维命令它都可以提供。查询 RabbitMQ 服务器的状态信息可以用参数 status。

rabbitmq-base-12.jpeg

RabbitMQ 中的基础概念

1、消息模型 几乎所有的 MQ 抽象来说都是一样的过程:消费者订阅某个队列,生产者生产消息,然后发布到队列中,最后将消息发送到监听该队列的消费者那里。如下图所示:

rabbitmq-base-1.jpeg

2、基本概念 上面上一个消息队列的抽象概述,具体到 RabbitMQ 有一些特有的概念,RabbitMQ 是 AMQP 协议的一个开源实现,其内部概念大都是 AMQP 协议的一些概念。

rabbitmq-base-2.jpeg

名称描述
Message 消息消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则是由一系列的可选属性组成,这些属性包括 routing-key(路由键)、priority(相对于其它消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。
Publisher 消息生产者一个向交换机发送消息的客户端应用程序。
Exchange 交换器用来接收生产者发送过来的消息,并将这些消息发送给服务器中的队列。
Binding 绑定用于消息队列和交换器之间的关联,一个绑定就是一个基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。
Queue 消息队列用来保存消息直到发送给消费者,它是消息的容器,也是消息的终点,一个消息可投入一个或多个队列,消息一直在队列里面,等待消费者连接到这个队列并将其取走。
Connection 网络连接比如一个 TCP 连接。
Channel 信道多路复用连接中的一条独立双向数据流通道,信道是建立在真实 TCP 连接内的虚拟连接,AMQP 命令都是通过信道发送出去的,不管是发布消息、订阅消息还是接收消息,这些动作都是通过信道完成的。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。
Consumer 消息的消费者一个从消息队列中获取消息的客户端应用程序。
Virtual Host 虚拟主机表示一批交换器、消息队列和相关对象。虚拟主机是共享相同身份认证和加密环境的对服务器域。每个 vhost 本质上是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。

3、AMQP 中的消息路由 AMQP 中消息路由过程和 Java 开发者熟悉的 JMS 存在一些差别,AMQP 中增加了 Exchange 和 Binding 的角色。生产者把消息发送到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发到哪个队列。

rabbitmq-base-3.jpeg

4、Exchange 类型 Exchange 分发消息时根据类型的不同分发策略略有区别,目前共有四种类型:direct、fanout、topic、headers。headers 匹配 AMQP 消息的 header 而不是路由键,此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了,所以直接看另外三种类型即可。

4.1、direct 类型

rabbitmq-base-4.jpeg

消息中的路由键(routing key)如果和 Binding 中的 binding key 一致,交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为 “dog”,则只转发 routing key 标记为 “dog” 的消息,不会转发 “dog.puppy”,也不会转发 “dog.guard” 等等。它是完全匹配、单播的模式。

4.2、fanout 类型

rabbitmq-base-5.jpeg

每个发到 fanout 类型交换机的消息都会发到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得一份复制的消息。fanout 类型转发消息是最快的。

3、topic 类型

rabbitmq-base-6.jpeg

topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上,它将路由键和绑定的字符串切分成单词,这些单词之间用点隔开。它同样也识别两个通配符:符号 “#” 和符号 “*”。# 符号匹配 0 个或多个单词,* 符号匹配不多不少一个单词。

总结

本文主要讲了关于 RabbitMQ 的安装以及基础概念的相关介绍,由于它是基于 Erlang 语言开发,可能对于部分 Java 开发者想了解其底层实现细节以及排查比较复杂的问题时不是很友好。

]]> + 什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

RabbitMQ 的特点

RabbitMQ 是一个由 Relang 语言开发的 AMQP 的开源实现。AMQP(Advanced Message Queue:高级消息队列协议)它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。RabbitMQ 最初起源于消息系统,用于在分布式系统中存储转发消息,具体有如下一些特点:

  • 可靠性: RabbitMQ 使用一些机制来保证可靠性,比如持久化、传输确认机制(ack)和发布确认等。
  • 灵活的路由策略: 在消息进入队列之前,通过 Exchange 来路由消息,对于典型的路由功能,RabbitMQ 已经提供了一些内置的 Exchange 来实现。针对复杂的路由功能,可以将多个 Exchange 绑在一起,也通过插件机制实现自己的 Exchange。
  • 消息集群: 多个 RabbitMQ 服务器可以组成一个集群,形成一个逻辑 Broker。
  • 高可用: 队列可以在集群中的集群上进行镜像,使得在部分节点出问题的情况下队列仍然可用。
  • 多种协议: RabbitMQ 支持多种消息队列协议,比如 STOMP、MQTT 等。
  • 多语言客户端: RabbitMQ 几乎支持多有常用的语言,比如:Java、.NET 等
  • 管理界面: RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker 的许多方面。

RabbitMQ 安装(mac)和运行

1、安装
因为 RabbitMQ 依赖于 Erlang 语言,所以在安装 RabbitMQ 之前需要先安装 Erlang 环境,但是由于是 Mac 环境,可以使用 HomeBrew 安装,安装前先更新 brew:

1
brew update

接着安装 RabbitMQ 即可,安装过程中会自动安装其所依赖的 Erlang。

rabbitmq-base-7.jpeg

2、运行
RabbitMQ 的启动运行很简单,找到其安装目录后(使用 Homwbrew 安装的默认目录为:/usr/local/Cellar/rabbitmq),进入到目录的 sbin 目录下,可以看到有 6 个
以 rabbitmq 开头的可执行文件,直接执行 rabbitmq-server 即可。

rabbitmq-base-8.jpeg

启动正常的话可以看到启动过程的日志信息和最后的 completed with 6 plugins,这也说明启动的时候默认加载了 6 个插件。

rabbitmq-base-9.jpeg

此时通过浏览器访问 http://localhost:15672 可以看到其管理界面(默认用户名和密码都是 guest),可以在 admin 选项卡页面新增用户,管理界面如下:

rabbitmq-base-10.jpeg

PS: 以上方式不是后台启动,如果想让 RabbitMQ 后台守护进程的方式启动的话,可以在启动的时候加上 -detached 参数。

rabbitmq-base-11.jpeg

3、查询服务器状态
在安装目录的 sbin 下面有个可执行文件 rabbitmqctl ,它提供了 RabbitMQ 管理需要的几乎一站式解决方案,绝大部分的运维命令它都可以提供。查询 RabbitMQ 服务器的状态信息可以用参数 status。

rabbitmq-base-12.jpeg

RabbitMQ 中的基础概念

1、消息模型 几乎所有的 MQ 抽象来说都是一样的过程:消费者订阅某个队列,生产者生产消息,然后发布到队列中,最后将消息发送到监听该队列的消费者那里。如下图所示:

rabbitmq-base-1.jpeg

2、基本概念 上面上一个消息队列的抽象概述,具体到 RabbitMQ 有一些特有的概念,RabbitMQ 是 AMQP 协议的一个开源实现,其内部概念大都是 AMQP 协议的一些概念。

rabbitmq-base-2.jpeg

名称描述
Message 消息消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则是由一系列的可选属性组成,这些属性包括 routing-key(路由键)、priority(相对于其它消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。
Publisher 消息生产者一个向交换机发送消息的客户端应用程序。
Exchange 交换器用来接收生产者发送过来的消息,并将这些消息发送给服务器中的队列。
Binding 绑定用于消息队列和交换器之间的关联,一个绑定就是一个基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。
Queue 消息队列用来保存消息直到发送给消费者,它是消息的容器,也是消息的终点,一个消息可投入一个或多个队列,消息一直在队列里面,等待消费者连接到这个队列并将其取走。
Connection 网络连接比如一个 TCP 连接。
Channel 信道多路复用连接中的一条独立双向数据流通道,信道是建立在真实 TCP 连接内的虚拟连接,AMQP 命令都是通过信道发送出去的,不管是发布消息、订阅消息还是接收消息,这些动作都是通过信道完成的。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。
Consumer 消息的消费者一个从消息队列中获取消息的客户端应用程序。
Virtual Host 虚拟主机表示一批交换器、消息队列和相关对象。虚拟主机是共享相同身份认证和加密环境的对服务器域。每个 vhost 本质上是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。

3、AMQP 中的消息路由 AMQP 中消息路由过程和 Java 开发者熟悉的 JMS 存在一些差别,AMQP 中增加了 Exchange 和 Binding 的角色。生产者把消息发送到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发到哪个队列。

rabbitmq-base-3.jpeg

4、Exchange 类型 Exchange 分发消息时根据类型的不同分发策略略有区别,目前共有四种类型:direct、fanout、topic、headers。headers 匹配 AMQP 消息的 header 而不是路由键,此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了,所以直接看另外三种类型即可。

4.1、direct 类型

rabbitmq-base-4.jpeg

消息中的路由键(routing key)如果和 Binding 中的 binding key 一致,交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为 “dog”,则只转发 routing key 标记为 “dog” 的消息,不会转发 “dog.puppy”,也不会转发 “dog.guard” 等等。它是完全匹配、单播的模式。

4.2、fanout 类型

rabbitmq-base-5.jpeg

每个发到 fanout 类型交换机的消息都会发到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得一份复制的消息。fanout 类型转发消息是最快的。

3、topic 类型

rabbitmq-base-6.jpeg

topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上,它将路由键和绑定的字符串切分成单词,这些单词之间用点隔开。它同样也识别两个通配符:符号 “#” 和符号 “*”。# 符号匹配 0 个或多个单词,* 符号匹配不多不少一个单词。

总结

本文主要讲了关于 RabbitMQ 的安装以及基础概念的相关介绍,由于它是基于 Erlang 语言开发,可能对于部分 Java 开发者想了解其底层实现细节以及排查比较复杂的问题时不是很友好。

]]> <h4 id="什么是消息队列(MQ)"><a href="#什么是消息队列(MQ)" class="headerlink" title="什么是消息队列(MQ)"></a>什么是消息队列(MQ)</h4><p>消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。</p> -<h4 id="什么场景下考虑使用消息队列"><a href="#什么场景下考虑使用消息队列" class="headerlink" title="什么场景下考虑使用消息队列"></a>什么场景下考虑使用消息队列</h4><p>从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作这份出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。</p> +<h4 id="什么场景下考虑使用消息队列"><a href="#什么场景下考虑使用消息队列" class="headerlink" title="什么场景下考虑使用消息队列"></a>什么场景下考虑使用消息队列</h4><p>从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。</p> diff --git a/css/main.css b/css/main.css index e30a6646..d008c953 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #95fabe; + background: #fff; } .links-of-blogroll { font-size: 13px; diff --git a/index.html b/index.html index 137f5ab7..a3bdde2c 100644 --- a/index.html +++ b/index.html @@ -457,7 +457,7 @@

什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

-

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作这份出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

+

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

diff --git a/post/c34b451f.html b/post/c34b451f.html index a61d3d3b..b8a48bf7 100644 --- a/post/c34b451f.html +++ b/post/c34b451f.html @@ -114,7 +114,7 @@ - + @@ -472,9 +472,9 @@

RabbitMQ 入门之基础概念什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

-

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作这份出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

+

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

-

RabbitMQ 的特点

RabbitMQ 是一个由 Relang 语言开发的 AMQP 的开源实现。AMQP(Advanced Message Queue:高级消息度列协议)它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。RabbitMQ 最初起源于消息系统,用于在分布式系统中存储转发消息,具体有如下一些特点:

+

RabbitMQ 的特点

RabbitMQ 是一个由 Relang 语言开发的 AMQP 的开源实现。AMQP(Advanced Message Queue:高级消息队列协议)它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。RabbitMQ 最初起源于消息系统,用于在分布式系统中存储转发消息,具体有如下一些特点:

  • 可靠性: RabbitMQ 使用一些机制来保证可靠性,比如持久化、传输确认机制(ack)和发布确认等。
  • 灵活的路由策略: 在消息进入队列之前,通过 Exchange 来路由消息,对于典型的路由功能,RabbitMQ 已经提供了一些内置的 Exchange 来实现。针对复杂的路由功能,可以将多个 Exchange 绑在一起,也通过插件机制实现自己的 Exchange。
  • diff --git a/search.xml b/search.xml index 877fc10c..cd641bee 100644 --- a/search.xml +++ b/search.xml @@ -3,7 +3,7 @@ <![CDATA[RabbitMQ 入门之基础概念]]> %2Fpost%2Fc34b451f.html - + RabbitMQ Java diff --git a/sitemap.xml b/sitemap.xml index 0de9bbff..4fed7c7d 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -4,7 +4,7 @@ https://www.mghio.cn/post/c34b451f.html - 2020-07-18T09:39:48.484Z + 2020-07-18T10:10:37.869Z From e4c98f013b5e4b5d1ac082e6f6f9d8dcbb53850f Mon Sep 17 00:00:00 2001 From: maguihai Date: Sun, 9 Aug 2020 22:44:45 +0800 Subject: [PATCH 06/19] Site updated: 2020-08-09 22:44:44 --- about/index.html | 2 +- archives/2019/10/index.html | 4 +- archives/2019/11/index.html | 4 +- archives/2019/12/index.html | 4 +- archives/2019/index.html | 4 +- archives/2019/page/2/index.html | 4 +- archives/2020/01/index.html | 4 +- archives/2020/02/index.html | 4 +- archives/2020/03/index.html | 4 +- archives/2020/04/index.html | 4 +- archives/2020/05/index.html | 4 +- archives/2020/06/index.html | 4 +- archives/2020/07/index.html | 4 +- archives/2020/08/index.html | 1273 +++++++++++++ archives/2020/index.html | 74 +- archives/2020/page/2/index.html | 39 +- archives/index.html | 74 +- archives/page/2/index.html | 74 +- archives/page/3/index.html | 39 +- atom.xml | 57 +- baidusitemap.xml | 3 + categories/JDK/Java/index.html | 2 +- .../index.html" | 2 +- categories/JDK/index.html | 2 +- categories/Java/Bloom-filter/index.html | 2 +- categories/Java/GC/index.html | 2 +- categories/Java/Guava/String/index.html | 2 +- categories/Java/Guava/index.html | 2 +- categories/Java/IDEA/index.html | 2 +- .../IDEA/\345\267\245\345\205\267/index.html" | 2 +- .../IO\346\250\241\345\236\213/index.html" | 2 +- categories/Java/JVM/index.html | 2 +- categories/Java/index.html | 2 +- categories/Java/page/2/index.html | 2 +- categories/Java/page/3/index.html | 2 +- categories/Java/unit-test/index.html | 2 +- categories/Java/unit-test/mockito/index.html | 2 +- .../Java/\345\216\237\347\220\206/index.html" | 2 +- .../Java/\345\217\215\345\260\204/index.html" | 2 +- .../index.html" | 2 +- .../Java/\345\271\266\345\217\221/index.html" | 2 +- .../\350\277\233\351\230\266/index.html" | 2 +- .../Java/\345\274\202\346\255\245/index.html" | 2 +- .../Eureka/index.html" | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- .../Java/\351\207\215\346\236\204/index.html" | 2 +- .../Linux\347\254\224\350\256\260/index.html" | 2 +- categories/RabbitMQ/Java/index.html | 28 +- categories/RabbitMQ/index.html | 28 +- categories/index.html | 4 +- .../CAP\345\256\232\347\220\206/index.html" | 2 +- .../index.html" | 2 +- css/main.css | 2 +- index.html | 320 ++-- page/2/index.html | 409 +++-- page/3/index.html | 206 ++- post/102cd3d9.html | 2 +- post/11cb7677.html | 2 +- post/192cb539.html | 2 +- post/24042edf.html | 2 +- post/34755d6c.html | 2 +- post/3ae0ff4e.html | 2 +- post/4615256d.html | 2 +- post/4b00e13c.html | 2 +- post/4ea48fa7.html | 2 +- post/51e5bd99.html | 2 +- post/710bd10b.html | 2 +- post/7528c810.html | 2 +- post/7b9ead86.html | 2 +- post/7eb2637f.html | 2 +- post/817c7d82.html | 2 +- post/8a061473.html | 2 +- post/8bd965a0.html | 2 +- post/99ea2970.html | 2 +- post/a38c0645.html | 2 +- post/ab706eb5.html | 2 +- post/b1d4025b.html | 2 +- post/bc557e1a.html | 2 +- post/bfcdfeaf.html | 2 +- post/c34b451f.html | 6 +- post/e09f0428.html | 2 +- post/ee27c07f.html | 2 +- post/f440d00b.html | 2 +- post/f92758d8.html | 1596 +++++++++++++++++ post/fe76043.html | 2 +- search.xml | 13 + sitemap.xml | 7 + tags/Bloom-filter/index.html | 2 +- "tags/CAP\345\256\232\347\220\206/index.html" | 2 +- tags/Eureka/index.html | 2 +- tags/GC/index.html | 2 +- tags/Guava/index.html | 2 +- tags/IDEA/index.html | 2 +- "tags/IO\346\250\241\345\236\213/index.html" | 2 +- tags/JDK/index.html | 2 +- tags/JVM/index.html | 2 +- .../Java-\345\216\237\347\220\206/index.html" | 2 +- .../Java-\345\271\266\345\217\221/index.html" | 2 +- tags/Java/index.html | 54 +- tags/Java/page/2/index.html | 54 +- tags/Java/page/3/index.html | 28 +- .../Linux\347\254\224\350\256\260/index.html" | 2 +- tags/RabbitMQ/index.html | 28 +- tags/String/index.html | 2 +- tags/index.html | 4 +- tags/mockito/index.html | 2 +- tags/test/index.html | 2 +- .../index.html" | 2 +- "tags/\345\217\215\345\260\204/index.html" | 2 +- .../index.html" | 2 +- "tags/\345\267\245\345\205\267/index.html" | 2 +- "tags/\345\271\266\345\217\221/index.html" | 2 +- "tags/\345\274\202\346\255\245/index.html" | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- "tags/\351\207\215\346\236\204/index.html" | 2 +- 117 files changed, 3952 insertions(+), 678 deletions(-) create mode 100644 archives/2020/08/index.html create mode 100644 post/f92758d8.html diff --git a/about/index.html b/about/index.html index a76302eb..8fbc24a2 100644 --- a/about/index.html +++ b/about/index.html @@ -408,7 +408,7 @@

    - 28 + 29 日志

diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html index 08295829..5a67fb20 100644 --- a/archives/2019/10/index.html +++ b/archives/2019/10/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -546,7 +546,7 @@

- 28 + 29 日志 diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html index 96894eb9..a197ab6b 100644 --- a/archives/2019/11/index.html +++ b/archives/2019/11/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 28 + 29 日志 diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html index 508edbd6..be46cb26 100644 --- a/archives/2019/12/index.html +++ b/archives/2019/12/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 28 + 29 日志 diff --git a/archives/2019/index.html b/archives/2019/index.html index 3582bb1d..7727188a 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -725,7 +725,7 @@

- 28 + 29 日志 diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html index 07fe2b26..8d9d8d3f 100644 --- a/archives/2019/page/2/index.html +++ b/archives/2019/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -480,7 +480,7 @@

- 28 + 29 日志 diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html index 5ff2cab7..542ad18d 100644 --- a/archives/2020/01/index.html +++ b/archives/2020/01/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -441,7 +441,7 @@

- 28 + 29 日志 diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html index fcbbc696..7dda8e34 100644 --- a/archives/2020/02/index.html +++ b/archives/2020/02/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -406,7 +406,7 @@

- 28 + 29 日志 diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index e0d1bee1..4c89c97e 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 28 + 29 日志 diff --git a/archives/2020/04/index.html b/archives/2020/04/index.html index 0f75ee38..9a1c0c2f 100644 --- a/archives/2020/04/index.html +++ b/archives/2020/04/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 28 + 29 日志 diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index 56d35f22..2076e1ab 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -441,7 +441,7 @@

- 28 + 29 日志 diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html index e52279bd..40230772 100644 --- a/archives/2020/06/index.html +++ b/archives/2020/06/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -406,7 +406,7 @@

- 28 + 29 日志 diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html index 1a3a0be5..74e6e3f4 100644 --- a/archives/2020/07/index.html +++ b/archives/2020/07/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -406,7 +406,7 @@

- 28 + 29 日志 diff --git a/archives/2020/08/index.html b/archives/2020/08/index.html new file mode 100644 index 00000000..f8ffa264 --- /dev/null +++ b/archives/2020/08/index.html @@ -0,0 +1,1273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/index.html b/archives/2020/index.html index 332807d5..31727d1c 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -633,41 +668,6 @@

- - - - - - - - - - - - - - - @@ -725,7 +725,7 @@

- 28 + 29 日志 diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html index 0a408207..1e84f192 100644 --- a/archives/2020/page/2/index.html +++ b/archives/2020/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -550,7 +585,7 @@

- 28 + 29 日志 diff --git a/archives/index.html b/archives/index.html index a29ae69e..a92c7020 100644 --- a/archives/index.html +++ b/archives/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -633,41 +668,6 @@

- - - - - - - - - - - - - - - @@ -725,7 +725,7 @@

- 28 + 29 日志 diff --git a/archives/page/2/index.html b/archives/page/2/index.html index c0636388..8ceb0a64 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -638,41 +673,6 @@

- - - - - - - - - - - - - - - @@ -730,7 +730,7 @@

- 28 + 29 日志 diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 5f6ae2ab..107bcd6e 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 28 篇日志。 继续努力。 + 嗯..! 目前共计 29 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2019

+ + + + + + + + + + + + + + +
@@ -655,7 +690,7 @@

- 28 + 29 日志 diff --git a/atom.xml b/atom.xml index e3a38101..015be2d3 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2020-07-18T10:10:37.869Z + 2020-08-09T14:44:05.879Z https://www.mghio.cn/ @@ -16,6 +16,34 @@ Hexo + + RabbitMQ 基础概念进阶 + + https://www.mghio.cn/post/f92758d8.html + 2020-08-09T14:28:00.000Z + 2020-08-09T14:44:05.879Z + + 上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

消息生产者发送的消息不可达时如何处理

RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

1.1 mandatory 参数

mandatory 被定义在 RabbitMQ 提供的客户端的 channel.basicPublish 方法中,如下所示:

rabbitmq_advanced_1.png

当把方法的 mandatory 参数设置为 true 时,那么会在交换器无法根据自身的类型和路由键找到一个符合要求的队列时,RabbitMQ 会自动调用 Basic.Return 把该消息回传给发送方也就是我们的消息生产者。反之,如果设置为 false 的话,消息就会被直接丢弃掉。那么问题来了,我们要如何去获取这些没有被发送出去的消息呢?RabbitMQ 给我们提供了事件监听机制来获取这种消息,可以通过 addReturnListener 方法添加一个 ReturnListener 来获取这种未发送到队列的消息,如下所示:

rabbitmq_advanced_2.png

通过查看 ReturnListener 接口的源码可以看到,该接口只有一个方法,如果是 JDK8+ 的版本的话可以使用 Lambda 表达式来简化一些代码。

可以看出,当设置了 mandatory 参数时,还必须为生产者同时添加 ReturnListener 监听器的编程逻辑,这样就会使得生产者的代码变得更加复杂了,为了处理这种情况,RabbitMQ 提供了 备份交换器 来将没有成功路由出去的消息存储起来,当我们需要的时候再去处理即可。

1.2 immediate 参数

该的参数同样也是在channel.basicPublish 方法中定义的,其官方描述如下:

This flag tells the server how to react if the message cannot be routed to a queue consumer immediately. If this flag is set, the server will return an undeliverable message with a Return method. If this flag is zero, the server will queue the message, but with no guarantee that it will ever be consumed.

当把 immediate 参数设置为 true 时,如果交换器根据其类型和路由键找到符合要求的队列时,发现所有队列上没有任何消费者,则该消息并不会存入到队列中,会通过 Basic.Return 命令把消息回传给生产者。简而言之也就是说,当设置了 immediate 参数时,该消息关联的队列上存在消费者时,会立即发送消息到该队列中,反之如果匹配的队列上不存在任何消费者,则直接把消息回传给生产者。这里有一点需要注意的是:从 RabbitMQ 3.0 + 已经去除了该参数。

如何对消息和队列设置过期时间 (TTL)

TTL 是 time to live 首字母的简称,RabbitMQ 中可以设置消息和队列的过期时间,我们先来看看要如何设置消息的过期时间。

1.1 消息 TTL 设置

RabbitMQ 提供了两种设置消息的过期时间,第一种是通过队列的属性设置,该方式的特点就是队列中所有消息的过期时间都一致。还有一种是更小粒度的设置,就是对每条消息单独设置过期时间,这种方式更加灵活,每条消息的过期时间都可以不一样。这是你可能会问,如果同时设置了队列的过期属性和消息本身的过期属性,最终以哪个为准呢?结果是 RabbitMQ 会比较这两个 TTL 的值大小,以较小的那个为准。很容易想到,通过队列的属性的方式设置过期时间的话是在声明队列的时候指定,对应到客户端就是其提供的 channel.queueDeclare 方法的参数 arguments 指定,示例代码如下:

rabbitmq_advanced_3.png

需要注意的是 x-message-ttl 参数的单位是毫秒。如果不设置 TLL,则表示该消息不会过期,如果将 TTL 设置为 0,表示除非此时可以把消息直接发送投递到消费者端去,否则就会直接丢弃该消息。

准对每条消息设置 TTL 的方法是在发送消息的时候设置的,对应到客户端方法是 channel.basicPublish 的 expiration 属性参数,具体设置代码如下:

rabbitmq_advanced_4.png

这种设置方式,即使队列过期也不会立即从队列中移除,因为每条消息是否过期的判定是在发送到消费者是才进行的,如果此时发现已经过期才会删除消息。而对于第一种方式则会把已经过期的消息移到队列头部,然后 RabbitMQ 只要定期的从头开始扫描是否存在过期的消息即可。

1.2 队列 TTL 设置

设置队列的过期时间使用的是客户端的 channel.queueDeclare 方法参数中的 x-expires 参数,其单位同样也是毫秒,不过需要注意的是它不能设置为 0。设置队列过期的代码如下所示:

rabbitmq_advanced_5.png

上面代码创建了一个过期时间为 15 分钟的队列。

死信队列介绍

死信交换器(DLX)的全称是 Dead-Letter-Exchange ,也称之为死信邮箱。简单来说就是当一个消息由于 消息被拒绝消息过期队列达到最大长度 时,变成死信(dead message)之后,会被重新发送到一个交换器中,这个交换器就是死信交换器,绑定在这个交换器上的队列就称之为死信队列。死信交换器实际上就是平常的交换器,可以在任何队列上指定,当在一个队列上设置死信交换器后,如果该队列出现死信时就会被 RabbitMQ 把死信消息重新发送到死信交换器上去,然后路由到死信队列中,我们可以监听这个队列来处理那些死信消息。为一个队列设置死信交换器是在生产者的声明队列的方法中设置 x-dead-letter-message 参数来实现的,如下所示:

rabbitmq_advanced_6.png

同时也可以通过 x-dead-letter-routing-key 参数设置死信交互器的路由键,不设置默认使用原始度列的路由键。可以到 RabbitMQ 的后台管理界面,有 DLX 标志的就是死信队列。

rabbitmq_advanced_7.png

RabbitMQ 提供的 DLX 是个比较实用的功能特性,它可以在我们消息不能被消费者正确消费的情况下放入到死信队列,后续我们可以通过这个死信队列的内容来查看异常情况来改造和优化系统。

延迟队列介绍

顾名思义,延迟队列存储的是哪些需要等待指定时间后才能拿到的延迟消息,一个比较典型的场景就是订单 30 分钟后未支付取消订单。这里需要注意的是,在 RabbitMQ 中并没有直接提供延迟队列的功能,而是需要通过上面介绍的过期时间(TTL)和死信队列一起来实现,比如超时取消订单这个场景,我们可以让消费者订阅死信队列,设置正常的那个队列的超时时间为 30 分钟并绑定到该死信队列上,当消息超过 30 分钟未被处理后消息就会把发送到死信队列中,然后死信队列的消费者就可以在 30 分钟后成功的消费到该消息了。

rabbitmq_advanced_8.png

同时当我们有其它的超时配置需求时也很方便扩展,比如可以在生产者发送消息的时候通过设置不同的路由键,通过路由键来将消息发送到与交换器绑定的不同队列中,然后这些队列分别设置不同的过期时间和与之相对应的死信队列,当消息过期时就会被 RabbitMQ 转发到相应的死信队列中,这样就可以去订阅相应的死信队列即可。

交换器、消息和队列持久化

持久化可以提高可靠性,可以防止宕机或者重启等异常下数据的丢失,RabbitMQ 的持久化从组成结构上可以分为三个部分,即交换器持久化、消息持久化和队列持久化。

1.1 交换器持久化

交换器持久化是在声明交换器时将 durable 参数设置为 true 来实现的。如果不设置持久化属性的话,当 RabbitMQ 服务重启后交换器的数据就会丢失,需要注意的是,是交换器的数据丢失,消息不会丢失,只是不能将消息发送到这个交换器中了,一般生产环境使用都会把该属性设置为持久化。

1.2 消息持久化

交换器的持久化仅仅只是保证了交换器本身的元数据不会丢失,无法保证其存储的消息不会丢失,如果需要其内部存储的消息不丢失,则需要设置消息的持久化,通过将消息的投递模式(deliveryMode)设置为 2 即可实现消息的持久化,如下所示:

rabbitmq_advanced_9.png

需要消息持久化的前提是其所在的队列也要设置持久化,假如仅仅只设置消息的持久化的话,RabbitMQ 重启之后队列消失,然后消息也会丢失。这里有点需要注意一下,虽然持久化可以提高可靠性,但是持久化是将数据存储到硬盘上,比直接操作内存要慢很多,所以对于哪些可靠性要求不高的业务不需要进行持久化。

1.3 队列持久化

队列的持久化的设置和交换器持久化类似,同样也是在声明的时候通过 durable 参数设置为 true 实现的,如果不设置,当 RabbitMQ 重启后,相关的队列元数据也会丢失,相应的其存储的消息也会随之丢失掉。

将交换器、队列、消息都设置了持久化之后就能百分之百保证数据不丢失了吗?其实无法保证百分之百数据不丢失。比如消费者在订阅消费队列时将自动应答(autoAck)参数设置为 true 的话,在接收到消息后还没来得及处理就挂了,这时需要把自动应答设置 false,进行手动 ack 应答即可。还有一个就是由于不是实时持久化存盘,当消息存盘的过程中 RabbitMQ 宕机了,此时也会发生数据丢失,此时需要通过 RabbitMQ 的 镜像队列机制 来处理了。

总结

本文主要介绍了一些参数具体使用时的设置细节和死信队列、延迟队列以及持久化等,还有一些比较重要的点没有涉及到,比如消息确认机制。“纸上得来终觉浅,绝知此事要躬行”,在了解一些基础的概念之后还是需要通过具体编码实践才能对其更加理解深刻。

]]>
+ + + + <p>上一篇 <a href="https://www.mghio.cn/post/c34b451f.html">RabbitMQ 入门之基础概念</a> 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。</p> +<h4 id="消息生产者发送的消息不可达时如何处理"><a href="#消息生产者发送的消息不可达时如何处理" class="headerlink" title="消息生产者发送的消息不可达时如何处理"></a>消息生产者发送的消息不可达时如何处理</h4><p>RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 <code>channel.basicPublish</code> 方法的两个参数 <code>mandatory</code> 和 <code>immediate</code> (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。</p> + + + + + + + + + + + + + +
+ RabbitMQ 入门之基础概念 @@ -612,31 +640,4 @@ - - Java 线程池(二) - - https://www.mghio.cn/post/ab706eb5.html - 2019-11-30T08:07:14.000Z - 2019-12-01T04:16:31.573Z - - 简介

在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

线程池如何处理提交的任务

我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}

首先对提交的任务进行判非空指针后,三个方法都是调用 newTaskFor 方法把任务统一封装成 RunnableFuture 对象,然后把封装好的对象作为 execute 方法的入参去执行,而此时 execute 方法还未实现,这个方法是在 AbstractExecutorService 的继承类 ThreadPoolExecutor 中实现。下面看看 newTaskFor 方法是如何封装我们提交的任务的,两个重载方法的源码如下:

1
2
3
4
5
6
7
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}

那么这个 FutureTask 是个什么东东呢,进入其源码发现它实现了 RunnableFuture 接口,而 RunnableFuture 接口的作用正如其名,它是 RunnableFuture 的结合体,表示一个能异步返回结果的线程。我们知道 Runnable 是不能返回结果的,所以上面第一个 newTaskFor(Runnable runnable, T value) 方法的第二个参数 value 的作用就是指定返回结果。其实最后也是通过 RunnableAdapterRunnablevalue 封装成 Callable 的。下面我们看看 execute 方法是怎么处理的,方法源码如下:

thread-pool-3.png

第 ① 步 获取当前的 ctl 值,在上篇 Java 线程池(一) 中说过,变量 ctl 存储了线程池的工作状态 runState 和线程池中正在运行的线程数 workerCount
第 ② 步 通过 workerCountOf 方法取出线程池中当前正在运行的线程数( ctl 低 29 位的值),如果线程池当前工作线程数小于核心线程数 corePoolSize,则进行第 ③ 步。
第 ③ 步 通过 addWorker 方法新建一个线程加到线程池中,addWorker 方法的第二个参数如果为 true 则限制添加线程的数量是根据 corePoolSize 来判断,反之则根据 maximumPoolSize 来判断,并把任务添加到该线程中。
第 ④ 步 如果添加失败,则重新获取 ctl 的值。
第 ⑤ 步 如果当前线程池的状态是运行状态(state < SHUTDOWN)并且把任务成功添加到队列中。
第 ⑥ 步 重新获取 ctl 的值,再次判断线程池的运行状态,如果不是运行状态,要从队列中移除任务,因为到这一步了,意味着之前已经把任务成功添加到队列中了,所以需要从队列移除。移除成功后调用拒绝策略对任务进行处理,整个 execute 方法结束(PS:为什么不在入队列之前就先判断线程池的状态呢?因为判断一个线程池工作处于运行状态到执行入队列操作这段时间,线程池可能已经被其它线程关闭了,所以提前判断其实毫无意义)。
第 ⑦ 步 通过 workerCountOf 方法取出线程池中当前正在运行的线程数( ctl 低 29 位的值),如果是 0 则执行 addWorker(null, false) 方法,第一个参数传 null 表示只是在线程池中创建一个线程出来,但是没有立即启动,因为我们创建线程池时可能要求核心线程数量为 0。第二个参数为 false 表示限制添加线程时根据 maximumPoolSize 来判断,如果当前线程池中正在运行线程数量大于 0 ,则直接返回,因为在上面第 ⑤ 步已经把任务成功添加到队列 workQueue 中,它会在将来的某个时刻执行到。
第 ⑧ 步 如果执行到这个地方,只有两种情况,一种是线程池的状态已经不是运行状态了,另一种是线程池是运行状态,但是此时线程池的工作线程数大于等于核心线程数(workerCount >= corePoolSize)并且队列 workQueue 已满。这时会再次调用 addWorker 方法,第二个参数传的 false,意味着限制添加线程的数量是根据 maximumPoolSize 来判断的,如果失败则调用拒绝策略对任务进行处理,整个 execute 方法结束。
上面的 execute 方法中多次调用 addWorker,该方法的主要作用就是创建一个线程来执行任务。addWorker 的方法签名如下:

1
addWorker(Runnable firstTask, boolean core)

第一个参数 firstTask 如果不为 null,则创建的线程首先执行 firstTask 任务,然后才会从队列中获取任务,否则会直接从队列中获取任务。第二个参数如果为 true,则表示限制添加线程时根据 corePoolSize 来判断,否则根据maximumPoolSize 来判断。我们看看 addWorker 方法的源码,方法源码如下:

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);

// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;

for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}

boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());

if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}

方法首先获取线程池 ctl 属性的值,该属性包含了线程池的运行状态工作线程数,通过 runStateOf 获取线程池的运行状态,然后执行下面这个比较复杂的条件判断

thread-pool-4.png

第 ① 个条件表示此时线程池已经不再接受新任务了,接下来的 ②、③、④ 三个判断条件只要有一个不满足,那么方法就会返回 false,方法结束。第 ② 个条件表示线程池为关闭状态,处于关闭状态的线程池不会处理新提交的任务,但会处理完已处理的任务,第 ③ 个条件为 firstTask 为 null,第 ④ 个条件为队列不为空。我们看看如果线程池此时为关闭状态的情况,这种情况线程池不会接受新提交的任务,所以此时如果传入的 firstTask 不为 null,则会直接返回 false;然后如果 firstTasknull,并且队列 workQueue 为空,此时也会返回 false,因为此时队列里已经没有任务了,那么也不需要再添加线程了,然后接下来会进入一个循环。

thread-pool-5.png

第 ① 步 调用 workerCountOf 方法获取当前线程池的工作线程数
第 ② 步 如果当前线程池的工作数大于 CAPACITY 也就是 ctl 的低 29 位的最大值,则返回 false,如果不大于 CAPACITY,然后根据 core (该方法的第二个参数)来判断是和 corePoolSize 比较还是和 maximumPoolSize 比较,如果比这个值大则返回 false
第 ③ 步 使用 ctlcompareAndSet 原子方法尝试把工作线程数 workerCount + 1,如果增加成功,退出第一层循环。
第 ④ 步 如果增加线程池工作线程数失败,则重新获取 ctl 的值。
第 ⑤ 步 调用 runStateOf 获取线程池的状态,如果不等于方法前面获取的 rs,说明线程池的状态已经改变了,回到第一层循环继续执行。
接下来会启动线程执行任务,源码如下:

thread-pool-6.png

第 ① 步 根据 firstTask 创建 Worker 对象,每一个 Worker 对象都会创建一个线程,然后会使用重入锁 ReentrantLock 进行加锁操作。
第 ② 步 调用 runStateOf 获取线程池的状态,然后进行一个条件判断,第一个 rs < SHUTDOWN 表示线程池是运行状态。如果线程池是运行状态或者线程池是关闭状态并且 firstTasknull,那么就往线程池中加入线程(因为当线程池是 SHUTDOWN 状态时不会再向线程池添加新的任务,但会执行队列 workQueue 中的任务)。这里的 workers 是一个 HashSet,所以其 add 方法不是线程安全的,所以需要加锁操作。然后修改线程池中出现过的最大线程数量 largestPoolSize 记录和把是否添加成功标记 workerAddedtrue。如果 workerAddedtrue 那么会启动线程并把线程是否启动标记 workerStarted 改为 true
第 ③ 步 根据线程是否启动 workerStarted 标记来判断是否需要进行失败的操作。包含从 workers 移除当前的 worker、线程池的工作线程数减 1、尝试终端线程池。

线程池中线程是如何执行的

线程池的线程执行是调用 Workerthread 属性的 start 方法,而 threadrun 方法实际上调用了 Worker 类的 runWorker 方法,所以我们直接来看看 runWorker 方法的源码:

thread-pool-7.png

第 ① 步 获取第一个任务,while 循环不断地通过 getTask 方法从队列中获取任务。
第 ② 步 这个判断条件目的是要保证如果线程池正在停止,要保证当前线程是中断状态,如果是的话,要保证当前线程不是终端状态。
第 ③ 步 方法 beforeExecute 方法在类 ThreadPoolExecutor 中没有做任何操作,是留给子类去自定义在线程执行之前添加操作的方法。
第 ④ 步 执行 task.run() 执行任务(PS:这里为什么是调用 run 方法而不是调用 start 方法呢?我们知道当调用了 start 方法后操作系统才会给我们创建一个独立的线程来运行,而调用 run 方法只是一个普通的方法调用,而线程池正好就是需要它是一个普通的方法才能进行任务的调度。我们可以想象一下,假如这里是调用的 Runnable 的 start 方法,那么会是什么结果呢。如果我们往一个核心线程数、最大线程数为 3 的线程池里丢了 500 个任务,那么它会额外的创建 500 个线程,同时每个任务都是异步执行的,结果一下子就执行完毕了,根本无法对任务进行调度。从而没法做到由这 3 个 Worker 线程来调度这 1000 个任务,而只有当做一个普通的 run 方法调用时才能满足线程池的这个要求)。
第 ⑤ 步 方法 afterExecute 方法在类 ThreadPoolExecutor 中没有做任何操作,是留给子类去自定义在线程执行之后添加操作的方法。completedAbruptly 变量是用来表示在执行任务过程中是否出现了异常,processWorkerExit 方法中会对该变量的值进行判断。
接下来我们看看 getTask 方法是如何从队列中获取任务的,方法源码如下:

thread-pool-8.png

第 ① 步 如果线程池不是运行状态,则判断线程池是否正在停止或者当前队列为空,如果条件满足将线程池的工作线程数减一并返回 null。因为如果当前线程池状态的值是 SHUTDOWN 或以上时,就不允许再向队列中添加任务了。
第 ② 步 这里的 timed 变量用来标记是否需要线程进行超时控制,allowCoreThreadTimeOut 默认是 false,也就是核心线程不允许进行超时。wc > corePoolSize 表示当前线程池中的工作线程数量大于核心线程数量,对于超过核心线程数量的这些线程,需要进行超时控制。
第 ③ 步 第一个判断 wc > maximumPoolSize 如果成立是因为可能在此方法执行阶段同时执行了线程池的 setMaximumPoolSize 方法;第二个判断 timed && timedOut 如果成立表示当前操作需要进行超时控制,并且上次从队列中获取任务发生了超时(timeOut 变量的值表示上次从阻塞队列中取任务时是否超时);第三个判断 wc > 1 || workQueue.isEmpty() 如果线程池中工作线程数量大于 1,或者队列是空的,那么尝试将 workerCount 减一,如果减一失败,则返回重试。如果 wc == 1 时,也就说明当前线程是线程池中唯一的一个线程了。
第 ④ 步 根据 timed 来判断,如果为 true,则通过阻塞队列的 poll 方法进行超时控制,如果在 keepAliveTime 时间内没有获取到任务,则返回 null,否则通过 take 方法,如果这时队列为空,则 take 方法会阻塞直到队列不为空。如果 r == null,说明已经超时,timedOut 设置为 true
第 ⑤ 步 如果获取任务时当前线程发生了中断,则设置 timedOutfalse 并重新循环重试。

关闭线程池

线程池的关闭一般都是使用 shutdown 方法和 shutdownNow 方法,两者的区别是前面的 shutdown 方法不会执行新的任务,但是会执行完当前正在执行的任务,而后面的 shutdownNow 方法会立即停止当前线程池,不管当前是否有线程在执行。一般都是使用 shutdown 方法来停止线程池,其方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}

advanceRunState(SHUTDOWN) 方法的作用是通过 CAS 原子操作将线程池的状态更改为关闭状态。interruptIdleWorkers 方法是对空闲的线程进行中断,其实是调用重载带参数的函数 interruptIdleWorkers(false)。然后 onShutdown 方法和上文提到的 beforeExecuteafterExecute 方法一样,在类 ThreadPoolExecutor 是空实现,也是个钩子函数。我们看看 interruptIdleWorkers 的实现源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}

先进行加锁操作,然后遍历 workers 容器,也就是遍历线程池中的线程,对每个线程进行 tryLock 操作,如果成功说明线程空闲,则设置其中断标志位。而线程是否响应中断则交给我们定义任务的人来决定。

总结

本文比较详细的分析了线程池任务的提交、线程的执行、线程池的关闭的工作流程。通过学习线程池相关的源码后,看到了在其内部用运用了很多多线程的解决方法,有如下几个方式:

  1. 通过定义重入锁 ReentrantLock 变量 mainLock 来解决并发多线程的安全问题
  2. 利用等待机制来实现线程之间的通讯问题
    除了内置的功能外,ThreadPoolExecutor 也向外提供了两个接口供我们自己扩展满足我们需求的线程池,这两个接口分别是:beforeExecute 任务执行前执行的方法,afterExecute 任务执行结束后执行的方法。
]]> - - - - <h4 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h4><p>在上篇 <a href="http://www.mghio.cn/post/bc557e1a.html">Java 线程池(一)</a> 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现<code>线程池</code>的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。</p> -<h4 id="线程池如何处理提交的任务"><a href="#线程池如何处理提交的任务" class="headerlink" title="线程池如何处理提交的任务"></a>线程池如何处理提交的任务</h4><p>我们向线程池提交任务有两种方式,分别是通过 <code>submit</code> 方法提交和通过 <code>execute</code> 方法提交,这两种方式的区别为 <code>execute</code> 只能提交 <code>Runnable</code> 类型的任务并且没有返回值,而 <code>submit</code> 既能提交 <code>Runnable</code> 类型的任务也能提交 <code>Callable</code>(JDK 1.5+)类型的任务并且会有一个类型 <code>Future</code> 的返回值,我们知道 <code>Runnable</code> 是没有返回值的,所以只有当提交 <code>Callable</code> 类型的任务时才会有返回值,而提交 <code>Runnable</code> 的返回值是 <code>null</code>。 <code>execute</code> 执行任务时,如果此时遇到异常会直接抛出,而 <code>submit</code> 不会直接抛出,只有在使用 <code>Future</code> 的 <code>get</code> 方法获取任务的返回结果时,才会抛出异常。<br>通过查看 <code>ThreadPoolExecutor</code> 的源码我们发现,其 <code>submit</code> 方法是继承自其抽象父类 <code>AbstractExecutorService</code> 而来的,有三个重载的方法,分别可以提交 <code>Runnable</code> 类型和 <code>Callable</code> 类型的任务。无论是哪个 <code>submit</code> 方法最终还是调用了 <code>execute</code> 方法来实现的。方法源码如下:</p> -<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Future&lt;?&gt; submit(Runnable task) &#123;</span><br><span class="line"> <span class="keyword">if</span> (task == <span class="keyword">null</span>) <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> RunnableFuture&lt;Void&gt; ftask = newTaskFor(task, <span class="keyword">null</span>);</span><br><span class="line"> execute(ftask);</span><br><span class="line"> <span class="keyword">return</span> ftask;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> &lt;T&gt; <span class="function">Future&lt;T&gt; <span class="title">submit</span><span class="params">(Runnable task, T result)</span> </span>&#123;</span><br><span class="line"> <span class="keyword">if</span> (task == <span class="keyword">null</span>) <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> RunnableFuture&lt;T&gt; ftask = newTaskFor(task, result);</span><br><span class="line"> execute(ftask);</span><br><span class="line"> <span class="keyword">return</span> ftask;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> &lt;T&gt; <span class="function">Future&lt;T&gt; <span class="title">submit</span><span class="params">(Callable&lt;T&gt; task)</span> </span>&#123;</span><br><span class="line"> <span class="keyword">if</span> (task == <span class="keyword">null</span>) <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> RunnableFuture&lt;T&gt; ftask = newTaskFor(task);</span><br><span class="line"> execute(ftask);</span><br><span class="line"> <span class="keyword">return</span> ftask;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure> - - - - - - - - - - - - - diff --git a/baidusitemap.xml b/baidusitemap.xml index ced97985..3f80b021 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -1,6 +1,9 @@ + https://www.mghio.cn/post/f92758d8.html + 2020-08-09 + https://www.mghio.cn/post/c34b451f.html 2020-07-18 diff --git a/categories/JDK/Java/index.html b/categories/JDK/Java/index.html index 7d87ce06..567c5744 100644 --- a/categories/JDK/Java/index.html +++ b/categories/JDK/Java/index.html @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index d91336fe..ea06ef92 100644 --- "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git a/categories/JDK/index.html b/categories/JDK/index.html index cadd2a97..738b7a13 100644 --- a/categories/JDK/index.html +++ b/categories/JDK/index.html @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git a/categories/Java/Bloom-filter/index.html b/categories/Java/Bloom-filter/index.html index 9f99311c..8da657f9 100644 --- a/categories/Java/Bloom-filter/index.html +++ b/categories/Java/Bloom-filter/index.html @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git a/categories/Java/GC/index.html b/categories/Java/GC/index.html index 339b53b6..8ae8a6d8 100644 --- a/categories/Java/GC/index.html +++ b/categories/Java/GC/index.html @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git a/categories/Java/Guava/String/index.html b/categories/Java/Guava/String/index.html index 5694c32e..5e604947 100644 --- a/categories/Java/Guava/String/index.html +++ b/categories/Java/Guava/String/index.html @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git a/categories/Java/Guava/index.html b/categories/Java/Guava/index.html index 883da6f7..6c806d72 100644 --- a/categories/Java/Guava/index.html +++ b/categories/Java/Guava/index.html @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git a/categories/Java/IDEA/index.html b/categories/Java/IDEA/index.html index 30850c1c..37eed51f 100644 --- a/categories/Java/IDEA/index.html +++ b/categories/Java/IDEA/index.html @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" index 667289cb..525116bd 100644 --- "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" +++ "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/IO\346\250\241\345\236\213/index.html" "b/categories/Java/IO\346\250\241\345\236\213/index.html" index f41d21fa..1d73c13f 100644 --- "a/categories/Java/IO\346\250\241\345\236\213/index.html" +++ "b/categories/Java/IO\346\250\241\345\236\213/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git a/categories/Java/JVM/index.html b/categories/Java/JVM/index.html index dd2c2657..cc9d3367 100644 --- a/categories/Java/JVM/index.html +++ b/categories/Java/JVM/index.html @@ -413,7 +413,7 @@

- 28 + 29 日志 diff --git a/categories/Java/index.html b/categories/Java/index.html index 907d726b..ab37deac 100644 --- a/categories/Java/index.html +++ b/categories/Java/index.html @@ -625,7 +625,7 @@

- 28 + 29 日志 diff --git a/categories/Java/page/2/index.html b/categories/Java/page/2/index.html index 3cbac204..c36f5d09 100644 --- a/categories/Java/page/2/index.html +++ b/categories/Java/page/2/index.html @@ -625,7 +625,7 @@

- 28 + 29 日志 diff --git a/categories/Java/page/3/index.html b/categories/Java/page/3/index.html index ebc732a3..d2f3c65b 100644 --- a/categories/Java/page/3/index.html +++ b/categories/Java/page/3/index.html @@ -469,7 +469,7 @@

- 28 + 29 日志 diff --git a/categories/Java/unit-test/index.html b/categories/Java/unit-test/index.html index 309bf701..539b5e53 100644 --- a/categories/Java/unit-test/index.html +++ b/categories/Java/unit-test/index.html @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git a/categories/Java/unit-test/mockito/index.html b/categories/Java/unit-test/mockito/index.html index 7ee4d542..8ffcbe75 100644 --- a/categories/Java/unit-test/mockito/index.html +++ b/categories/Java/unit-test/mockito/index.html @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/\345\216\237\347\220\206/index.html" "b/categories/Java/\345\216\237\347\220\206/index.html" index ae3374b9..fa2dc548 100644 --- "a/categories/Java/\345\216\237\347\220\206/index.html" +++ "b/categories/Java/\345\216\237\347\220\206/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/\345\217\215\345\260\204/index.html" "b/categories/Java/\345\217\215\345\260\204/index.html" index 9f7bf73f..f413b093 100644 --- "a/categories/Java/\345\217\215\345\260\204/index.html" +++ "b/categories/Java/\345\217\215\345\260\204/index.html" @@ -413,7 +413,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" index 663948d8..315e4917 100644 --- "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" @@ -413,7 +413,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/\345\271\266\345\217\221/index.html" "b/categories/Java/\345\271\266\345\217\221/index.html" index 4a5d45e0..7f0b7606 100644 --- "a/categories/Java/\345\271\266\345\217\221/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/index.html" @@ -439,7 +439,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" index e6a8b45b..2ae8aa70 100644 --- "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/\345\274\202\346\255\245/index.html" "b/categories/Java/\345\274\202\346\255\245/index.html" index 9c449eeb..723418af 100644 --- "a/categories/Java/\345\274\202\346\255\245/index.html" +++ "b/categories/Java/\345\274\202\346\255\245/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" index a5b2e7cf..220829bc 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 17e475f6..56a1f57d 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" index 0b2e70b7..c20fba62 100644 --- "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" +++ "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" @@ -413,7 +413,7 @@

- 28 + 29 日志 diff --git "a/categories/Java/\351\207\215\346\236\204/index.html" "b/categories/Java/\351\207\215\346\236\204/index.html" index f9844d2d..0976f6ce 100644 --- "a/categories/Java/\351\207\215\346\236\204/index.html" +++ "b/categories/Java/\351\207\215\346\236\204/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/Linux\347\254\224\350\256\260/index.html" "b/categories/Linux\347\254\224\350\256\260/index.html" index 7f28df0f..b3f4a086 100644 --- "a/categories/Linux\347\254\224\350\256\260/index.html" +++ "b/categories/Linux\347\254\224\350\256\260/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git a/categories/RabbitMQ/Java/index.html b/categories/RabbitMQ/Java/index.html index a9833f72..b78f4a3a 100644 --- a/categories/RabbitMQ/Java/index.html +++ b/categories/RabbitMQ/Java/index.html @@ -309,6 +309,32 @@

Java分类 + + + + + +
@@ -387,7 +413,7 @@

- 28 + 29 日志 diff --git a/categories/RabbitMQ/index.html b/categories/RabbitMQ/index.html index 106e8484..5aade16a 100644 --- a/categories/RabbitMQ/index.html +++ b/categories/RabbitMQ/index.html @@ -309,6 +309,32 @@

RabbitMQ分类 + + + + + +
@@ -387,7 +413,7 @@

- 28 + 29 日志 diff --git a/categories/index.html b/categories/index.html index 517aa584..d9e6aaaa 100644 --- a/categories/index.html +++ b/categories/index.html @@ -320,7 +320,7 @@

目前共计 29 个分类 @@ -378,7 +378,7 @@

- 28 + 29 日志 diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" index 4ab6fdad..1632afa8 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index cf1c24d6..03c67096 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -387,7 +387,7 @@

- 28 + 29 日志 diff --git a/css/main.css b/css/main.css index d008c953..c8eefc1d 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #fff; + background: #5ebd9a; } .links-of-blogroll { font-size: 13px; diff --git a/index.html b/index.html index a3bdde2c..85da1eba 100644 --- a/index.html +++ b/index.html @@ -310,7 +310,7 @@

Java 搬运工 & 终身学习
- +

@@ -456,11 +456,11 @@

-

什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

-

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

+

上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

+

消息生产者发送的消息不可达时如何处理

RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

- + 阅读全文 »
@@ -513,7 +513,7 @@

- +

-

+

@@ -670,10 +659,11 @@

-

前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

+

什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

+

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

- + 阅读全文 »
@@ -726,7 +716,7 @@

前言 - +

@@ -883,10 +873,10 @@

-

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

+

前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

- + 阅读全文 »
@@ -939,7 +929,7 @@

前言 - +

@@ -1096,10 +1086,10 @@

-

前言

对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

+

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

- + 阅读全文 »
@@ -1152,7 +1142,7 @@

前言 - +

@@ -1298,11 +1299,10 @@

-

前言

在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

-

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

+

前言

对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

- + 阅读全文 »
@@ -1355,7 +1355,7 @@

- +

-

+

@@ -1501,14 +1501,11 @@

-

前言

在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

-

原理

布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

-
-

A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

-
+

前言

在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

+

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

- + 阅读全文 »
@@ -1561,7 +1558,7 @@

原理 - +

@@ -1718,15 +1704,14 @@

-

前言

Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

-

如何使用

Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

-
1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
- -

对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

-
1
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
+

前言

在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

+

原理

布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

+
+

A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

+
- + 阅读全文 »
@@ -1779,7 +1764,7 @@

- +

-

+

@@ -1925,11 +1921,15 @@

-

前言

在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

-

什么是 CompletableFuture

CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

+

前言

Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

+

如何使用

Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

+
1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
+ +

对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

+
1
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
- + 阅读全文 »
@@ -1982,7 +1982,7 @@

- +

-

+

@@ -2128,11 +2128,11 @@

-

前言

在日常生活中,当我们买的水果放久了之后会发出一种难闻的气味(“坏味道”),这个时候我们就应该把它扔掉。同样,代码也有“坏味道”,当然确定什么是和不是代码“坏味道”是主观的,它会随语言、开发人员和开发方法的不同而不同。在工作当中,很多时候都是在维护之前的项目和在此基础上增加一些新功能,为了能让项目代码易于理解和维护,要时刻注意代码中的“坏味道”,当发现代码如果有坏味道了,要及时去重构它使其变成优秀的整洁的代码。本文列举代码中一些常见的“坏味道”和相应的重构方案。

-

过长方法 (Long Method)

这种“坏味道”表现为方法代码行数过长,方法行数越长,就越难以理解和维护它。一个比较有用的方案就是当你觉得需要对方法中的内容加注释的时候,你应该将这个代码段作为一个新方法提取出来,哪怕有时候仅仅是一行代码也可以这么做,而且方法的命名要尽量做到见名知意,如果局部变量和参数干扰到方法的提取,则可以使用引入参数对象来进行提取。一般情况下,方法中条件运算符和循环是可以将代码移至单独方法的一个很好的代码段,对于条件运算符,可以尝试分解条件,如果方法出现循环,可以尝试提取方法。

+

前言

在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

+

什么是 CompletableFuture

CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

- + 阅读全文 »
@@ -2185,7 +2185,7 @@

- +

-

+

diff --git a/page/2/index.html b/page/2/index.html index d5f36c2f..ba378974 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -305,6 +305,209 @@

Java 搬运工 & 终身学习 +
+ + + +
+ + + + + + + +
+ + + +

+ +

+ + + +
+ + + + + +
+ + + + + + +

前言

在计算机科学中,垃圾回收(GC: garbage collection)是内存自动管理的一种方式,它并不是同 Java 语言一起诞生的,实际上,早在 1959 年为了简化 Lisp 语言的手动内存管理,该语言的作者就开始使用了内存自动管理技术。 垃圾收集手动内存管理刚好相反,后者需要编程人员自己去指定需要释放的对象然后将内存归还给操作系统,而前者不需要关心给对象分配的内存回收问题。Java 语言使用自动垃圾收集器来管理对象生命周期中的内存,要进行垃圾收集首先需要明确三个问题:1. 哪些内存需要回收2. 什么时候进行回收3. 怎么进行内存回收。接下来让我们一起看看 Java 语言对这些问题是如何处理的。

+

哪些内存需要回收

为了方便管理和跨平台,Java 虚拟机规范规定在执行 Java 程序的时候把它所管理的内存划分为若干个不同的数据区域。这些区域都有着各自不同的用途以及创建和销毁的时间,有的数据区域随着用户线程的启动和结束而建立和销毁,有的区域会随着虚拟机进程的启动和停止而存在和销毁。更多有关运行时数据区域的内容请看 Java 运行时数据区域
由于 Java 运行时数据区域中的 程序计数器虚拟机栈本地方法栈和线程的生命周期一致,随线程的启动和结束而建立和销毁。而且当我们的类结构确定了之后,在编译期间,一个栈帧需要分配内存的大小基本上也就确定下来了,这三个区域的内存分配和收回都是具备确定性的,不需要我们过多的去考虑内存回收问题。主要考虑Java 堆方法区的内存回收的问题。

+ +
+ + 阅读全文 » + +
+ + + +
+ + + + + + + + + + + + +
+ + + + + + + + +
+ +
+
+ + + +
+ + + + + + + + + + +
@@ -2157,210 +2360,6 @@
线程 - - - - - - - - -
- - - - - - -
- - - - - - - - - - - -
- - - -
- - - - - - - -
- - - -

- -

- - - -
- - - - - -
- - - - - - -

简介

在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

-

线程池如何处理提交的任务

我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
- -
- - 阅读全文 » - -
- - - -
- - - - - - - - - - - -
diff --git a/page/3/index.html b/page/3/index.html index cc1c97d3..3ded4988 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -305,6 +305,210 @@

Java 搬运工 & 终身学习 +
+ + + +
+ + + + + + + +
+ + + +

+ +

+ + + +
+ + + + + +
+ + + + + + +

简介

在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

+

线程池如何处理提交的任务

我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
+ +
+ + 阅读全文 » + +
+ + + +
+ + + + + + + + + + + + +
+ + + + + + + + +
+ +
+
+ + + +
+ + + + + + + + + + +
@@ -1985,7 +2189,7 @@

- 28 + 29 日志 diff --git a/post/102cd3d9.html b/post/102cd3d9.html index 35bf1c11..fc56947f 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -847,7 +847,7 @@

总结 - 28 + 29 日志 diff --git a/post/11cb7677.html b/post/11cb7677.html index 764b9c81..059cfb50 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -698,7 +698,7 @@

总结 - 28 + 29 日志 diff --git a/post/192cb539.html b/post/192cb539.html index cb96d9ea..54354080 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -762,7 +762,7 @@

- 28 + 29 日志 diff --git a/post/24042edf.html b/post/24042edf.html index bb2f92cb..4c47a7cc 100644 --- a/post/24042edf.html +++ b/post/24042edf.html @@ -770,7 +770,7 @@

总结 - 28 + 29 日志 diff --git a/post/34755d6c.html b/post/34755d6c.html index 733180db..44c0c4ca 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -677,7 +677,7 @@

总结 - 28 + 29 日志 diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index 065cbac5..da713c4b 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -744,7 +744,7 @@

总结 - 28 + 29 日志 diff --git a/post/4615256d.html b/post/4615256d.html index 8d96d47c..1d085e30 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -753,7 +753,7 @@

- 28 + 29 日志 diff --git a/post/4b00e13c.html b/post/4b00e13c.html index 61522fea..65189ddd 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -852,7 +852,7 @@

总结 - 28 + 29 日志 diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index e5341103..485a8698 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -685,7 +685,7 @@

总结 - 28 + 29 日志 diff --git a/post/51e5bd99.html b/post/51e5bd99.html index 54ca8908..e91ee30d 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -726,7 +726,7 @@

- 28 + 29 日志 diff --git a/post/710bd10b.html b/post/710bd10b.html index 574d8211..5a48117f 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -732,7 +732,7 @@

总结 - 28 + 29 日志 diff --git a/post/7528c810.html b/post/7528c810.html index 2a9f9e80..39ceed4b 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -715,7 +715,7 @@

总结 - 28 + 29 日志 diff --git a/post/7b9ead86.html b/post/7b9ead86.html index 9c9372cf..b93dbe89 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -715,7 +715,7 @@

总结 - 28 + 29 日志 diff --git a/post/7eb2637f.html b/post/7eb2637f.html index d7281c57..79cdf0e7 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -754,7 +754,7 @@

- 28 + 29 日志 diff --git a/post/817c7d82.html b/post/817c7d82.html index a1b9c49f..3dd8ca9c 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1323,7 +1323,7 @@

- 28 + 29 日志 diff --git a/post/8a061473.html b/post/8a061473.html index 4bf9da9b..6aefe222 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -791,7 +791,7 @@
- 28 + 29 日志 diff --git a/post/8bd965a0.html b/post/8bd965a0.html index bc80c43c..9cd0b856 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -714,7 +714,7 @@

- 28 + 29 日志 diff --git a/post/99ea2970.html b/post/99ea2970.html index f2083271..e1822301 100644 --- a/post/99ea2970.html +++ b/post/99ea2970.html @@ -710,7 +710,7 @@

- 28 + 29 日志 diff --git a/post/a38c0645.html b/post/a38c0645.html index 8a247fd6..721b1076 100644 --- a/post/a38c0645.html +++ b/post/a38c0645.html @@ -694,7 +694,7 @@

总结 - 28 + 29 日志 diff --git a/post/ab706eb5.html b/post/ab706eb5.html index c24a6c12..d8a1c2c4 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -697,7 +697,7 @@

总结 - 28 + 29 日志 diff --git a/post/b1d4025b.html b/post/b1d4025b.html index fe2417f6..b62ade15 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -627,7 +627,7 @@

hello world

- 28 + 29 日志 diff --git a/post/bc557e1a.html b/post/bc557e1a.html index 1aeb2ca0..3a620f5f 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -762,7 +762,7 @@
- 28 + 29 日志 diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index 529bb949..5166cbed 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -714,7 +714,7 @@

- 28 + 29 日志 diff --git a/post/c34b451f.html b/post/c34b451f.html index b8a48bf7..f61ddf5b 100644 --- a/post/c34b451f.html +++ b/post/c34b451f.html @@ -662,6 +662,10 @@

总结 + + @@ -749,7 +753,7 @@

总结 - 28 + 29 日志 diff --git a/post/e09f0428.html b/post/e09f0428.html index 0391a2bb..4fe0bd50 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -684,7 +684,7 @@

- 28 + 29 日志 diff --git a/post/ee27c07f.html b/post/ee27c07f.html index 6e4aa7c0..2c0ff3e4 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -677,7 +677,7 @@

- 28 + 29 日志 diff --git a/post/f440d00b.html b/post/f440d00b.html index 767ec228..381b4da0 100644 --- a/post/f440d00b.html +++ b/post/f440d00b.html @@ -713,7 +713,7 @@

总结 - 28 + 29 日志 diff --git a/post/f92758d8.html b/post/f92758d8.html new file mode 100644 index 00000000..d20b8b20 --- /dev/null +++ b/post/f92758d8.html @@ -0,0 +1,1596 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RabbitMQ 基础概念进阶 | mghio + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

RabbitMQ 基础概念进阶

+ + + +
+ + + + + +
+ + + + + +

上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

+

消息生产者发送的消息不可达时如何处理

RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

+ +
1.1 mandatory 参数

mandatory 被定义在 RabbitMQ 提供的客户端的 channel.basicPublish 方法中,如下所示:

+

rabbitmq_advanced_1.png

+

当把方法的 mandatory 参数设置为 true 时,那么会在交换器无法根据自身的类型和路由键找到一个符合要求的队列时,RabbitMQ 会自动调用 Basic.Return 把该消息回传给发送方也就是我们的消息生产者。反之,如果设置为 false 的话,消息就会被直接丢弃掉。那么问题来了,我们要如何去获取这些没有被发送出去的消息呢?RabbitMQ 给我们提供了事件监听机制来获取这种消息,可以通过 addReturnListener 方法添加一个 ReturnListener 来获取这种未发送到队列的消息,如下所示:

+

rabbitmq_advanced_2.png

+

通过查看 ReturnListener 接口的源码可以看到,该接口只有一个方法,如果是 JDK8+ 的版本的话可以使用 Lambda 表达式来简化一些代码。

+

可以看出,当设置了 mandatory 参数时,还必须为生产者同时添加 ReturnListener 监听器的编程逻辑,这样就会使得生产者的代码变得更加复杂了,为了处理这种情况,RabbitMQ 提供了 备份交换器 来将没有成功路由出去的消息存储起来,当我们需要的时候再去处理即可。

+
1.2 immediate 参数

该的参数同样也是在channel.basicPublish 方法中定义的,其官方描述如下:

+
+

This flag tells the server how to react if the message cannot be routed to a queue consumer immediately. If this flag is set, the server will return an undeliverable message with a Return method. If this flag is zero, the server will queue the message, but with no guarantee that it will ever be consumed.

+
+

当把 immediate 参数设置为 true 时,如果交换器根据其类型和路由键找到符合要求的队列时,发现所有队列上没有任何消费者,则该消息并不会存入到队列中,会通过 Basic.Return 命令把消息回传给生产者。简而言之也就是说,当设置了 immediate 参数时,该消息关联的队列上存在消费者时,会立即发送消息到该队列中,反之如果匹配的队列上不存在任何消费者,则直接把消息回传给生产者。这里有一点需要注意的是:从 RabbitMQ 3.0 + 已经去除了该参数。

+

如何对消息和队列设置过期时间 (TTL)

TTL 是 time to live 首字母的简称,RabbitMQ 中可以设置消息和队列的过期时间,我们先来看看要如何设置消息的过期时间。

+
1.1 消息 TTL 设置

RabbitMQ 提供了两种设置消息的过期时间,第一种是通过队列的属性设置,该方式的特点就是队列中所有消息的过期时间都一致。还有一种是更小粒度的设置,就是对每条消息单独设置过期时间,这种方式更加灵活,每条消息的过期时间都可以不一样。这是你可能会问,如果同时设置了队列的过期属性和消息本身的过期属性,最终以哪个为准呢?结果是 RabbitMQ 会比较这两个 TTL 的值大小,以较小的那个为准。很容易想到,通过队列的属性的方式设置过期时间的话是在声明队列的时候指定,对应到客户端就是其提供的 channel.queueDeclare 方法的参数 arguments 指定,示例代码如下:

+

rabbitmq_advanced_3.png

+

需要注意的是 x-message-ttl 参数的单位是毫秒。如果不设置 TLL,则表示该消息不会过期,如果将 TTL 设置为 0,表示除非此时可以把消息直接发送投递到消费者端去,否则就会直接丢弃该消息。

+

准对每条消息设置 TTL 的方法是在发送消息的时候设置的,对应到客户端方法是 channel.basicPublish 的 expiration 属性参数,具体设置代码如下:

+

rabbitmq_advanced_4.png

+

这种设置方式,即使队列过期也不会立即从队列中移除,因为每条消息是否过期的判定是在发送到消费者是才进行的,如果此时发现已经过期才会删除消息。而对于第一种方式则会把已经过期的消息移到队列头部,然后 RabbitMQ 只要定期的从头开始扫描是否存在过期的消息即可。

+
1.2 队列 TTL 设置

设置队列的过期时间使用的是客户端的 channel.queueDeclare 方法参数中的 x-expires 参数,其单位同样也是毫秒,不过需要注意的是它不能设置为 0。设置队列过期的代码如下所示:

+

rabbitmq_advanced_5.png

+

上面代码创建了一个过期时间为 15 分钟的队列。

+

死信队列介绍

死信交换器(DLX)的全称是 Dead-Letter-Exchange ,也称之为死信邮箱。简单来说就是当一个消息由于 消息被拒绝消息过期队列达到最大长度 时,变成死信(dead message)之后,会被重新发送到一个交换器中,这个交换器就是死信交换器,绑定在这个交换器上的队列就称之为死信队列。死信交换器实际上就是平常的交换器,可以在任何队列上指定,当在一个队列上设置死信交换器后,如果该队列出现死信时就会被 RabbitMQ 把死信消息重新发送到死信交换器上去,然后路由到死信队列中,我们可以监听这个队列来处理那些死信消息。为一个队列设置死信交换器是在生产者的声明队列的方法中设置 x-dead-letter-message 参数来实现的,如下所示:

+

rabbitmq_advanced_6.png

+

同时也可以通过 x-dead-letter-routing-key 参数设置死信交互器的路由键,不设置默认使用原始度列的路由键。可以到 RabbitMQ 的后台管理界面,有 DLX 标志的就是死信队列。

+

rabbitmq_advanced_7.png

+

RabbitMQ 提供的 DLX 是个比较实用的功能特性,它可以在我们消息不能被消费者正确消费的情况下放入到死信队列,后续我们可以通过这个死信队列的内容来查看异常情况来改造和优化系统。

+

延迟队列介绍

顾名思义,延迟队列存储的是哪些需要等待指定时间后才能拿到的延迟消息,一个比较典型的场景就是订单 30 分钟后未支付取消订单。这里需要注意的是,在 RabbitMQ 中并没有直接提供延迟队列的功能,而是需要通过上面介绍的过期时间(TTL)和死信队列一起来实现,比如超时取消订单这个场景,我们可以让消费者订阅死信队列,设置正常的那个队列的超时时间为 30 分钟并绑定到该死信队列上,当消息超过 30 分钟未被处理后消息就会把发送到死信队列中,然后死信队列的消费者就可以在 30 分钟后成功的消费到该消息了。

+

rabbitmq_advanced_8.png

+

同时当我们有其它的超时配置需求时也很方便扩展,比如可以在生产者发送消息的时候通过设置不同的路由键,通过路由键来将消息发送到与交换器绑定的不同队列中,然后这些队列分别设置不同的过期时间和与之相对应的死信队列,当消息过期时就会被 RabbitMQ 转发到相应的死信队列中,这样就可以去订阅相应的死信队列即可。

+

交换器、消息和队列持久化

持久化可以提高可靠性,可以防止宕机或者重启等异常下数据的丢失,RabbitMQ 的持久化从组成结构上可以分为三个部分,即交换器持久化、消息持久化和队列持久化。

+
1.1 交换器持久化

交换器持久化是在声明交换器时将 durable 参数设置为 true 来实现的。如果不设置持久化属性的话,当 RabbitMQ 服务重启后交换器的数据就会丢失,需要注意的是,是交换器的数据丢失,消息不会丢失,只是不能将消息发送到这个交换器中了,一般生产环境使用都会把该属性设置为持久化。

+
1.2 消息持久化

交换器的持久化仅仅只是保证了交换器本身的元数据不会丢失,无法保证其存储的消息不会丢失,如果需要其内部存储的消息不丢失,则需要设置消息的持久化,通过将消息的投递模式(deliveryMode)设置为 2 即可实现消息的持久化,如下所示:

+

rabbitmq_advanced_9.png

+

需要消息持久化的前提是其所在的队列也要设置持久化,假如仅仅只设置消息的持久化的话,RabbitMQ 重启之后队列消失,然后消息也会丢失。这里有点需要注意一下,虽然持久化可以提高可靠性,但是持久化是将数据存储到硬盘上,比直接操作内存要慢很多,所以对于哪些可靠性要求不高的业务不需要进行持久化。

+
1.3 队列持久化

队列的持久化的设置和交换器持久化类似,同样也是在声明的时候通过 durable 参数设置为 true 实现的,如果不设置,当 RabbitMQ 重启后,相关的队列元数据也会丢失,相应的其存储的消息也会随之丢失掉。

+

将交换器、队列、消息都设置了持久化之后就能百分之百保证数据不丢失了吗?其实无法保证百分之百数据不丢失。比如消费者在订阅消费队列时将自动应答(autoAck)参数设置为 true 的话,在接收到消息后还没来得及处理就挂了,这时需要把自动应答设置 false,进行手动 ack 应答即可。还有一个就是由于不是实时持久化存盘,当消息存盘的过程中 RabbitMQ 宕机了,此时也会发生数据丢失,此时需要通过 RabbitMQ 的 镜像队列机制 来处理了。

+

总结

本文主要介绍了一些参数具体使用时的设置细节和死信队列、延迟队列以及持久化等,还有一些比较重要的点没有涉及到,比如消息确认机制。“纸上得来终觉浅,绝知此事要躬行”,在了解一些基础的概念之后还是需要通过具体编码实践才能对其更加理解深刻。

+ + +
+ + + + + +
+
-------------本文结束感谢您的阅读-------------
+
+ + + +
+
+ mghio wechat +
微信公众号「mghio」
+
+ +
+ + + +
+
+
请我吃🍗
+ + +
+ +
+ + + +
+ +
+ + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ +
+
+ + + + + +
+ + + + + + + + + +
+
+ +
+ +
+ + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/post/fe76043.html b/post/fe76043.html index 3976d3bf..04aef053 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -680,7 +680,7 @@

总结 - 28 + 29 日志 diff --git a/search.xml b/search.xml index cd641bee..f77011b0 100644 --- a/search.xml +++ b/search.xml @@ -1,5 +1,18 @@ + + <![CDATA[RabbitMQ 基础概念进阶]]> + %2Fpost%2Ff92758d8.html + + + RabbitMQ + Java + + + Java + RabbitMQ + + <![CDATA[RabbitMQ 入门之基础概念]]> %2Fpost%2Fc34b451f.html diff --git a/sitemap.xml b/sitemap.xml index 4fed7c7d..86386ffa 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,13 @@ + + https://www.mghio.cn/post/f92758d8.html + + 2020-08-09T14:44:05.879Z + + + https://www.mghio.cn/post/c34b451f.html diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index 283edda4..a3002cc8 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index eb2a978f..c374b55e 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index e7ee1fd8..16c839c8 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git a/tags/GC/index.html b/tags/GC/index.html index 5f6c2887..769aa6b6 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git a/tags/Guava/index.html b/tags/Guava/index.html index 6ebac23e..442ed04f 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index 2cff0b03..967cadd5 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index 5d01e900..ae4b3945 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git a/tags/JDK/index.html b/tags/JDK/index.html index a27acbde..554861ab 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git a/tags/JVM/index.html b/tags/JVM/index.html index 9898210a..abb63d8e 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -412,7 +412,7 @@

- 28 + 29 日志 diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index f02fa11a..72f7c175 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index f3d4aab5..83530bcc 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git a/tags/Java/index.html b/tags/Java/index.html index b656117e..b07309f8 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -624,7 +624,7 @@

- 28 + 29 日志 diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index fde425d6..45686068 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -624,7 +624,7 @@

- 28 + 29 日志 diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index 6e74a781..6548f7ff 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -468,7 +494,7 @@

- 28 + 29 日志 diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index 45bdcf24..3dab3b77 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git a/tags/RabbitMQ/index.html b/tags/RabbitMQ/index.html index a3acef55..8a6b01d4 100644 --- a/tags/RabbitMQ/index.html +++ b/tags/RabbitMQ/index.html @@ -309,6 +309,32 @@

RabbitMQ标签 + + + + + +
@@ -386,7 +412,7 @@

- 28 + 29 日志 diff --git a/tags/String/index.html b/tags/String/index.html index a16ab91b..9735b0f6 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git a/tags/index.html b/tags/index.html index 2ec0c6b1..566a5615 100644 --- a/tags/index.html +++ b/tags/index.html @@ -320,7 +320,7 @@

目前共计 26 个标签 @@ -378,7 +378,7 @@

- 28 + 29 日志 diff --git a/tags/mockito/index.html b/tags/mockito/index.html index 1205192b..ec32dac6 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git a/tags/test/index.html b/tags/test/index.html index 89d44377..6b496300 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index ef875f20..00ed7fe4 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index d16c7944..10cdc397 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -412,7 +412,7 @@

- 28 + 29 日志 diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 764ba8f6..866438ef 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -412,7 +412,7 @@

- 28 + 29 日志 diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index 72eb2533..436f9d21 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index a179fb78..d10c8014 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -412,7 +412,7 @@

- 28 + 29 日志 diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index 5d7cebe6..056de621 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index b372ef81..9218b636 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index a5943e90..5523bda9 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index c8009660..98a4f85e 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -386,7 +386,7 @@

- 28 + 29 日志 From b6464b1e49f0043f7e93b0f3ce6480c803f5b13a Mon Sep 17 00:00:00 2001 From: maguihai Date: Sun, 23 Aug 2020 14:24:25 +0800 Subject: [PATCH 07/19] Site updated: 2020-08-23 14:24:24 --- about/index.html | 6 +- archives/2019/10/index.html | 8 +- archives/2019/11/index.html | 8 +- archives/2019/12/index.html | 8 +- archives/2019/index.html | 8 +- archives/2019/page/2/index.html | 8 +- archives/2020/01/index.html | 8 +- archives/2020/02/index.html | 8 +- archives/2020/03/index.html | 8 +- archives/2020/04/index.html | 8 +- archives/2020/05/index.html | 8 +- archives/2020/06/index.html | 8 +- archives/2020/07/index.html | 8 +- archives/2020/08/index.html | 43 +- archives/2020/index.html | 78 +- archives/2020/page/2/index.html | 43 +- archives/index.html | 78 +- archives/page/2/index.html | 78 +- archives/page/3/index.html | 43 +- atom.xml | 60 +- baidusitemap.xml | 3 + categories/JDK/Java/index.html | 6 +- .../index.html" | 6 +- categories/JDK/index.html | 6 +- categories/Java/Bloom-filter/index.html | 6 +- categories/Java/GC/index.html | 6 +- categories/Java/Guava/String/index.html | 6 +- categories/Java/Guava/index.html | 6 +- categories/Java/IDEA/index.html | 6 +- .../IDEA/\345\267\245\345\205\267/index.html" | 6 +- .../IO\346\250\241\345\236\213/index.html" | 6 +- categories/Java/JVM/index.html | 6 +- categories/Java/List/index.html | 1254 +++++++++++++ categories/Java/index.html | 58 +- categories/Java/page/2/index.html | 58 +- categories/Java/page/3/index.html | 32 +- categories/Java/unit-test/index.html | 6 +- categories/Java/unit-test/mockito/index.html | 6 +- .../Java/\345\216\237\347\220\206/index.html" | 6 +- .../Java/\345\217\215\345\260\204/index.html" | 6 +- .../index.html" | 6 +- .../Java/\345\271\266\345\217\221/index.html" | 6 +- .../\350\277\233\351\230\266/index.html" | 6 +- .../Java/\345\274\202\346\255\245/index.html" | 6 +- .../Eureka/index.html" | 6 +- .../index.html" | 6 +- .../index.html" | 6 +- .../Java/\351\207\215\346\236\204/index.html" | 6 +- .../Linux\347\254\224\350\256\260/index.html" | 6 +- categories/RabbitMQ/Java/index.html | 6 +- categories/RabbitMQ/index.html | 6 +- categories/index.html | 10 +- .../CAP\345\256\232\347\220\206/index.html" | 6 +- .../index.html" | 6 +- css/main.css | 2 +- index.html | 333 ++-- page/2/index.html | 409 +++-- page/3/index.html | 210 ++- post/102cd3d9.html | 6 +- post/11cb7677.html | 6 +- post/192cb539.html | 6 +- post/24042edf.html | 6 +- post/34755d6c.html | 6 +- post/3ae0ff4e.html | 6 +- post/4615256d.html | 6 +- post/4b00e13c.html | 6 +- post/4ea48fa7.html | 6 +- post/51e5bd99.html | 6 +- post/710bd10b.html | 6 +- post/7528c810.html | 6 +- post/7b9ead86.html | 6 +- post/7eb2637f.html | 6 +- post/817c7d82.html | 6 +- post/8a061473.html | 6 +- post/8bd965a0.html | 6 +- post/99ea2970.html | 6 +- post/a38c0645.html | 6 +- post/ab706eb5.html | 6 +- post/b1d4025b.html | 6 +- post/bc557e1a.html | 6 +- post/bfcdfeaf.html | 6 +- post/c34b451f.html | 6 +- post/d7d0fc76.html | 1574 +++++++++++++++++ post/e09f0428.html | 6 +- post/ee27c07f.html | 6 +- post/f440d00b.html | 6 +- post/f92758d8.html | 10 +- post/fe76043.html | 6 +- search.xml | 13 + sitemap.xml | 7 + tags/Bloom-filter/index.html | 6 +- "tags/CAP\345\256\232\347\220\206/index.html" | 6 +- tags/Eureka/index.html | 6 +- tags/GC/index.html | 6 +- tags/Guava/index.html | 6 +- tags/IDEA/index.html | 6 +- "tags/IO\346\250\241\345\236\213/index.html" | 6 +- tags/JDK/index.html | 6 +- tags/JVM/index.html | 6 +- .../Java-\345\216\237\347\220\206/index.html" | 6 +- .../Java-\345\271\266\345\217\221/index.html" | 6 +- tags/Java/index.html | 58 +- tags/Java/page/2/index.html | 58 +- tags/Java/page/3/index.html | 32 +- .../Linux\347\254\224\350\256\260/index.html" | 6 +- tags/List/index.html | 1253 +++++++++++++ tags/RabbitMQ/index.html | 6 +- tags/String/index.html | 6 +- tags/index.html | 10 +- tags/mockito/index.html | 6 +- tags/test/index.html | 6 +- .../index.html" | 6 +- "tags/\345\217\215\345\260\204/index.html" | 6 +- .../index.html" | 6 +- "tags/\345\267\245\345\205\267/index.html" | 6 +- "tags/\345\271\266\345\217\221/index.html" | 6 +- "tags/\345\274\202\346\255\245/index.html" | 6 +- .../index.html" | 6 +- .../index.html" | 6 +- "tags/\351\207\215\346\236\204/index.html" | 6 +- 120 files changed, 5432 insertions(+), 963 deletions(-) create mode 100644 categories/Java/List/index.html create mode 100644 post/d7d0fc76.html create mode 100644 tags/List/index.html diff --git a/about/index.html b/about/index.html index 8fbc24a2..bc437808 100644 --- a/about/index.html +++ b/about/index.html @@ -408,7 +408,7 @@

- 29 + 30 日志 @@ -419,7 +419,7 @@

- 29 + 30 分类 @@ -430,7 +430,7 @@

- 26 + 27 标签 diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html index 5a67fb20..7ddacc80 100644 --- a/archives/2019/10/index.html +++ b/archives/2019/10/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -546,7 +546,7 @@

- 29 + 30 日志 @@ -557,7 +557,7 @@

@@ -568,7 +568,7 @@

diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html index a197ab6b..1da21b11 100644 --- a/archives/2019/11/index.html +++ b/archives/2019/11/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 29 + 30 日志 @@ -522,7 +522,7 @@

@@ -533,7 +533,7 @@

diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html index be46cb26..4e1eafbc 100644 --- a/archives/2019/12/index.html +++ b/archives/2019/12/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 29 + 30 日志 @@ -522,7 +522,7 @@

@@ -533,7 +533,7 @@

diff --git a/archives/2019/index.html b/archives/2019/index.html index 7727188a..3a86123f 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -725,7 +725,7 @@

- 29 + 30 日志 @@ -736,7 +736,7 @@

@@ -747,7 +747,7 @@

diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html index 8d9d8d3f..2a37f1e1 100644 --- a/archives/2019/page/2/index.html +++ b/archives/2019/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -480,7 +480,7 @@

- 29 + 30 日志 @@ -491,7 +491,7 @@

@@ -502,7 +502,7 @@

diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html index 542ad18d..78a2e968 100644 --- a/archives/2020/01/index.html +++ b/archives/2020/01/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -441,7 +441,7 @@

- 29 + 30 日志 @@ -452,7 +452,7 @@

@@ -463,7 +463,7 @@

diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html index 7dda8e34..6d2529a6 100644 --- a/archives/2020/02/index.html +++ b/archives/2020/02/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -406,7 +406,7 @@

- 29 + 30 日志 @@ -417,7 +417,7 @@

@@ -428,7 +428,7 @@

diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index 4c89c97e..c0fd5137 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 29 + 30 日志 @@ -522,7 +522,7 @@

@@ -533,7 +533,7 @@

diff --git a/archives/2020/04/index.html b/archives/2020/04/index.html index 9a1c0c2f..8624187b 100644 --- a/archives/2020/04/index.html +++ b/archives/2020/04/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -511,7 +511,7 @@

- 29 + 30 日志 @@ -522,7 +522,7 @@

@@ -533,7 +533,7 @@

diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index 2076e1ab..d503914b 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -441,7 +441,7 @@

- 29 + 30 日志 @@ -452,7 +452,7 @@

@@ -463,7 +463,7 @@

diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html index 40230772..d8865e6d 100644 --- a/archives/2020/06/index.html +++ b/archives/2020/06/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -406,7 +406,7 @@

- 29 + 30 日志 @@ -417,7 +417,7 @@

@@ -428,7 +428,7 @@

diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html index 74e6e3f4..76a4b8df 100644 --- a/archives/2020/07/index.html +++ b/archives/2020/07/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -406,7 +406,7 @@

- 29 + 30 日志 @@ -417,7 +417,7 @@

@@ -428,7 +428,7 @@

diff --git a/archives/2020/08/index.html b/archives/2020/08/index.html index f8ffa264..440310ea 100644 --- a/archives/2020/08/index.html +++ b/archives/2020/08/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -406,7 +441,7 @@

- 29 + 30 日志 @@ -417,7 +452,7 @@

@@ -428,7 +463,7 @@

diff --git a/archives/2020/index.html b/archives/2020/index.html index 31727d1c..5e605a15 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -633,41 +668,6 @@

- - - - - - - - - - - - - - - @@ -725,7 +725,7 @@

- 29 + 30 日志 @@ -736,7 +736,7 @@

@@ -747,7 +747,7 @@

diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html index 1e84f192..e727088d 100644 --- a/archives/2020/page/2/index.html +++ b/archives/2020/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -585,7 +620,7 @@

- 29 + 30 日志 @@ -596,7 +631,7 @@

@@ -607,7 +642,7 @@

diff --git a/archives/index.html b/archives/index.html index a92c7020..87df985d 100644 --- a/archives/index.html +++ b/archives/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -633,41 +668,6 @@

- - - - - - - - - - - - - - - @@ -725,7 +725,7 @@

- 29 + 30 日志 @@ -736,7 +736,7 @@

@@ -747,7 +747,7 @@

diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 8ceb0a64..4443c298 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -638,41 +673,6 @@

- - - - - - - - - - - - - - - @@ -730,7 +730,7 @@

- 29 + 30 日志 @@ -741,7 +741,7 @@

@@ -752,7 +752,7 @@

diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 107bcd6e..59d04ee3 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -308,7 +308,7 @@

Java 搬运工 & 终身学习 - 嗯..! 目前共计 29 篇日志。 继续努力。 + 嗯..! 目前共计 30 篇日志。 继续努力。 @@ -327,6 +327,41 @@

2019

+ + + + + + + + + + + + + + +
@@ -690,7 +725,7 @@

- 29 + 30 日志 @@ -701,7 +736,7 @@

@@ -712,7 +747,7 @@

diff --git a/atom.xml b/atom.xml index 015be2d3..7521722f 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2020-08-09T14:44:05.879Z + 2020-08-23T06:22:47.888Z https://www.mghio.cn/ @@ -16,6 +16,35 @@ Hexo + + Java 集合类 List 的那些坑 + + https://www.mghio.cn/post/d7d0fc76.html + 2020-08-23T06:20:29.000Z + 2020-08-23T06:22:47.888Z + + 现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑。

第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作

例如我们执行以下代码:

1
2
List<String> strings = Arrays.asList("m", "g");
strings.add("h");

会抛出 java.lang.UnsupportedOperationException 异常,此时你内心 OS what?明明返回的 ArrayList 为啥不能往里面增加元素,这以后还能好好的增加元素吗?,然后果断开启 Debug 大法:

list-pit-one.jpg

发现返回的 ArrayList 并不是我们常用的 java.util.ArrayList,而是 Arrays 的内部类 java.util.Arrays.ArrayList。进入方法 Arrays.asList 源码如下:

1
2
3
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}

方法返回的是 Arrays 的静态内部类 java.util.Arrays.ArrayList,该类虽然和 java.util.ArrayList 也继承自抽象类 java.util.AbstractList ,但是通过该类的源码发现它并没有对抽象父类AbstractListadd 方法默认就是抛出 java.lang.UnsupportedOperationException 异常。

list-pit-two.jpg

这个坑的根本原因是我们调用返回的 stringsadd 方法是继承自抽象父类的 add 方法,而抽象父类的方法默认就是抛出 java.lang.UnsupportedOperationException 这个异常。

第二个坑,Arrays.asList 方法返回的新 List 和该方法原始入参数组修改会相互影响

Arrays.asList 方法除了上面这个 不支持增加、删除元素 这个坑之外,还有另外一个坑:

list-pit-three.jpg

从以上代码可以发现,对原始数组的修改会影响我们通过 Arrays.asList方法获得的新 List,深入 java.util.Arrays.ArrayList 的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;

ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}

...

}

可以发现是直接使用了原始的数组,所有当我们使用 Arrays.asList 方式获得的 List 时要特别注意,因为共享了数组,相互修改时可能产生一些意想不到的 Bug。标准的姿势之一是将其作为 ArrayList 构造方法的参数重新 new 一个 List 出来即可(e.g. List<String> stringList = new ArrayList<>(Arrays.asList(arrays)))或者通过 Guava 库中的 Lists.newArrayList ,将返回的新 List 和原始的数组解耦,就不会再互相影响了。

第三个坑,直接遍历 List 集合删除元素会报错

在直接遍历集合元素时增加、删除元素会报错,比如执行如下代码:

1
2
3
4
5
6
List<String> stringList = Lists.newArrayList("m", "g", "h");
for (String s : stringList) {
if (Arrays.asList("m", "h").contains(s)) {
stringList.remove(s);
}
}

以上代码可以正常编译通过,但是执行时会抛出 java.util.ConcurrentModificationException 异常,查看其源码可以发现,删除元素方法 remove 会使集合结构发生修改,也就是 modCount(集合实际修改的次数)会修改,在循环过程中,会比较当前 List 的集合实际修改的次数 modCount 与迭代器修改的次数 expectedModCount ,而 expectedModCount 是初始化时的 modCount, 二者不相等,就会报 ConcurrentModificationException 异常。解决方法主要有两种方式,1.使用 ArrayList 的迭代器方式遍历,然后调用其中的方法。2.在 JDK 1.8+ 可以使用 removeIf 方法进行删除操作。

最后扎心一问:调用 ArrayListremove 方法传入 int 基本类型的数字和 Integer 包装类型的数字,执行结果是不是一样的?

]]>
+ + + + <p>现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑。 </p> +<h4 id="第一个坑:Arrays-asList-方法返回的-List-不支持增加、删除操作"><a href="#第一个坑:Arrays-asList-方法返回的-List-不支持增加、删除操作" class="headerlink" title="第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作"></a>第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作</h4><p>例如我们执行以下代码:</p> +<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; strings = Arrays.asList(<span class="string">"m"</span>, <span class="string">"g"</span>);</span><br><span class="line">strings.add(<span class="string">"h"</span>);</span><br></pre></td></tr></table></figure> + + + + + + + + + + + + + +
+ RabbitMQ 基础概念进阶 @@ -605,35 +634,6 @@ - - - - - - - - Java 多线程基础(一) - - https://www.mghio.cn/post/7eb2637f.html - 2019-12-07T13:56:55.000Z - 2019-12-08T15:20:18.832Z - - 简介

在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

进程与线程的区别

进程

进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

线程

线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

二者的区别
  1. 调度 线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
  2. 并发性 不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行
  3. 拥有资源 进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源
  4. 系统开销 在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销

创建线程的方式

在 Java 中使用 Thread 类代表线程,所有的线程对象都必须是 Thread 类或者其子类的实例,Java 中创建线程主要有以下三种方式:

方式一 继承 Thread 类

step 1 定义一个类继承自 Thread 类,然后重写该类的 run 方法,这个方法的内容表示线程要完成的任务
step 2 创建线程对象,即创建 Thread 类子类的实例
step 3 调用步骤二中创建出来的对象的 start 方法来启动线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* @author mghio
* @date: 2019-12-07
* @version: 1.0
* @description: 通过继承 Thread 类的方式创建线程
* @since JDK 1.8
*/
public class CreateThreadByExtendsThread extends Thread {

@Override
public void run() {
IntStream.rangeClosed(1, 10).forEach(i -> System.out.println(Thread.currentThread().getName() + " " + i));
}

public static void main(String[] args) {
CreateThreadByExtendsThread threadOne = new CreateThreadByExtendsThread();
CreateThreadByExtendsThread threadTwo = new CreateThreadByExtendsThread();
CreateThreadByExtendsThread threadThree = new CreateThreadByExtendsThread();

threadOne.start();
threadTwo.start();
threadThree.start();
}

}
方式二 实现 Runnable 接口

step 1 定义一个类实现 Runnable 接口,然后实现该接口的 run 方法,这个方法的内容同样也表示线程要完成的任务
step 2 创建 Runnable 接口实现类的实例,并使用该实例作为 Thraed 构造方法的参数创建 Thread 类的对象,该对象才是真正的线程对象
step 3 调用线程对象的 start 方法来启动该线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @author mghio
* @date: 2019-12-07
* @version: 1.0
* @description: 通过实现 Runnable 接口的方式创建线程
* @since JDK 1.8
*/
public class CreateThreadByImplementsRunnable implements Runnable {

@Override
public void run() {
IntStream.rangeClosed(1, 10).forEach(i -> System.out.println(Thread.currentThread().getName() + " " + i));
}

public static void main(String[] args) {
CreateThreadByImplementsRunnable target = new CreateThreadByImplementsRunnable();
new Thread(target, "thread-one").start();
new Thread(target, "thread-two").start();
new Thread(target, "thread-three").start();
}

}
方式三 实现 Callable 接口

step 1 定义一个类实现 Callable 接口,然后实现该接口的 call 方法,这个方法的内容同样也表示线程要完成的任务,并且有返回值
step 2 创建 Callable 接口实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了 Callable 对象的 call 方法的返回值
step 3 并使用 FutureTask 对象作为 Thraed 构造方法的参数创建 Thread 对象,并调用该对象的 start 方法启动线程
step 4 调用 FutureTask 对象的 get 方法获取线程执行结束后的返回值

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
/**
* @author mghio
* @date: 2019-12-07
* @version: 1.0
* @description: 通过实现 Callable 接口的方式创建线程
* @since JDK 1.8
*/
public class CreateThreadByImplementsCallable implements Callable<Integer> {

@Override
public Integer call() {
AtomicInteger count = new AtomicInteger();
IntStream.rangeClosed(0, 10).forEach(i -> {
System.out.println(Thread.currentThread().getName() + " " + i);
count.getAndIncrement();
});

return count.get();
}

public static void main(String[] args) {
CreateThreadByImplementsCallable target = new CreateThreadByImplementsCallable();
FutureTask<Integer> futureTask = new FutureTask<>(target);

IntStream.rangeClosed(0, 10).forEach(i -> {
System.out.println(Thread.currentThread().getName() + " 的循环变量 i 的值" + i);
if (i == 8) {
new Thread(futureTask, "有返回值的线程").start();
}
});

try {
System.out.println("有返回值线程的返回值:" + futureTask.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}

}

通过以上可以看出,其实通过实现 Runnable 接口和实现 Callable 接口这两种方式创建线程基本相同,采用实现 RunnableCallable 接口的方式创建线程时,线程类只是实现接口,还可以继承其它类(PS:Java 单继承决定)。在这种方式下,多个线程可以共享同一个 target对象,所以非常适合多个相同线程来处理同一份资源的情况。还有一点就是,使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。,在实际项目中如果使用这三种方式创建线程,如果创建关闭频繁会消耗系统资源影响性能,而使用线程池可以不用线程的时候放回线程池,用的时候再从线程池取,所以在我们项目开发中主要还是使用线程池,有关线程池的可以看看这两篇 Java 线程池(一)Java 线程池(二)

线程的几种状态

线程是一个动态执行的过程,它也有一个从产生到死亡的过程,在 Java 中一个线程完整的生命周期一共包含以下五种状态:
新建状态(New)
当使用 new 关键字和 Thread 类或其子类创建一个线程对象后,那么线程就进入了新建状态,此时它和其它的 Java 对象一样,仅仅由 JVM 分配了内存,并初始化其成员变量值,它会一直保持这个状态直到调用该对象的 start 方法。

就绪状态(Runnable)
当线程对象调用了 start 方法之后,该线程就进入了就绪状态。就绪状态的线程会放在一个就绪队列中,等待 JVM 里的调度器进行调度。处于就绪状态的线程,随时可能被 CPU 调度执行。

运行状态(Running)
如果就绪状态的执行被 CPU 调度执行,就可以执行 run 方法,此时线程就处于线程状态。处于运行状态的线程最复杂,它可以变为阻塞状态就绪状态死亡状态。需要注意一点,线程变为运行状态之前的状态只能是就绪状态

阻塞状态(Blocked)
线程变为阻塞状态是因为某种原因放弃 CPU 的使用权,暂时停止运行,如果执行了 sleepsuspend 等方法,释放了所占用的资源之后,线程就从运行状态进入阻塞状态。等待睡眠时间结束或者获得设备资源之可以重新进入就绪状态。阻塞可以分为以下三种:

  1. 等待阻塞 处于运行状态的线程调用wait方法,会使线程进入等待阻塞状态
  2. 同步阻塞 当线程获取 synchronized 同步锁因为同步锁被其他线程占用而失败后,会使线程进入同步阻塞
  3. 其它阻塞 通过调用线程的sleepjoin发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep状态超时,join等待线程终止或超时,或者 I/O 处理完毕,线程重新回到就绪状态

死亡状态(Dead)
一个处于运行状态的线程执行完了 run 方法或者因为其它终止条件发生时,线程就会进入到死亡状态,该线程结束生命周期。
以上线程各种状态的流转用一张图表示如下:

thread-state-transfer.png

线程常用方法

线程中常用的方法按照来源可以分为两类,一类是继承自 Object 类的方法,如下所示:

方法描述
public final native void notify()唤醒在此对象监视器上等待的单个线程,使其进入就绪状态
public final native void notifyAll()唤醒在此对象监视器上等待的所有线程,使其进入就绪状态
public final void wait()让当前线程处于·等待阻塞状态,直到其他线程调用此对象的notify方法或notifyAll方法,当前线程被唤醒,会释放它所持有的锁
public final native void wait(long timeout)让当前线程处于·等待阻塞状态,直到其他线程调用此对象的notify方法或notifyAll方法,当前线程被唤醒
public final void wait(long timeout, int nanos)让当前线程处于·等待阻塞状态,直到其他线程调用此对象的notify方法或notifyAll方法或者其他某个线程中断当前线程,或者已超过某个实际时间量,当前线程被唤醒

另一类是 Thread 类定义的方法,如下所示:

方法描述
public static native void yield()暂停当前正在执行的线程对象,并执行其他线程,yield 方法不会释放锁
public static native void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),sleep 方法不会释放锁
public final void join()当某个程序执行流中调用其他线程的 join 方法时,调用线程将被阻塞,直到被 join 的线程执行完毕
public void interrupt()用于中断本线程,这个方法被调用时,会立即将线程的中断标志设置为 true
public static boolean interrupted()Thread 类的一个静态方法,它返回一个布尔类型指明当前线程是否已经被中断,interrupted 方法除了返回中断标记之外,它还会清除中断标记(即将中断标记设为 false)
public boolean isInterrupted()Thread 类的一个实例方法,它返回一个布尔类型指明当前线程是否已经被中断,isInterrupted 方法仅仅返回中断标记,不会清楚终端标记

线程的优先级

每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。Java 线程的优先级是一个整数,其取值范围是1(Thread.MIN_PRIORITY )~ 10(Thread.MAX_PRIORITY )。默认情况下,每一个线程都会分配一个优先级NORM_PRIORITY(5)。具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源,Thread 类提供了 setPrioritygetPriority 方法来更改和获取线程优先级(需要注意的是: 线程优先级不能保证线程执行的顺序,而且非常依赖于平台)。


参考文章

]]> - - - - <h4 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h4><p>在接触<code>多线程</code>之前,在我们程序中在任意时刻都只能执行一个步骤,称之为<code>单线程</code>。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。</p> -<h4 id="进程与线程的区别"><a href="#进程与线程的区别" class="headerlink" title="进程与线程的区别"></a>进程与线程的区别</h4><h5 id="进程"><a href="#进程" class="headerlink" title="进程"></a>进程</h5><p>进程是<code>操作系统资源分配</code>的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(<code>PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样</code>)。 </p> -<h5 id="线程"><a href="#线程" class="headerlink" title="线程"></a>线程</h5><p>线程是<code>任务调度和执行</code>的基本单位,也被称为<code>轻量级进程</code>,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。</p> - - - - - - - - - diff --git a/baidusitemap.xml b/baidusitemap.xml index 3f80b021..ca2148a9 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -1,6 +1,9 @@ + https://www.mghio.cn/post/d7d0fc76.html + 2020-08-23 + https://www.mghio.cn/post/f92758d8.html 2020-08-09 diff --git a/categories/JDK/Java/index.html b/categories/JDK/Java/index.html index 567c5744..739b1861 100644 --- a/categories/JDK/Java/index.html +++ b/categories/JDK/Java/index.html @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index ea06ef92..8f1c2f1b 100644 --- "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/JDK/index.html b/categories/JDK/index.html index 738b7a13..737748ea 100644 --- a/categories/JDK/index.html +++ b/categories/JDK/index.html @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/Bloom-filter/index.html b/categories/Java/Bloom-filter/index.html index 8da657f9..9f78d678 100644 --- a/categories/Java/Bloom-filter/index.html +++ b/categories/Java/Bloom-filter/index.html @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/GC/index.html b/categories/Java/GC/index.html index 8ae8a6d8..57e23568 100644 --- a/categories/Java/GC/index.html +++ b/categories/Java/GC/index.html @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/Guava/String/index.html b/categories/Java/Guava/String/index.html index 5e604947..3356c5e4 100644 --- a/categories/Java/Guava/String/index.html +++ b/categories/Java/Guava/String/index.html @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/Guava/index.html b/categories/Java/Guava/index.html index 6c806d72..d109b45b 100644 --- a/categories/Java/Guava/index.html +++ b/categories/Java/Guava/index.html @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/IDEA/index.html b/categories/Java/IDEA/index.html index 37eed51f..49589019 100644 --- a/categories/Java/IDEA/index.html +++ b/categories/Java/IDEA/index.html @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" index 525116bd..294df884 100644 --- "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" +++ "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/IO\346\250\241\345\236\213/index.html" "b/categories/Java/IO\346\250\241\345\236\213/index.html" index 1d73c13f..4cb7ac11 100644 --- "a/categories/Java/IO\346\250\241\345\236\213/index.html" +++ "b/categories/Java/IO\346\250\241\345\236\213/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/JVM/index.html b/categories/Java/JVM/index.html index cc9d3367..1ad9f56f 100644 --- a/categories/Java/JVM/index.html +++ b/categories/Java/JVM/index.html @@ -413,7 +413,7 @@

- 29 + 30 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git a/categories/Java/List/index.html b/categories/Java/List/index.html new file mode 100644 index 00000000..55ed4869 --- /dev/null +++ b/categories/Java/List/index.html @@ -0,0 +1,1254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: List | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/Java/index.html b/categories/Java/index.html index ab37deac..e1635798 100644 --- a/categories/Java/index.html +++ b/categories/Java/index.html @@ -309,6 +309,32 @@

Java分类 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -625,7 +625,7 @@

- 29 + 30 日志 @@ -636,7 +636,7 @@

@@ -647,7 +647,7 @@

diff --git a/categories/Java/page/2/index.html b/categories/Java/page/2/index.html index c36f5d09..e990cecd 100644 --- a/categories/Java/page/2/index.html +++ b/categories/Java/page/2/index.html @@ -309,6 +309,32 @@

Java分类 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -625,7 +625,7 @@

- 29 + 30 日志 @@ -636,7 +636,7 @@

@@ -647,7 +647,7 @@

diff --git a/categories/Java/page/3/index.html b/categories/Java/page/3/index.html index d2f3c65b..40a6f28e 100644 --- a/categories/Java/page/3/index.html +++ b/categories/Java/page/3/index.html @@ -309,6 +309,32 @@

Java分类 + + + + + +
@@ -469,7 +495,7 @@

- 29 + 30 日志 @@ -480,7 +506,7 @@

@@ -491,7 +517,7 @@

diff --git a/categories/Java/unit-test/index.html b/categories/Java/unit-test/index.html index 539b5e53..16648785 100644 --- a/categories/Java/unit-test/index.html +++ b/categories/Java/unit-test/index.html @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/unit-test/mockito/index.html b/categories/Java/unit-test/mockito/index.html index 8ffcbe75..2d7ad0f1 100644 --- a/categories/Java/unit-test/mockito/index.html +++ b/categories/Java/unit-test/mockito/index.html @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\345\216\237\347\220\206/index.html" "b/categories/Java/\345\216\237\347\220\206/index.html" index fa2dc548..c6540004 100644 --- "a/categories/Java/\345\216\237\347\220\206/index.html" +++ "b/categories/Java/\345\216\237\347\220\206/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\345\217\215\345\260\204/index.html" "b/categories/Java/\345\217\215\345\260\204/index.html" index f413b093..9f4d6587 100644 --- "a/categories/Java/\345\217\215\345\260\204/index.html" +++ "b/categories/Java/\345\217\215\345\260\204/index.html" @@ -413,7 +413,7 @@

- 29 + 30 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" index 315e4917..fba05b2c 100644 --- "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" @@ -413,7 +413,7 @@

- 29 + 30 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git "a/categories/Java/\345\271\266\345\217\221/index.html" "b/categories/Java/\345\271\266\345\217\221/index.html" index 7f0b7606..fba89379 100644 --- "a/categories/Java/\345\271\266\345\217\221/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/index.html" @@ -439,7 +439,7 @@

- 29 + 30 日志 @@ -450,7 +450,7 @@

@@ -461,7 +461,7 @@

diff --git "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" index 2ae8aa70..bb7bd578 100644 --- "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\345\274\202\346\255\245/index.html" "b/categories/Java/\345\274\202\346\255\245/index.html" index 723418af..e54d142f 100644 --- "a/categories/Java/\345\274\202\346\255\245/index.html" +++ "b/categories/Java/\345\274\202\346\255\245/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" index 220829bc..f41dab26 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 56a1f57d..87876e0d 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" index c20fba62..b1868be7 100644 --- "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" +++ "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" @@ -413,7 +413,7 @@

- 29 + 30 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git "a/categories/Java/\351\207\215\346\236\204/index.html" "b/categories/Java/\351\207\215\346\236\204/index.html" index 0976f6ce..6962f241 100644 --- "a/categories/Java/\351\207\215\346\236\204/index.html" +++ "b/categories/Java/\351\207\215\346\236\204/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Linux\347\254\224\350\256\260/index.html" "b/categories/Linux\347\254\224\350\256\260/index.html" index b3f4a086..fc46e397 100644 --- "a/categories/Linux\347\254\224\350\256\260/index.html" +++ "b/categories/Linux\347\254\224\350\256\260/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/RabbitMQ/Java/index.html b/categories/RabbitMQ/Java/index.html index b78f4a3a..5c466f6b 100644 --- a/categories/RabbitMQ/Java/index.html +++ b/categories/RabbitMQ/Java/index.html @@ -413,7 +413,7 @@

- 29 + 30 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git a/categories/RabbitMQ/index.html b/categories/RabbitMQ/index.html index 5aade16a..d3e362ba 100644 --- a/categories/RabbitMQ/index.html +++ b/categories/RabbitMQ/index.html @@ -413,7 +413,7 @@

- 29 + 30 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git a/categories/index.html b/categories/index.html index d9e6aaaa..900b853c 100644 --- a/categories/index.html +++ b/categories/index.html @@ -317,10 +317,10 @@

@@ -378,7 +378,7 @@

- 29 + 30 日志 @@ -389,7 +389,7 @@

@@ -400,7 +400,7 @@

diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" index 1632afa8..4080b426 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 03c67096..90b28c90 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -387,7 +387,7 @@

- 29 + 30 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/css/main.css b/css/main.css index c8eefc1d..05ea609f 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #5ebd9a; + background: #6bffff; } .links-of-blogroll { font-size: 13px; diff --git a/index.html b/index.html index 85da1eba..3cba7c6f 100644 --- a/index.html +++ b/index.html @@ -310,7 +310,7 @@

Java 搬运工 & 终身学习
- +

@@ -456,11 +456,12 @@

-

上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

-

消息生产者发送的消息不可达时如何处理

RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

+

现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑。

+

第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作

例如我们执行以下代码:

+
1
2
List<String> strings = Arrays.asList("m", "g");
strings.add("h");
- + 阅读全文 »
@@ -513,7 +514,7 @@

- +

-

+

@@ -659,11 +660,11 @@

-

什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

-

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

+

上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

+

消息生产者发送的消息不可达时如何处理

RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

- + 阅读全文 »
@@ -716,7 +717,7 @@

- +

-

+

@@ -873,10 +863,11 @@

-

前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

+

什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

+

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

- + 阅读全文 »
@@ -929,7 +920,7 @@

前言 - +

@@ -1086,10 +1077,10 @@

-

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

+

前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

- + 阅读全文 »
@@ -1142,7 +1133,7 @@

前言 - +

@@ -1299,10 +1290,10 @@

-

前言

对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

+

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

- + 阅读全文 »
@@ -1355,7 +1346,7 @@

前言 - +

@@ -1501,11 +1503,10 @@

-

前言

在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

-

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

+

前言

对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

- + 阅读全文 »
@@ -1558,7 +1559,7 @@

- +

-

+

@@ -1704,14 +1705,11 @@

-

前言

在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

-

原理

布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

-
-

A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

-
+

前言

在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

+

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

- + 阅读全文 »
@@ -1764,7 +1762,7 @@

原理 - +

@@ -1921,15 +1908,14 @@

-

前言

Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

-

如何使用

Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

-
1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
- -

对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

-
1
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
+

前言

在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

+

原理

布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

+
+

A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

+
- + 阅读全文 »
@@ -1982,7 +1968,7 @@

- +

-

+

@@ -2128,11 +2125,15 @@

-

前言

在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

-

什么是 CompletableFuture

CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

+

前言

Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

+

如何使用

Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

+
1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
+ +

对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

+
1
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
- + 阅读全文 »
@@ -2185,7 +2186,7 @@

- +

-

+

@@ -2331,11 +2332,11 @@

-

前言

在日常生活中,当我们买的水果放久了之后会发出一种难闻的气味(“坏味道”),这个时候我们就应该把它扔掉。同样,代码也有“坏味道”,当然确定什么是和不是代码“坏味道”是主观的,它会随语言、开发人员和开发方法的不同而不同。在工作当中,很多时候都是在维护之前的项目和在此基础上增加一些新功能,为了能让项目代码易于理解和维护,要时刻注意代码中的“坏味道”,当发现代码如果有坏味道了,要及时去重构它使其变成优秀的整洁的代码。本文列举代码中一些常见的“坏味道”和相应的重构方案。

-

过长方法 (Long Method)

这种“坏味道”表现为方法代码行数过长,方法行数越长,就越难以理解和维护它。一个比较有用的方案就是当你觉得需要对方法中的内容加注释的时候,你应该将这个代码段作为一个新方法提取出来,哪怕有时候仅仅是一行代码也可以这么做,而且方法的命名要尽量做到见名知意,如果局部变量和参数干扰到方法的提取,则可以使用引入参数对象来进行提取。一般情况下,方法中条件运算符和循环是可以将代码移至单独方法的一个很好的代码段,对于条件运算符,可以尝试分解条件,如果方法出现循环,可以尝试提取方法。

+

前言

在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

+

什么是 CompletableFuture

CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

- + 阅读全文 »
@@ -2427,7 +2428,7 @@

- 29 + 30 日志 @@ -2438,7 +2439,7 @@

- 29 + 30 分类 @@ -2449,7 +2450,7 @@

- 26 + 27 标签 diff --git a/page/2/index.html b/page/2/index.html index ba378974..97b4caa5 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -310,7 +310,7 @@

Java 搬运工 & 终身学习
- +

@@ -2454,7 +2453,7 @@
线程 - 26 + 27 标签 diff --git a/page/3/index.html b/page/3/index.html index 3ded4988..94ca34f3 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -305,6 +305,210 @@

Java 搬运工 & 终身学习 +
+ + + +
+ + + + + + + +
+ + + +

+ +

+ + + +
+ + + + + +
+ + + + + + +

简介

在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

+

进程与线程的区别

进程

进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

+
线程

线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

+ +
+ + 阅读全文 » + +
+ + + +
+ + + + + + + + + + + + +
+ + + + + + + + +
+ +
+
+ + + +
+ + + + + + + + + + +
@@ -2189,7 +2393,7 @@

- 29 + 30 日志 @@ -2200,7 +2404,7 @@

@@ -2211,7 +2415,7 @@

diff --git a/post/102cd3d9.html b/post/102cd3d9.html index fc56947f..7f30ce86 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -847,7 +847,7 @@

总结 - 29 + 30 日志 @@ -858,7 +858,7 @@

总结 - 29 + 30 分类 @@ -869,7 +869,7 @@

总结 - 26 + 27 标签 diff --git a/post/11cb7677.html b/post/11cb7677.html index 059cfb50..a900d1f4 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -698,7 +698,7 @@

总结 - 29 + 30 日志 @@ -709,7 +709,7 @@

总结 - 29 + 30 分类 @@ -720,7 +720,7 @@

总结 - 26 + 27 标签 diff --git a/post/192cb539.html b/post/192cb539.html index 54354080..f31b06dc 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -762,7 +762,7 @@

- 29 + 30 日志 @@ -773,7 +773,7 @@

@@ -784,7 +784,7 @@

diff --git a/post/24042edf.html b/post/24042edf.html index 4c47a7cc..c2f8cb09 100644 --- a/post/24042edf.html +++ b/post/24042edf.html @@ -770,7 +770,7 @@

总结 - 29 + 30 日志 @@ -781,7 +781,7 @@

总结 - 29 + 30 分类 @@ -792,7 +792,7 @@

总结 - 26 + 27 标签 diff --git a/post/34755d6c.html b/post/34755d6c.html index 44c0c4ca..e72b8a79 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -677,7 +677,7 @@

总结 - 29 + 30 日志 @@ -688,7 +688,7 @@

总结 - 29 + 30 分类 @@ -699,7 +699,7 @@

总结 - 26 + 27 标签 diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index da713c4b..9a371c0e 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -744,7 +744,7 @@

总结 - 29 + 30 日志 @@ -755,7 +755,7 @@

总结 - 29 + 30 分类 @@ -766,7 +766,7 @@

总结 - 26 + 27 标签 diff --git a/post/4615256d.html b/post/4615256d.html index 1d085e30..7269938e 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -753,7 +753,7 @@

- 29 + 30 日志 @@ -764,7 +764,7 @@

- 29 + 30 分类 @@ -775,7 +775,7 @@

- 26 + 27 标签 diff --git a/post/4b00e13c.html b/post/4b00e13c.html index 65189ddd..93befd47 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -852,7 +852,7 @@

总结 - 29 + 30 日志 @@ -863,7 +863,7 @@

总结 - 29 + 30 分类 @@ -874,7 +874,7 @@

总结 - 26 + 27 标签 diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index 485a8698..fdb662fe 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -685,7 +685,7 @@

总结 - 29 + 30 日志 @@ -696,7 +696,7 @@

总结 - 29 + 30 分类 @@ -707,7 +707,7 @@

总结 - 26 + 27 标签 diff --git a/post/51e5bd99.html b/post/51e5bd99.html index e91ee30d..b7558ebb 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -726,7 +726,7 @@

- 29 + 30 日志 @@ -737,7 +737,7 @@

- 29 + 30 分类 @@ -748,7 +748,7 @@

- 26 + 27 标签 diff --git a/post/710bd10b.html b/post/710bd10b.html index 5a48117f..cf1bcb0e 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -732,7 +732,7 @@

总结 - 29 + 30 日志 @@ -743,7 +743,7 @@

总结 - 29 + 30 分类 @@ -754,7 +754,7 @@

总结 - 26 + 27 标签 diff --git a/post/7528c810.html b/post/7528c810.html index 39ceed4b..821fcd80 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -715,7 +715,7 @@

总结 - 29 + 30 日志 @@ -726,7 +726,7 @@

总结 - 29 + 30 分类 @@ -737,7 +737,7 @@

总结 - 26 + 27 标签 diff --git a/post/7b9ead86.html b/post/7b9ead86.html index b93dbe89..0a7f1c64 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -715,7 +715,7 @@

总结 - 29 + 30 日志 @@ -726,7 +726,7 @@

总结 - 29 + 30 分类 @@ -737,7 +737,7 @@

总结 - 26 + 27 标签 diff --git a/post/7eb2637f.html b/post/7eb2637f.html index 79cdf0e7..bcf0444e 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -754,7 +754,7 @@

- 29 + 30 日志 @@ -765,7 +765,7 @@

- 29 + 30 分类 @@ -776,7 +776,7 @@

- 26 + 27 标签 diff --git a/post/817c7d82.html b/post/817c7d82.html index 3dd8ca9c..f17f66cf 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1323,7 +1323,7 @@

- 29 + 30 日志 @@ -1334,7 +1334,7 @@
- 29 + 30 分类 @@ -1345,7 +1345,7 @@
- 26 + 27 标签 diff --git a/post/8a061473.html b/post/8a061473.html index 6aefe222..ece0a027 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -791,7 +791,7 @@
- 29 + 30 日志 @@ -802,7 +802,7 @@
- 29 + 30 分类 @@ -813,7 +813,7 @@
- 26 + 27 标签 diff --git a/post/8bd965a0.html b/post/8bd965a0.html index 9cd0b856..007436a2 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -714,7 +714,7 @@

- 29 + 30 日志 @@ -725,7 +725,7 @@

@@ -736,7 +736,7 @@

diff --git a/post/99ea2970.html b/post/99ea2970.html index e1822301..75c58eae 100644 --- a/post/99ea2970.html +++ b/post/99ea2970.html @@ -710,7 +710,7 @@

- 29 + 30 日志 @@ -721,7 +721,7 @@

@@ -732,7 +732,7 @@

diff --git a/post/a38c0645.html b/post/a38c0645.html index 721b1076..989dd491 100644 --- a/post/a38c0645.html +++ b/post/a38c0645.html @@ -694,7 +694,7 @@

总结 - 29 + 30 日志 @@ -705,7 +705,7 @@

总结 - 29 + 30 分类 @@ -716,7 +716,7 @@

总结 - 26 + 27 标签 diff --git a/post/ab706eb5.html b/post/ab706eb5.html index d8a1c2c4..64f2ce45 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -697,7 +697,7 @@

总结 - 29 + 30 日志 @@ -708,7 +708,7 @@

总结 - 29 + 30 分类 @@ -719,7 +719,7 @@

总结 - 26 + 27 标签 diff --git a/post/b1d4025b.html b/post/b1d4025b.html index b62ade15..8b825710 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -627,7 +627,7 @@

hello world

- 29 + 30 日志 @@ -638,7 +638,7 @@

hello world

@@ -649,7 +649,7 @@

hello world

diff --git a/post/bc557e1a.html b/post/bc557e1a.html index 3a620f5f..798108f1 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -762,7 +762,7 @@
- 29 + 30 日志 @@ -773,7 +773,7 @@
- 29 + 30 分类 @@ -784,7 +784,7 @@
- 26 + 27 标签 diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index 5166cbed..8cc88259 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -714,7 +714,7 @@

- 29 + 30 日志 @@ -725,7 +725,7 @@

@@ -736,7 +736,7 @@

diff --git a/post/c34b451f.html b/post/c34b451f.html index f61ddf5b..860b9476 100644 --- a/post/c34b451f.html +++ b/post/c34b451f.html @@ -753,7 +753,7 @@

总结 - 29 + 30 日志 @@ -764,7 +764,7 @@

总结 - 29 + 30 分类 @@ -775,7 +775,7 @@

总结 - 26 + 27 标签 diff --git a/post/d7d0fc76.html b/post/d7d0fc76.html new file mode 100644 index 00000000..14749f43 --- /dev/null +++ b/post/d7d0fc76.html @@ -0,0 +1,1574 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Java 集合类 List 的那些坑 | mghio + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

Java 集合类 List 的那些坑

+ + + +
+ + + + + +
+ + + + + +

现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑。

+

第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作

例如我们执行以下代码:

+
1
2
List<String> strings = Arrays.asList("m", "g");
strings.add("h");
+ + +

会抛出 java.lang.UnsupportedOperationException 异常,此时你内心 OS what?明明返回的 ArrayList 为啥不能往里面增加元素,这以后还能好好的增加元素吗?,然后果断开启 Debug 大法:

+

list-pit-one.jpg

+

发现返回的 ArrayList 并不是我们常用的 java.util.ArrayList,而是 Arrays 的内部类 java.util.Arrays.ArrayList。进入方法 Arrays.asList 源码如下:

+
1
2
3
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
+ +

方法返回的是 Arrays 的静态内部类 java.util.Arrays.ArrayList,该类虽然和 java.util.ArrayList 也继承自抽象类 java.util.AbstractList ,但是通过该类的源码发现它并没有对抽象父类AbstractListadd 方法默认就是抛出 java.lang.UnsupportedOperationException 异常。

+

list-pit-two.jpg

+

这个坑的根本原因是我们调用返回的 stringsadd 方法是继承自抽象父类的 add 方法,而抽象父类的方法默认就是抛出 java.lang.UnsupportedOperationException 这个异常。

+

第二个坑,Arrays.asList 方法返回的新 List 和该方法原始入参数组修改会相互影响

Arrays.asList 方法除了上面这个 不支持增加、删除元素 这个坑之外,还有另外一个坑:

+

list-pit-three.jpg

+

从以上代码可以发现,对原始数组的修改会影响我们通过 Arrays.asList方法获得的新 List,深入 java.util.Arrays.ArrayList 的源码:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;

ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}

...

}
+ +

可以发现是直接使用了原始的数组,所有当我们使用 Arrays.asList 方式获得的 List 时要特别注意,因为共享了数组,相互修改时可能产生一些意想不到的 Bug。标准的姿势之一是将其作为 ArrayList 构造方法的参数重新 new 一个 List 出来即可(e.g. List<String> stringList = new ArrayList<>(Arrays.asList(arrays)))或者通过 Guava 库中的 Lists.newArrayList ,将返回的新 List 和原始的数组解耦,就不会再互相影响了。

+

第三个坑,直接遍历 List 集合删除元素会报错

在直接遍历集合元素时增加、删除元素会报错,比如执行如下代码:

+
1
2
3
4
5
6
List<String> stringList = Lists.newArrayList("m", "g", "h");
for (String s : stringList) {
if (Arrays.asList("m", "h").contains(s)) {
stringList.remove(s);
}
}
+ +

以上代码可以正常编译通过,但是执行时会抛出 java.util.ConcurrentModificationException 异常,查看其源码可以发现,删除元素方法 remove 会使集合结构发生修改,也就是 modCount(集合实际修改的次数)会修改,在循环过程中,会比较当前 List 的集合实际修改的次数 modCount 与迭代器修改的次数 expectedModCount ,而 expectedModCount 是初始化时的 modCount, 二者不相等,就会报 ConcurrentModificationException 异常。解决方法主要有两种方式,1.使用 ArrayList 的迭代器方式遍历,然后调用其中的方法。2.在 JDK 1.8+ 可以使用 removeIf 方法进行删除操作。

+

最后扎心一问:调用 ArrayListremove 方法传入 int 基本类型的数字和 Integer 包装类型的数字,执行结果是不是一样的?

+ + +
+ + + + + +
+
-------------本文结束感谢您的阅读-------------
+
+ + + +
+
+ mghio wechat +
微信公众号「mghio」
+
+ +
+ + + +
+
+
请我吃🍗
+ + +
+ +
+ + + +
+ +
+ + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ +
+
+ + + + + +
+ + + + + + + + + +
+
+ +
+ +
+ + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/post/e09f0428.html b/post/e09f0428.html index 4fe0bd50..6751e8b6 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -684,7 +684,7 @@

- 29 + 30 日志 @@ -695,7 +695,7 @@

- 29 + 30 分类 @@ -706,7 +706,7 @@

- 26 + 27 标签 diff --git a/post/ee27c07f.html b/post/ee27c07f.html index 2c0ff3e4..ce5ac068 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -677,7 +677,7 @@

- 29 + 30 日志 @@ -688,7 +688,7 @@

@@ -699,7 +699,7 @@

diff --git a/post/f440d00b.html b/post/f440d00b.html index 381b4da0..b7bbaceb 100644 --- a/post/f440d00b.html +++ b/post/f440d00b.html @@ -713,7 +713,7 @@

总结 - 29 + 30 日志 @@ -724,7 +724,7 @@

总结 - 29 + 30 分类 @@ -735,7 +735,7 @@

总结 - 26 + 27 标签 diff --git a/post/f92758d8.html b/post/f92758d8.html index d20b8b20..f850e4f2 100644 --- a/post/f92758d8.html +++ b/post/f92758d8.html @@ -610,6 +610,10 @@

总结 + + @@ -697,7 +701,7 @@

总结 - 29 + 30 日志 @@ -708,7 +712,7 @@

总结 - 29 + 30 分类 @@ -719,7 +723,7 @@

总结 - 26 + 27 标签 diff --git a/post/fe76043.html b/post/fe76043.html index 04aef053..d2e36217 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -680,7 +680,7 @@

总结 - 29 + 30 日志 @@ -691,7 +691,7 @@

总结 - 29 + 30 分类 @@ -702,7 +702,7 @@

总结 - 26 + 27 标签 diff --git a/search.xml b/search.xml index f77011b0..de51bfa3 100644 --- a/search.xml +++ b/search.xml @@ -1,5 +1,18 @@ + + <![CDATA[Java 集合类 List 的那些坑]]> + %2Fpost%2Fd7d0fc76.html + + + Java + List + + + Java + List + + <![CDATA[RabbitMQ 基础概念进阶]]> %2Fpost%2Ff92758d8.html diff --git a/sitemap.xml b/sitemap.xml index 86386ffa..67627114 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,13 @@ + + https://www.mghio.cn/post/d7d0fc76.html + + 2020-08-23T06:22:47.888Z + + + https://www.mghio.cn/post/f92758d8.html diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index a3002cc8..af95d6aa 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index c374b55e..f8e41708 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index 16c839c8..d889ea0f 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/GC/index.html b/tags/GC/index.html index 769aa6b6..1901a3fc 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/Guava/index.html b/tags/Guava/index.html index 442ed04f..33d75df2 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index 967cadd5..5ec688fc 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index ae4b3945..52579210 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/JDK/index.html b/tags/JDK/index.html index 554861ab..aaec5748 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/JVM/index.html b/tags/JVM/index.html index abb63d8e..99f84e22 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -412,7 +412,7 @@

- 29 + 30 日志 @@ -423,7 +423,7 @@

@@ -434,7 +434,7 @@

diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index 72f7c175..8bf627e2 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index 83530bcc..5c0da6ce 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/Java/index.html b/tags/Java/index.html index b07309f8..4dc48778 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -624,7 +624,7 @@

- 29 + 30 日志 @@ -635,7 +635,7 @@

@@ -646,7 +646,7 @@

diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index 45686068..a475b71d 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -624,7 +624,7 @@

- 29 + 30 日志 @@ -635,7 +635,7 @@

@@ -646,7 +646,7 @@

diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index 6548f7ff..ae853de8 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -309,6 +309,32 @@

Java标签 + + + + + +
@@ -494,7 +520,7 @@

- 29 + 30 日志 @@ -505,7 +531,7 @@

@@ -516,7 +542,7 @@

diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index 3dab3b77..9b0dfaa0 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/List/index.html b/tags/List/index.html new file mode 100644 index 00000000..accf28fd --- /dev/null +++ b/tags/List/index.html @@ -0,0 +1,1253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: List | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/RabbitMQ/index.html b/tags/RabbitMQ/index.html index 8a6b01d4..985958d4 100644 --- a/tags/RabbitMQ/index.html +++ b/tags/RabbitMQ/index.html @@ -412,7 +412,7 @@

- 29 + 30 日志 @@ -423,7 +423,7 @@

@@ -434,7 +434,7 @@

diff --git a/tags/String/index.html b/tags/String/index.html index 9735b0f6..cff5b96c 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/index.html b/tags/index.html index 566a5615..2bde9de3 100644 --- a/tags/index.html +++ b/tags/index.html @@ -317,10 +317,10 @@

@@ -378,7 +378,7 @@

- 29 + 30 日志 @@ -389,7 +389,7 @@

@@ -400,7 +400,7 @@

diff --git a/tags/mockito/index.html b/tags/mockito/index.html index ec32dac6..4c191d95 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git a/tags/test/index.html b/tags/test/index.html index 6b496300..b697d951 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 00ed7fe4..a1573bda 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index 10cdc397..7043055f 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -412,7 +412,7 @@

- 29 + 30 日志 @@ -423,7 +423,7 @@

@@ -434,7 +434,7 @@

diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 866438ef..26bc1d21 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -412,7 +412,7 @@

- 29 + 30 日志 @@ -423,7 +423,7 @@

@@ -434,7 +434,7 @@

diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index 436f9d21..7fc8f418 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index d10c8014..c6067acb 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -412,7 +412,7 @@

- 29 + 30 日志 @@ -423,7 +423,7 @@

@@ -434,7 +434,7 @@

diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index 056de621..cee08a40 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 9218b636..d9dc4664 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 5523bda9..1020cded 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index 98a4f85e..3820e906 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -386,7 +386,7 @@

- 29 + 30 日志 @@ -397,7 +397,7 @@

@@ -408,7 +408,7 @@

From 611d814a15a1a20b70265209adaf485a71c257ca Mon Sep 17 00:00:00 2001 From: maguihai Date: Thu, 24 Sep 2020 23:17:18 +0800 Subject: [PATCH 08/19] Site updated: 2020-09-24 23:17:17 --- about/index.html | 6 +- archives/2019/10/index.html | 11 +- archives/2019/11/index.html | 11 +- archives/2019/12/index.html | 11 +- archives/2019/index.html | 11 +- archives/2019/page/2/index.html | 11 +- archives/2020/01/index.html | 11 +- archives/2020/02/index.html | 11 +- archives/2020/03/index.html | 11 +- archives/2020/04/index.html | 11 +- archives/2020/05/index.html | 11 +- archives/2020/06/index.html | 11 +- archives/2020/07/index.html | 11 +- archives/2020/08/index.html | 11 +- archives/2020/09/index.html | 1272 +++++++++++++ archives/2020/index.html | 81 +- archives/2020/page/2/index.html | 46 +- archives/index.html | 83 +- archives/page/2/index.html | 83 +- archives/page/3/index.html | 83 +- archives/page/4/index.html | 1276 +++++++++++++ atom.xml | 64 +- baidusitemap.xml | 3 + categories/JDK/Java/index.html | 6 +- .../index.html" | 6 +- categories/JDK/index.html | 6 +- categories/Java/Bloom-filter/index.html | 6 +- categories/Java/GC/index.html | 6 +- categories/Java/Guava/String/index.html | 6 +- categories/Java/Guava/index.html | 6 +- categories/Java/IDEA/index.html | 6 +- .../IDEA/\345\267\245\345\205\267/index.html" | 6 +- .../IO\346\250\241\345\236\213/index.html" | 6 +- categories/Java/JVM/index.html | 6 +- categories/Java/List/index.html | 6 +- categories/Java/index.html | 58 +- categories/Java/page/2/index.html | 58 +- categories/Java/page/3/index.html | 32 +- categories/Java/unit-test/index.html | 6 +- categories/Java/unit-test/mockito/index.html | 6 +- .../Java/\345\216\237\347\220\206/index.html" | 6 +- .../Java/\345\217\215\345\260\204/index.html" | 6 +- .../index.html" | 6 +- .../Java/\345\271\266\345\217\221/index.html" | 6 +- .../\350\277\233\351\230\266/index.html" | 6 +- .../Java/\345\274\202\346\255\245/index.html" | 6 +- .../Eureka/index.html" | 6 +- .../index.html" | 6 +- .../index.html" | 6 +- .../Java/\347\274\223\345\255\230/index.html" | 1254 +++++++++++++ .../Java/\351\207\215\346\236\204/index.html" | 6 +- .../Linux\347\254\224\350\256\260/index.html" | 6 +- categories/RabbitMQ/Java/index.html | 6 +- categories/RabbitMQ/index.html | 6 +- categories/index.html | 10 +- .../CAP\345\256\232\347\220\206/index.html" | 6 +- .../index.html" | 6 +- css/main.css | 2 +- index.html | 344 ++-- page/2/index.html | 412 ++--- page/3/index.html | 356 ++-- page/4/index.html | 1407 ++++++++++++++ post/102cd3d9.html | 6 +- post/11cb7677.html | 6 +- post/192cb539.html | 6 +- post/24042edf.html | 6 +- post/34755d6c.html | 6 +- post/3ae0ff4e.html | 6 +- post/4615256d.html | 6 +- post/4b00e13c.html | 6 +- post/4ea48fa7.html | 6 +- post/51e5bd99.html | 6 +- post/710bd10b.html | 6 +- post/7528c810.html | 6 +- post/7b9ead86.html | 6 +- post/7eb2637f.html | 6 +- post/817c7d82.html | 6 +- post/8a061473.html | 6 +- post/8bd965a0.html | 6 +- post/99ea2970.html | 6 +- post/a38c0645.html | 6 +- post/ab706eb5.html | 6 +- post/b1d4025b.html | 6 +- post/bc557e1a.html | 6 +- post/bfcdfeaf.html | 6 +- post/c34b451f.html | 6 +- post/d7d0fc76.html | 10 +- post/e09f0428.html | 6 +- post/ee27c07f.html | 6 +- post/f440d00b.html | 6 +- post/f92758d8.html | 6 +- post/fa75f5d7.html | 1612 +++++++++++++++++ post/fe76043.html | 6 +- search.xml | 13 + sitemap.xml | 7 + tags/Bloom-filter/index.html | 6 +- "tags/CAP\345\256\232\347\220\206/index.html" | 6 +- tags/Eureka/index.html | 6 +- tags/GC/index.html | 6 +- tags/Guava/index.html | 6 +- tags/IDEA/index.html | 6 +- "tags/IO\346\250\241\345\236\213/index.html" | 6 +- tags/JDK/index.html | 6 +- tags/JVM/index.html | 6 +- .../Java-\345\216\237\347\220\206/index.html" | 6 +- .../Java-\345\271\266\345\217\221/index.html" | 6 +- tags/Java/index.html | 58 +- tags/Java/page/2/index.html | 58 +- tags/Java/page/3/index.html | 32 +- .../Linux\347\254\224\350\256\260/index.html" | 6 +- tags/List/index.html | 6 +- tags/RabbitMQ/index.html | 6 +- tags/String/index.html | 6 +- tags/index.html | 10 +- tags/mockito/index.html | 6 +- tags/test/index.html | 6 +- .../index.html" | 6 +- "tags/\345\217\215\345\260\204/index.html" | 6 +- .../index.html" | 6 +- "tags/\345\267\245\345\205\267/index.html" | 6 +- "tags/\345\271\266\345\217\221/index.html" | 6 +- "tags/\345\274\202\346\255\245/index.html" | 6 +- .../index.html" | 6 +- .../index.html" | 6 +- "tags/\347\274\223\345\255\230/index.html" | 1253 +++++++++++++ "tags/\351\207\215\346\236\204/index.html" | 6 +- 126 files changed, 9412 insertions(+), 1218 deletions(-) create mode 100644 archives/2020/09/index.html create mode 100644 archives/page/4/index.html create mode 100644 "categories/Java/\347\274\223\345\255\230/index.html" create mode 100644 page/4/index.html create mode 100644 post/fa75f5d7.html create mode 100644 "tags/\347\274\223\345\255\230/index.html" diff --git a/about/index.html b/about/index.html index bc437808..e5d9541a 100644 --- a/about/index.html +++ b/about/index.html @@ -408,7 +408,7 @@

- 30 + 31 日志 @@ -419,7 +419,7 @@

- 30 + 31 分类 @@ -430,7 +430,7 @@

- 27 + 28 标签 diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html index 7ddacc80..85c36519 100644 --- a/archives/2019/10/index.html +++ b/archives/2019/10/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -546,7 +545,7 @@

- 30 + 31 日志 @@ -557,7 +556,7 @@

@@ -568,7 +567,7 @@

diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html index 1da21b11..9d71bcb2 100644 --- a/archives/2019/11/index.html +++ b/archives/2019/11/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -511,7 +510,7 @@

- 30 + 31 日志 @@ -522,7 +521,7 @@

@@ -533,7 +532,7 @@

diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html index 4e1eafbc..578e54bb 100644 --- a/archives/2019/12/index.html +++ b/archives/2019/12/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -511,7 +510,7 @@

- 30 + 31 日志 @@ -522,7 +521,7 @@

@@ -533,7 +532,7 @@

diff --git a/archives/2019/index.html b/archives/2019/index.html index 3a86123f..c095e26a 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -725,7 +724,7 @@

- 30 + 31 日志 @@ -736,7 +735,7 @@

@@ -747,7 +746,7 @@

diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html index 2a37f1e1..cb93e6f0 100644 --- a/archives/2019/page/2/index.html +++ b/archives/2019/page/2/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -480,7 +479,7 @@

- 30 + 31 日志 @@ -491,7 +490,7 @@

@@ -502,7 +501,7 @@

diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html index 78a2e968..e19f1fb7 100644 --- a/archives/2020/01/index.html +++ b/archives/2020/01/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -441,7 +440,7 @@

- 30 + 31 日志 @@ -452,7 +451,7 @@

@@ -463,7 +462,7 @@

diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html index 6d2529a6..c5917293 100644 --- a/archives/2020/02/index.html +++ b/archives/2020/02/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -406,7 +405,7 @@

- 30 + 31 日志 @@ -417,7 +416,7 @@

@@ -428,7 +427,7 @@

diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index c0fd5137..7194a09a 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -511,7 +510,7 @@

- 30 + 31 日志 @@ -522,7 +521,7 @@

@@ -533,7 +532,7 @@

diff --git a/archives/2020/04/index.html b/archives/2020/04/index.html index 8624187b..adf60188 100644 --- a/archives/2020/04/index.html +++ b/archives/2020/04/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -511,7 +510,7 @@

- 30 + 31 日志 @@ -522,7 +521,7 @@

@@ -533,7 +532,7 @@

diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index d503914b..a2f7b353 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -441,7 +440,7 @@

- 30 + 31 日志 @@ -452,7 +451,7 @@

@@ -463,7 +462,7 @@

diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html index d8865e6d..3ec73864 100644 --- a/archives/2020/06/index.html +++ b/archives/2020/06/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -406,7 +405,7 @@

- 30 + 31 日志 @@ -417,7 +416,7 @@

@@ -428,7 +427,7 @@

diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html index 76a4b8df..970cf453 100644 --- a/archives/2020/07/index.html +++ b/archives/2020/07/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -406,7 +405,7 @@

- 30 + 31 日志 @@ -417,7 +416,7 @@

@@ -428,7 +427,7 @@

diff --git a/archives/2020/08/index.html b/archives/2020/08/index.html index 440310ea..659fab34 100644 --- a/archives/2020/08/index.html +++ b/archives/2020/08/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -441,7 +440,7 @@

- 30 + 31 日志 @@ -452,7 +451,7 @@

@@ -463,7 +462,7 @@

diff --git a/archives/2020/09/index.html b/archives/2020/09/index.html new file mode 100644 index 00000000..8e098b51 --- /dev/null +++ b/archives/2020/09/index.html @@ -0,0 +1,1272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/index.html b/archives/2020/index.html index 5e605a15..51edc251 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -327,6 +326,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -633,41 +667,6 @@

- - - - - - - - - - - - - - - @@ -725,7 +724,7 @@

- 30 + 31 日志 @@ -736,7 +735,7 @@

@@ -747,7 +746,7 @@

diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html index e727088d..b008c840 100644 --- a/archives/2020/page/2/index.html +++ b/archives/2020/page/2/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -327,6 +326,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -620,7 +654,7 @@

- 30 + 31 日志 @@ -631,7 +665,7 @@

@@ -642,7 +676,7 @@

diff --git a/archives/index.html b/archives/index.html index 87df985d..4bfe24e0 100644 --- a/archives/index.html +++ b/archives/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -327,6 +326,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -633,41 +667,6 @@

- - - - - - - - - - - - - - - @@ -676,7 +675,7 @@

@@ -725,7 +724,7 @@

- 30 + 31 日志 @@ -736,7 +735,7 @@

@@ -747,7 +746,7 @@

diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 4443c298..eb0393df 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -327,6 +326,41 @@

2020

+ + + + + + + + + + + + + + +
@@ -638,41 +672,6 @@

- - - - - - - - - - - - - - - @@ -681,7 +680,7 @@

@@ -730,7 +729,7 @@

- 30 + 31 日志 @@ -741,7 +740,7 @@

@@ -752,7 +751,7 @@

diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 59d04ee3..9ce4e478 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -305,10 +305,9 @@

Java 搬运工 & 终身学习 + - - - 嗯..! 目前共计 30 篇日志。 继续努力。 + OK! 目前共计 31 篇日志。 继续努力。 @@ -327,6 +326,41 @@

2019

+ + + + + + + + + + + + + + +
@@ -633,41 +667,6 @@

- - - - - - - - - - - - - - - @@ -676,7 +675,7 @@

@@ -725,7 +724,7 @@

- 30 + 31 日志 @@ -736,7 +735,7 @@

@@ -747,7 +746,7 @@

diff --git a/archives/page/4/index.html b/archives/page/4/index.html new file mode 100644 index 00000000..a93cdc19 --- /dev/null +++ b/archives/page/4/index.html @@ -0,0 +1,1276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/atom.xml b/atom.xml index 7521722f..9f85e4f9 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2020-08-23T06:22:47.888Z + 2020-09-24T15:15:59.031Z https://www.mghio.cn/ @@ -16,6 +16,40 @@ Hexo + + 从 CPU 缓存看缓存的套路 + + https://www.mghio.cn/post/fa75f5d7.html + 2020-09-24T15:07:50.000Z + 2020-09-24T15:15:59.031Z + + 一、前言

不同存储技术的访问时间差异很大,从 计算机层次结构 可知,通常情况下,从高层往底层走,存储设备变得更慢、更便宜同时体积也会更大,CPU 和内存之间的速度存在着巨大的差异,此时就会想到计算机科学界中一句著名的话:计算机科学的任何一个问题,都可以通过增加一个中间层来解决。

二、引入缓存层

为了解决速度不匹配问题,可以通过引入一个缓存中间层来解决问题,但是也会引入一些新的问题。现代计算机系统中,从硬件到操作系统、再到一些应用程序,绝大部分的设计都用到了著名的局部性原理,局部性通常有如下两种不同的形式:

时间局部性:在一个具有良好的时间局部性的程序当中,被引用过一次的内存位置,在将来一个不久的时间内很可能会被再次引用到。

空间局部性:在一个具有良好的空间局部性的程序当中,一个内存位置被引用了一次,那么在不久的时间内很可能会引用附近的位置。

有上面这个局部性原理为理论指导,为了解决二者速度不匹配问题就可以在 CPU 和内存之间加一个缓存层,于是就有了如下的结构:

Xnip2020-08-16_22-51-12.jpg

三、何时更新缓存

CPU 中引入缓存中间层后,虽然可以解决和内存速度不一致的问题,但是同时也面临着一个问题:当 CPU 更新了其缓存中的数据之后,要什么时候去写入到内存中呢?,比较容易想到的一个解决方案就是,CPU 更新了缓存的数据之后就立即更新到内存中,也就是说当 CPU 更新了缓存的数据之后就会从上到下更新,直到内存为止,英文称之为write through,这种方式的优点是比较简单,但是缺点也很明显,由于每次都需要访问内存,所以速度会比较慢。还有一种方法就是,当 CPU 更新了缓存之后并不马上更新到内存中去,在适当的时候再执行写入内存的操作,因为有很多的缓存只是存储一些中间结果,没必要每次都更新到内存中去,英文称之为write back,这种方式的优点是 CPU 执行更新的效率比较高,缺点就是实现起来会比较复杂。

上面说的在适当的时候写入内存,如果是单核 CPU 的话,可以在缓存要被新进入的数据取代时,才更新内存,但是在多核 CPU 的情况下就比较复杂了,由于 CPU 的运算速度超越了 1 级缓存的数据 I\O 能力,CPU 厂商又引入了多级的缓存结构,比如常见的 L1、L2、L3 三级缓存结构,L1 和 L2 为 CPU 核心独有,L3 为 CPU 共享缓存。

Xnip2020-08-16_23-39-28.jpg

如果现在分别有两个线程运行在两个不同的核 Core 1Core 2 上,内存中 i 的值为 1,这两个分别运行在两个不同核上的线程要对 i 进行加 1 操作,如果不加一些限制,两个核心同时从内存中读取 i 的值,然后进行加 1 操作后再分别写入内存中,可能会出现相互覆盖的情况,解决的方法相信大家都能想得到,第一种是只要有一个核心修改了缓存的数据之后,就立即把内存和其它核心更新。第二种是当一个核心修改了缓存的数据之后,就把其它同样复制了该数据的 CPU 核心失效掉这些数据,等到合适的时机再更新,通常是下一次读取该缓存的时候发现已经无效,才从内存中加载最新的值。

四、缓存一致性协议

不难看出第一种需要频繁访问内存更新数据,执行效率比较低,而第二种会把更新数据推迟到最后一刻才会更新,读取内存,效率高(类似于懒加载)。 缓存一致性协议(MESI) 就是使用第二种方案,该协议主要是保证缓存内部数据的一致,不让系统数据混乱。MESI 是指 4 种状态的首字母。每个缓存存储数据单元(Cache line)有 4 种不同的状态,用 2 个 bit 表示,状态和对应的描述如下:

状态描述监听任务
M 修改 (Modified)该 Cache line 有效,数据被修改了,和内存中的数据不一致,数据只存在于本 Cache 中Cache line 必须时刻监听所有试图读该缓存行相对就主存的操作,这种操作必须在缓存将该缓存行写回主存并将状态变成 S(共享)状态之前被延迟执行
E 独享、互斥 (Exclusive)该 Cache line 有效,数据和内存中的数据一致,数据只存在于本 Cache 中Cache line 必须监听其它缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行需要变成 S(共享)状态
S 共享 (Shared)该 Cache line 有效,数据和内存中的数据一致,数据存在于很多 Cache 中Cache line 必须监听其它缓存使该缓存行无效或者独享该缓存行的请求,并将该 Cache line 变成无效
I 无效 (Invalid)该 Cache line 无效无监听任务

下面看看基于缓存一致性协议是如何进行读取和写入操作的, 假设现在有一个双核的 CPU,为了描述方便,简化一下只看其逻辑结构:

Xnip2020-08-17_08-44-37.jpg

单核读取步骤Core 0 发出一条从内存中读取 a 的指令,从内存通过 BUS 读取 a 到 Core 0 的缓存中,因为此时数据只在 Core 0 的缓存中,所以将 Cache line 修改为 E 状态(独享),该过程用示意图表示如下:

dnmKYQ.jpg

双核读取步骤:首先 Core 0 发出一条从内存中读取 a 的指令,从内存通过 BUS 读取 a 到 Core 0 的缓存中,然后将 Cache line 置为 E 状态,此时 Core 1 发出一条指令,也是要从内存中读取 a,当 Core 1 试图从内存读取 a 的时候, Core 0 检测到了发生地址冲突(其它缓存读主存中该缓存行的操作),然后 Core 0 对相关数据做出响应,a 存储于这两个核心 Core 0Core 1 的缓存行中,然后设置其状态为 S 状态(共享),该过程示意图如下:

dnQsoV.jpg

假设此时 Core 0 核心需要对 a 进行修改了,首先 Core 0 会将其缓存的 a 设置为 M(修改)状态,然后通知其它缓存了 a 的其它核 CPU(比如这里的 Core 1)将内部缓存的 a 的状态置为 I(无效)状态,最后才对 a 进行赋值操作。该过程如下所示:

dnQxeI.jpg

细心的朋友们可能已经注意到了,上图中内存中 a 的值(值为 1)并不等于 Core 0 核心中缓存的最新值(值为 2),那么要什么时候才会把该值更新到内存中去呢?就是当 Core 1 需要读取 a 的值的时候,此时会通知 Core 0a 的修改后的最新值同步到内存(Memory)中去,在这个同步的过程中 Core 0 中缓存的 a 的状态会置为 E(独享)状态,同步完成后将 Core 0Core 1 中缓存的 a 置为 S(共享)状态,示意图描述该过程如下所示:

dn8HHA.jpg

至此,变量 aCPU 的两个核 Core 0Core 1 中回到了 S(共享)状态了,以上只是简单的描述了一下大概的过程,实际上这些都是在 CPU 的硬件层面上去保证的,而且操作比较复杂。

五、总结

现在很多一些实现缓存功能的应用程序都是基于这些思想设计的,缓存把数据库中的数据进行缓存到速度更快的内存中,可以加快我们应用程序的响应速度,比如我们使用常见的 Redis 数据库可能是采用下面这些策略:① 首先应用程序从缓存中查询数据,如果有就直接使用该数据进行相应操作后返回,如果没有则查询数据库,更新缓存并且返回。② 当我们需要更新数据时,先更新数据库,然后再让缓存失效,这样下次就会先查询数据库再回填到缓存中去,可以发现,实际上底层的一些思想都是相通的,不同的只是对于特定的场景可能需要增加一些额外的约束。基础知识才是技术这颗大树的根,我们先把根栽好了,剩下的那些枝和叶都是比较容易得到的东西了。

]]> + + + + <h4 id="一、前言"><a href="#一、前言" class="headerlink" title="一、前言"></a>一、前言</h4><p>不同存储技术的访问时间差异很大,从 <code>计算机层次结构</code> 可知,通常情况下,从高层往底层走,存储设备变得更慢、更便宜同时体积也会更大,<code>CPU</code> 和内存之间的速度存在着巨大的差异,此时就会想到计算机科学界中一句著名的话:<code>计算机科学的任何一个问题,都可以通过增加一个中间层来解决。</code></p> +<h4 id="二、引入缓存层"><a href="#二、引入缓存层" class="headerlink" title="二、引入缓存层"></a>二、引入缓存层</h4><p>为了解决速度不匹配问题,可以通过引入一个缓存中间层来解决问题,但是也会引入一些新的问题。现代计算机系统中,从硬件到操作系统、再到一些应用程序,绝大部分的设计都用到了著名的<strong>局部性原理</strong>,局部性通常有如下两种不同的形式:</p> +<blockquote> +<p>时间局部性:在一个具有良好的时间局部性的程序当中,被引用过一次的内存位置,在将来一个不久的时间内很可能会被再次引用到。</p> +</blockquote> +<blockquote> +<p>空间局部性:在一个具有良好的空间局部性的程序当中,一个内存位置被引用了一次,那么在不久的时间内很可能会引用附近的位置。</p> +</blockquote> + + + + + + + + + + + + + + + Java 集合类 List 的那些坑 @@ -612,32 +646,4 @@ - - Java 多线程基础(二) - - https://www.mghio.cn/post/4ea48fa7.html - 2019-12-14T08:32:14.000Z - 2019-12-16T12:22:59.495Z - - 简介

在上篇 Java 多线程基础(一) 我们提到了一些线程的常用方法,这篇我们具体看看其中一些方法的使用以及方法的区别,让我们在工作中更好的使用。

wait 方法与 notify 方法

Object 类中定义了 wait 方法和 notify 方法,wait 方法的作用是让当前线程进入等待状态,将当前线程置入 预执行队列,会在 wait 方法所在代码处停止执行,直到被通知或者被中断,在调用 wait 方法之前,线程必须获取该对象的锁,因此只能在同步方法或者同步代码块中调用 wait 方法,并且该方法会释放当前线程锁持有的锁。notify 方法是唤醒在当前对象上等待的单个线程,如果有多个线程等待,那么线程调度器会挑出一个 wait 的线程,对其发出 notify ,并使它等待获取该对象的对象锁,这意味着,即使收到了通知,线程也不会立即获取到对象锁,必须等待 notify 方法的线程释放锁才可以。和 wait 方法一样,notify 方法也只能在同步方法或者同步代码块中调用。它还有个相似的方法 notifyAll,它的作用是唤醒在当前对象上等待的所有线程

下面通过一个生产者消费者来说明 wait 方法和 notify 方法的使用:

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
* @author mghio
* @date: 2019-12-14
* @version: 1.0
* @description: 线程 wait() 和 notify() 方法使用示例
* @since JDK 1.8
*/
public class ThreadWaitAndNotifyDemo {

public static void main(String[] args) {
Producer producer = new Producer();
producer.start();
new Consumer("Consumer One", producer).start();
new Consumer("Consumer Two", producer).start();
new Consumer("Consumer Three", producer).start();
new Consumer("Consumer Four", producer).start();
}

static class Producer extends Thread {

List<String> messageList = new ArrayList<>(2);

@Override
public void run() {
try {
while (true) {
Thread.sleep(2000);
synchronized (messageList) {
String message = String.format("producer message [create time:%s]", LocalDateTime.now());
messageList.add(message);
System.out.println("Producer " + getName() + " producer a msg: " + message);
messageList.notify();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

String getMessage() {
synchronized (messageList) {
if (messageList.size() == 0) {
try {
messageList.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return messageList.remove(0);
}
}
}

static class Consumer extends Thread {

private Producer producer;

public Consumer(String name, Producer producer) {
super(name);
this.producer = producer;
}

@Override
public void run() {
while (true) {
String message = producer.getMessage();
System.out.println("Consumer " + getName() + " get a msg: " + message);
}
}
}
}

输出结果如下:

1
2
3
4
5
6
7
8
Producer Thread-0 producer a msg: producer message [create time:2019-12-14T22:45:42.319]
Consumer Consumer One get a msg: producer message [create time:2019-12-14T22:45:42.319]
Producer Thread-0 producer a msg: producer message [create time:2019-12-14T22:45:44.324]
Consumer Consumer Two get a msg: producer message [create time:2019-12-14T22:45:44.324]
Producer Thread-0 producer a msg: producer message [create time:2019-12-14T22:45:46.325]
Consumer Consumer Three get a msg: producer message [create time:2019-12-14T22:45:46.325]
Producer Thread-0 producer a msg: producer message [create time:2019-12-14T22:45:48.328]
Consumer Consumer Four get a msg: producer message [create time:2019-12-14T22:45:48.328]

消费者线程循环调用生产者的 getMessage 方法获取消息,如果消息列表 messageList 为空,则调用消息列表的 wait 方法让线程进入等待状态,生产者每隔 2 秒生成消息并放入消息列表 messageList 中,放入成功后调用 notify 方法唤醒一个处于 wait 状态的线程去消费消息,需要注意的是,在调用 waitnotify 方法时必须要先获得该对象的锁,上面的示例中是在 synchronized 代码块中调用的。

sleep 方法

waitnotify 方法不同,sleep 方法定义在 Thread 类中,从方法名也可以知道,这个方法的作用就是让当前线程休眠,即调用该方法后当前线程会从运行状态(Running)状态进入到阻塞(休眠)状态(Blocked),同时该方法必须指定休眠的时间,当前线程的休眠时间会大于或者等于这个指定的休眠时间。当线程重新被唤醒时,线程会由阻塞状态(Blocked)变成就绪状态(Runnable),然后等待 CPU 的调度执行。sleep 方法的示例代码如下:

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
/**
* @author mghio
* @date: 2019-12-14
* @version: 1.0
* @description: 线程 sleep() 方法使用示例
* @since JDK 1.8
*/
public class ThreadSleepDemo {

private static Object object = new Object();

public static void main(String[] args) {
MyThread myThreadOne = new MyThread("t1");
MyThread myThreadTwo = new MyThread("t2");
myThreadOne.start();
myThreadTwo.start();
}

static class MyThread extends Thread {

public MyThread(String name) {
super(name);
}

@Override
public void run() {
synchronized (object) {
try {
for (int i = 0; i < 5; i++) {
System.out.println(String.format("%s: %d", this.getName(), i));
if (i % 2 == 0) {
Thread.sleep(2000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

输出结果如下:

1
2
3
4
5
6
7
8
9
10
t1: 0
t1: 1
t1: 2
t1: 3
t1: 4
t2: 0
t2: 1
t2: 2
t2: 3
t2: 4

我们启动了两个线程 t1t2,两个线程的 run 方法引用了同一个对象 object 的同步锁(synchronized (object)),虽然在第一个线程 t1 中当 i 被 2 整除时会调用 Thread.sleep(2000) 让当前线程休眠 2 s,但是此时线程 t2 也不会得到 cpu 的执行权去执行,因为 t1 线程调用 sleep 方法并没有释放object所持有的同步锁。如果我们注释掉 synchronized (object) 后再次执行该程序,线程 t1t2 是可以交替执行的,注释之后的输出结果如下:

1
2
3
4
5
6
7
8
9
10
t2: 0
t1: 0
t1: 1
t2: 1
t1: 2
t2: 2
t2: 3
t1: 3
t2: 4
t1: 4

yield 方法

yield 方法定义在 Thread 类中,是线程特有的方法。此方法的主要作用是让步,它会使当前线程从运行状态(Running)变为就绪状态(Runnable),从而让其他具有同样优先级的处于就绪状态的线程获取到 CPU 执行权(PS: CPU 会从众多的处于就绪状态的线程里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到),但是,也并不能保证在当前线程调用 yield 之后,其它哪些具有相同优先级的线程就一定能获得执行权,也有可能是当前线程又进入到运行状态(Running)继续运行。yield 方法的示例代码如下:

1
2
3
4
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
30
31
32
33
/**
* @author mghio
* @date: 2019-12-14
* @version: 1.0
* @description: 线程 yield() 方法使用示例
* @since JDK 1.8
*/
public class ThreadYieldDemo {

public static void main(String[] args) {
MyThread myThreadOne = new MyThread("t1");
MyThread myThreadTwo = new MyThread("t2");
myThreadOne.start();
myThreadTwo.start();
}

static class MyThread extends Thread {

MyThread(String name) {
super(name);
}

@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(String.format("%s [%d] ---> %d", this.getName(), this.getPriority(), i));
if (i % 2 == 0) {
yield();
}
}
}
}
}

输出结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
t1 [5] ---> 0
t2 [5] ---> 0
t1 [5] ---> 1
t1 [5] ---> 2
t1 [5] ---> 3
t1 [5] ---> 4
t1 [5] ---> 5
t1 [5] ---> 6
t1 [5] ---> 7
t1 [5] ---> 8
t1 [5] ---> 9
t2 [5] ---> 1
t2 [5] ---> 2
t2 [5] ---> 3
t2 [5] ---> 4
t2 [5] ---> 5
t2 [5] ---> 6
t2 [5] ---> 7
t2 [5] ---> 8
t2 [5] ---> 9

从以上输出结果可以看出,线程 t1 中的变量 i 在被 2 整除的时候,并没有切换到线程 t2 去执行,这也验证了我们上文说的,yield 方法虽然可以让线程由运行状态变成就绪状态,但是,它不一定会让其它线程获取 CPU 执行权从而进入到运行状态,即使这个其它线程和当前具有相同的优先级,yield 方法不会释放锁(证明方法只需将上面这个示例的 run 方法里面加上 synchronized (obj) 即可,此时 t2 线程会等到线程 t1 执行完毕后才会执行)。

join 方法

在有些场景中我们需要在子线程去执行一些耗时的任务,但是我们的主线程又必须等待子线程执行完毕之后才能结束,那么此时就可以使用 join 方法了,该方法定义在 Thread 类中,方法的作用是:让主线程等待子线程执行结束之后才能继续执行,下面我们通过一个例子来看看:

1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
/**
* @author mghio
* @date: 2019-12-15
* @version: 1.0
* @description: 线程 join() 方法使用示例
* @since JDK 1.8
*/
public class ThreadJoinDemo {

public static void main(String[] args) {
try {
MyThread myThread = new MyThread("t1");
myThread.start();
myThread.join();
System.out.println(String.format("%s ---> %s finish", LocalDateTime.now(), Thread.currentThread().getName()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}

static class MyThread extends Thread {

MyThread(String name) {
super(name);
}

@Override
public void run() {
System.out.println(String.format("%s ---> %s start", LocalDateTime.now(), this.getName()));
// 模拟耗时操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("%s ---> %s finish", LocalDateTime.now(), this.getName()));
}
}
}

输出结果如下:

1
2
3
2019-12-15T00:22:55.971 ---> t1 start
2019-12-15T00:22:57.984 ---> t1 finish
2019-12-15T00:22:57.985 ---> main finish

在主线程 main 中通过 new MyThread("t1") 新建线程 t1。 接着,通过 t1.start() 启动线程 t1,在执行 t1.join()之后, 主线程会进入阻塞状态等待 t1 运行结束。子线程 t1 结束之后,会唤醒主线程,主线程重新获取 CPU 执行权,主线程继续往下运行。在使用了 join 方法之后主线程会等待子线程结束之后才会结束。

总结

以上是线程一些常用的方法介绍和具体使用知识总结。

]]> - - - - <h4 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h4><p>在上篇 <a href="https://www.mghio.cn/post/7eb2637f.html">Java 多线程基础(一)</a> 我们提到了一些线程的常用方法,这篇我们具体看看其中一些方法的使用以及方法的区别,让我们在工作中更好的使用。</p> -<h4 id="wait-方法与-notify-方法"><a href="#wait-方法与-notify-方法" class="headerlink" title="wait 方法与 notify 方法"></a>wait 方法与 notify 方法</h4><p>在 <code>Object</code> 类中定义了 <code>wait</code> 方法和 <code>notify</code> 方法,<code>wait</code> 方法的作用是让当前线程进入等待状态,将当前线程置入 <code>预执行队列</code>,会在 <code>wait</code> 方法所在代码处停止执行,直到被通知或者被中断,在调用 <code>wait</code> 方法之前,线程必须获取该对象的锁,因此只能在<code>同步方法</code>或者<code>同步代码块</code>中调用 <code>wait</code> 方法,并且该方法会释放当前线程锁持有的锁。<code>notify</code> 方法是唤醒在当前对象上等待的<code>单个线程</code>,如果有多个线程等待,那么线程调度器会挑出一个 <code>wait</code> 的线程,对其发出 <code>notify</code> ,并使它等待获取该对象的对象锁,这意味着,即使收到了通知,线程也不会立即获取到对象锁,必须等待 <code>notify</code> 方法的线程释放锁才可以。和 <code>wait</code> 方法一样,<code>notify</code> 方法也只能在<code>同步方法</code>或者<code>同步代码块</code>中调用。它还有个相似的方法 <code>notifyAll</code>,它的作用是唤醒在当前对象上等待的<code>所有线程</code>。</p> - - - - - - - - - - - - - - - diff --git a/baidusitemap.xml b/baidusitemap.xml index ca2148a9..6da54f4d 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -1,6 +1,9 @@ + https://www.mghio.cn/post/fa75f5d7.html + 2020-09-24 + https://www.mghio.cn/post/d7d0fc76.html 2020-08-23 diff --git a/categories/JDK/Java/index.html b/categories/JDK/Java/index.html index 739b1861..de9ac3e1 100644 --- a/categories/JDK/Java/index.html +++ b/categories/JDK/Java/index.html @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 8f1c2f1b..a7a49663 100644 --- "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/JDK/index.html b/categories/JDK/index.html index 737748ea..33ba5878 100644 --- a/categories/JDK/index.html +++ b/categories/JDK/index.html @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/Bloom-filter/index.html b/categories/Java/Bloom-filter/index.html index 9f78d678..b6ac357d 100644 --- a/categories/Java/Bloom-filter/index.html +++ b/categories/Java/Bloom-filter/index.html @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/GC/index.html b/categories/Java/GC/index.html index 57e23568..9a1e1a39 100644 --- a/categories/Java/GC/index.html +++ b/categories/Java/GC/index.html @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/Guava/String/index.html b/categories/Java/Guava/String/index.html index 3356c5e4..1d4f95ca 100644 --- a/categories/Java/Guava/String/index.html +++ b/categories/Java/Guava/String/index.html @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/Guava/index.html b/categories/Java/Guava/index.html index d109b45b..0b7ad810 100644 --- a/categories/Java/Guava/index.html +++ b/categories/Java/Guava/index.html @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/IDEA/index.html b/categories/Java/IDEA/index.html index 49589019..1af29da5 100644 --- a/categories/Java/IDEA/index.html +++ b/categories/Java/IDEA/index.html @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" index 294df884..0ababdc1 100644 --- "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" +++ "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/IO\346\250\241\345\236\213/index.html" "b/categories/Java/IO\346\250\241\345\236\213/index.html" index 4cb7ac11..33252416 100644 --- "a/categories/Java/IO\346\250\241\345\236\213/index.html" +++ "b/categories/Java/IO\346\250\241\345\236\213/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/JVM/index.html b/categories/Java/JVM/index.html index 1ad9f56f..abb5820a 100644 --- a/categories/Java/JVM/index.html +++ b/categories/Java/JVM/index.html @@ -413,7 +413,7 @@

- 30 + 31 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git a/categories/Java/List/index.html b/categories/Java/List/index.html index 55ed4869..5b48666d 100644 --- a/categories/Java/List/index.html +++ b/categories/Java/List/index.html @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/index.html b/categories/Java/index.html index e1635798..22063189 100644 --- a/categories/Java/index.html +++ b/categories/Java/index.html @@ -309,6 +309,32 @@

Java分类 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -625,7 +625,7 @@

- 30 + 31 日志 @@ -636,7 +636,7 @@

@@ -647,7 +647,7 @@

diff --git a/categories/Java/page/2/index.html b/categories/Java/page/2/index.html index e990cecd..022b5403 100644 --- a/categories/Java/page/2/index.html +++ b/categories/Java/page/2/index.html @@ -309,6 +309,32 @@

Java分类 + + + + + +
@@ -541,32 +567,6 @@

- - - - - - @@ -625,7 +625,7 @@

- 30 + 31 日志 @@ -636,7 +636,7 @@

@@ -647,7 +647,7 @@

diff --git a/categories/Java/page/3/index.html b/categories/Java/page/3/index.html index 40a6f28e..d7056d51 100644 --- a/categories/Java/page/3/index.html +++ b/categories/Java/page/3/index.html @@ -309,6 +309,32 @@

Java分类 + + + + + +
@@ -495,7 +521,7 @@

- 30 + 31 日志 @@ -506,7 +532,7 @@

@@ -517,7 +543,7 @@

diff --git a/categories/Java/unit-test/index.html b/categories/Java/unit-test/index.html index 16648785..195959a5 100644 --- a/categories/Java/unit-test/index.html +++ b/categories/Java/unit-test/index.html @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/Java/unit-test/mockito/index.html b/categories/Java/unit-test/mockito/index.html index 2d7ad0f1..968e0199 100644 --- a/categories/Java/unit-test/mockito/index.html +++ b/categories/Java/unit-test/mockito/index.html @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\345\216\237\347\220\206/index.html" "b/categories/Java/\345\216\237\347\220\206/index.html" index c6540004..c6782fc7 100644 --- "a/categories/Java/\345\216\237\347\220\206/index.html" +++ "b/categories/Java/\345\216\237\347\220\206/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\345\217\215\345\260\204/index.html" "b/categories/Java/\345\217\215\345\260\204/index.html" index 9f4d6587..1e0f76c4 100644 --- "a/categories/Java/\345\217\215\345\260\204/index.html" +++ "b/categories/Java/\345\217\215\345\260\204/index.html" @@ -413,7 +413,7 @@

- 30 + 31 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" index fba05b2c..662f5475 100644 --- "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" @@ -413,7 +413,7 @@

- 30 + 31 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git "a/categories/Java/\345\271\266\345\217\221/index.html" "b/categories/Java/\345\271\266\345\217\221/index.html" index fba89379..5cc37865 100644 --- "a/categories/Java/\345\271\266\345\217\221/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/index.html" @@ -439,7 +439,7 @@

- 30 + 31 日志 @@ -450,7 +450,7 @@

@@ -461,7 +461,7 @@

diff --git "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" index bb7bd578..d37837fc 100644 --- "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\345\274\202\346\255\245/index.html" "b/categories/Java/\345\274\202\346\255\245/index.html" index e54d142f..9a971d0f 100644 --- "a/categories/Java/\345\274\202\346\255\245/index.html" +++ "b/categories/Java/\345\274\202\346\255\245/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" index f41dab26..d8e72d2e 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 87876e0d..ba58ae65 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" index b1868be7..dda3dc00 100644 --- "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" +++ "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" @@ -413,7 +413,7 @@

- 30 + 31 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git "a/categories/Java/\347\274\223\345\255\230/index.html" "b/categories/Java/\347\274\223\345\255\230/index.html" new file mode 100644 index 00000000..b1c22aff --- /dev/null +++ "b/categories/Java/\347\274\223\345\255\230/index.html" @@ -0,0 +1,1254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: 缓存 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/Java/\351\207\215\346\236\204/index.html" "b/categories/Java/\351\207\215\346\236\204/index.html" index 6962f241..0bfff56e 100644 --- "a/categories/Java/\351\207\215\346\236\204/index.html" +++ "b/categories/Java/\351\207\215\346\236\204/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/Linux\347\254\224\350\256\260/index.html" "b/categories/Linux\347\254\224\350\256\260/index.html" index fc46e397..f3f10322 100644 --- "a/categories/Linux\347\254\224\350\256\260/index.html" +++ "b/categories/Linux\347\254\224\350\256\260/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/categories/RabbitMQ/Java/index.html b/categories/RabbitMQ/Java/index.html index 5c466f6b..eda1aaed 100644 --- a/categories/RabbitMQ/Java/index.html +++ b/categories/RabbitMQ/Java/index.html @@ -413,7 +413,7 @@

- 30 + 31 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git a/categories/RabbitMQ/index.html b/categories/RabbitMQ/index.html index d3e362ba..15e96743 100644 --- a/categories/RabbitMQ/index.html +++ b/categories/RabbitMQ/index.html @@ -413,7 +413,7 @@

- 30 + 31 日志 @@ -424,7 +424,7 @@

@@ -435,7 +435,7 @@

diff --git a/categories/index.html b/categories/index.html index 900b853c..b6a4c739 100644 --- a/categories/index.html +++ b/categories/index.html @@ -317,10 +317,10 @@

@@ -378,7 +378,7 @@

- 30 + 31 日志 @@ -389,7 +389,7 @@

@@ -400,7 +400,7 @@

diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" index 4080b426..0e556de8 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 90b28c90..212d3fc9 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -387,7 +387,7 @@

- 30 + 31 日志 @@ -398,7 +398,7 @@

@@ -409,7 +409,7 @@

diff --git a/css/main.css b/css/main.css index 05ea609f..253c0026 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #6bffff; + background: #ff6feb; } .links-of-blogroll { font-size: 13px; diff --git a/index.html b/index.html index 3cba7c6f..8f908ed3 100644 --- a/index.html +++ b/index.html @@ -310,7 +310,7 @@

Java 搬运工 & 终身学习
- +

@@ -456,12 +456,17 @@

-

现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑。

-

第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作

例如我们执行以下代码:

-
1
2
List<String> strings = Arrays.asList("m", "g");
strings.add("h");
+

一、前言

不同存储技术的访问时间差异很大,从 计算机层次结构 可知,通常情况下,从高层往底层走,存储设备变得更慢、更便宜同时体积也会更大,CPU 和内存之间的速度存在着巨大的差异,此时就会想到计算机科学界中一句著名的话:计算机科学的任何一个问题,都可以通过增加一个中间层来解决。

+

二、引入缓存层

为了解决速度不匹配问题,可以通过引入一个缓存中间层来解决问题,但是也会引入一些新的问题。现代计算机系统中,从硬件到操作系统、再到一些应用程序,绝大部分的设计都用到了著名的局部性原理,局部性通常有如下两种不同的形式:

+
+

时间局部性:在一个具有良好的时间局部性的程序当中,被引用过一次的内存位置,在将来一个不久的时间内很可能会被再次引用到。

+
+
+

空间局部性:在一个具有良好的空间局部性的程序当中,一个内存位置被引用了一次,那么在不久的时间内很可能会引用附近的位置。

+
- + 阅读全文 »
@@ -514,7 +519,7 @@

- +

@@ -660,11 +665,12 @@

-

上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

-

消息生产者发送的消息不可达时如何处理

RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

+

现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑。

+

第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作

例如我们执行以下代码:

+
1
2
List<String> strings = Arrays.asList("m", "g");
strings.add("h");
- + 阅读全文 »
@@ -717,7 +723,7 @@

- +

-

+

@@ -863,11 +869,11 @@

-

什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

-

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

+

上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

+

消息生产者发送的消息不可达时如何处理

RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

- + 阅读全文 »
@@ -920,7 +926,7 @@

- +

-

+

@@ -1077,10 +1072,11 @@

-

前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

+

什么是消息队列(MQ)

消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

+

什么场景下考虑使用消息队列

从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

- + 阅读全文 »
@@ -1133,7 +1129,7 @@

前言 - +

@@ -1290,10 +1286,10 @@

-

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

+

前言

Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

- + 阅读全文 »
@@ -1346,7 +1342,7 @@

前言 - +

@@ -1503,10 +1499,10 @@

-

前言

对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

+

前言

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

- + 阅读全文 »
@@ -1559,7 +1555,7 @@

前言 - +

@@ -1705,11 +1712,10 @@

-

前言

在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

-

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

+

前言

对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

- + 阅读全文 »
@@ -1762,7 +1768,7 @@

- +

-

+

@@ -1908,14 +1914,11 @@

-

前言

在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

-

原理

布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

-
-

A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

-
+

前言

在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

+

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

- + 阅读全文 »
@@ -1968,7 +1971,7 @@

原理 - +

@@ -2125,15 +2117,14 @@

-

前言

Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

-

如何使用

Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

-
1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
- -

对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

-
1
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
+

前言

在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

+

原理

布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

+
+

A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

+
- + 阅读全文 »
@@ -2186,7 +2177,7 @@

- +

-

+

@@ -2332,11 +2334,15 @@

-

前言

在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

-

什么是 CompletableFuture

CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

+

前言

Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

+

如何使用

Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

+
1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
+ +

对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

+
1
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
- + 阅读全文 »
@@ -2380,7 +2386,7 @@

23 + 124 @@ -2428,7 +2434,7 @@

- 30 + 31 日志 @@ -2439,7 +2445,7 @@

- 30 + 31 分类 @@ -2450,7 +2456,7 @@

- 27 + 28 标签 diff --git a/page/2/index.html b/page/2/index.html index 97b4caa5..914d4037 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -310,7 +310,7 @@

Java 搬运工 & 终身学习
- +

@@ -456,11 +456,11 @@

-

前言

在日常生活中,当我们买的水果放久了之后会发出一种难闻的气味(“坏味道”),这个时候我们就应该把它扔掉。同样,代码也有“坏味道”,当然确定什么是和不是代码“坏味道”是主观的,它会随语言、开发人员和开发方法的不同而不同。在工作当中,很多时候都是在维护之前的项目和在此基础上增加一些新功能,为了能让项目代码易于理解和维护,要时刻注意代码中的“坏味道”,当发现代码如果有坏味道了,要及时去重构它使其变成优秀的整洁的代码。本文列举代码中一些常见的“坏味道”和相应的重构方案。

-

过长方法 (Long Method)

这种“坏味道”表现为方法代码行数过长,方法行数越长,就越难以理解和维护它。一个比较有用的方案就是当你觉得需要对方法中的内容加注释的时候,你应该将这个代码段作为一个新方法提取出来,哪怕有时候仅仅是一行代码也可以这么做,而且方法的命名要尽量做到见名知意,如果局部变量和参数干扰到方法的提取,则可以使用引入参数对象来进行提取。一般情况下,方法中条件运算符和循环是可以将代码移至单独方法的一个很好的代码段,对于条件运算符,可以尝试分解条件,如果方法出现循环,可以尝试提取方法。

+

前言

在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

+

什么是 CompletableFuture

CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

- + 阅读全文 »
@@ -513,7 +513,7 @@

- +

-

+

@@ -2453,7 +2453,7 @@

- 27 + 28 标签 diff --git a/page/3/index.html b/page/3/index.html index 94ca34f3..1f7e9662 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -310,7 +310,7 @@

Java 搬运工 & 终身学习
- +

@@ -456,12 +456,11 @@

-

简介

在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

-

进程与线程的区别

进程

进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

-
线程

线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

+

简介

在上篇 Java 多线程基础(一) 我们提到了一些线程的常用方法,这篇我们具体看看其中一些方法的使用以及方法的区别,让我们在工作中更好的使用。

+

wait 方法与 notify 方法

Object 类中定义了 wait 方法和 notify 方法,wait 方法的作用是让当前线程进入等待状态,将当前线程置入 预执行队列,会在 wait 方法所在代码处停止执行,直到被通知或者被中断,在调用 wait 方法之前,线程必须获取该对象的锁,因此只能在同步方法或者同步代码块中调用 wait 方法,并且该方法会释放当前线程锁持有的锁。notify 方法是唤醒在当前对象上等待的单个线程,如果有多个线程等待,那么线程调度器会挑出一个 wait 的线程,对其发出 notify ,并使它等待获取该对象的对象锁,这意味着,即使收到了通知,线程也不会立即获取到对象锁,必须等待 notify 方法的线程释放锁才可以。和 wait 方法一样,notify 方法也只能在同步方法或者同步代码块中调用。它还有个相似的方法 notifyAll,它的作用是唤醒在当前对象上等待的所有线程

- + 阅读全文 »
@@ -514,7 +513,7 @@
线程 - +
@@ -660,12 +659,12 @@

-

简介

在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

-

线程池如何处理提交的任务

我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
+

简介

在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

+

进程与线程的区别

进程

进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

+
线程

线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

- + 阅读全文 »
@@ -718,7 +717,7 @@

- +

-

+

@@ -864,17 +863,12 @@

-

线程池简介

使用线程池可以很好的提高性能,线程池在运行之初就会创建一定数量的空闲线程,我们将一个任务提交给线程池,线程池就会使用一个空闲的线程来执行这个任务,该任务执行完后,该线程不会死亡,而是再次变成空闲状态返回线程池,等待下一个任务的到来。在使用线程池时,我们把要执行的任务提交给整个线程池,而不是提交给某个线程,线程池拿到提交的任务后,会在内部寻找是否还有空闲的线程,如果有,就将这个任务提交给某个空闲的线程,虽然一个线程同一时刻只能执行一个任务,但是我们可以向线程池提交多个任务。合理使用线程池有以下几个优点:
降低资源消耗 多线程运行期间,系统不断的启动和关闭新线程,成本高,会过度消耗系统资源,通过重用存在的线程,减少对象创建、消亡的开销
提高响应速度 当有任务到达时,任务可以不需要等待线程的创建,可以直接从线程池中取出空闲的线程来执行任务
方便线程管理 线程对计算机来说是很稀缺的资源,如果让他无限制创建,它不仅消耗系统的资源,还会降低系统的稳定性,我们使用线程池后可以统一进行分配和监控
谈到线程池就会想到池化技术,核心思想就是把宝贵的资源放到一个池子中,每次要使用都从池子里面取,用完之后又放回池子让别人用。那么线程池在 Java 中是如何实现的呢?

-

Java 四种线程池

在 Java 中 Executors 工具类给我们提供了四种不同使用场景的线程池的创建方法,分别为:

-
    -
  1. newSingleThreadExecutor 只有一个线程来执行任务,适用于有顺序的任务的应用场景。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,它可以保证任务按照指定顺序(FIFO,LIFO)执行,它还有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为
  2. -
  3. newFixedThreadPool 固定线程数的线程池,只有核心线程,核心线程的即为最大的线程数量,没有非核心线程。每次提交一个任务就创建一个线程,直到达到线程池的最大大小。线程池一旦达到最大值就会保持不变,如果当中的某个线程因为异常而结束,那么线程池会新建一个线程加入到线程池中。它还可以控制线程的最大并发数,超出的线程会在阻塞队列(LinkedBlockingQueue)中等待,同样它也有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为。
  4. -
  5. newCachedThreadPool 创建一个可缓存线程池,最大的线程个数为 2^31 - 1(Integer.MAX_VALUE),可以认为是无限大,若无可回收,则新建线程,如果线程池的大小超出了处理任务所需要的线程,那么就会回收部分空闲(60s 不执行任务)的线程。
  6. -
  7. newScheduledThreadPool 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大(Integer.MAX_VALUE:2^31 - 1),适用于执行周期性的任务。
  8. -
+

简介

在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

+

线程池如何处理提交的任务

我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
- + 阅读全文 »
@@ -927,7 +921,7 @@

- +

-

+

@@ -1073,23 +1067,24 @@

-

1.1 前言

做过 java 开发的朋友们相信都很熟悉 HashMap 这个类,它是一个基于 hashing 原理用于存储 Key-Value 键值对的集合,其中的每一个键也叫做 Entry,这些键分别存储在一个数组当中,系统会根据 hash 方法来计算出 Key-Value 的存储位置,可以通过 key 快速存取 value。
HashMap 基于 hashing 原理,当我们将一个键值对(Key-Value) 传入 put 方法时,它将调用这个 key 的 hashcode 方法计算出 key 的 hashcode 值,然后根据这个 hashcode 值来定位其存放数组的位置来存储对象(HashMap 使用链表来解决碰撞问题,当其发生碰撞了,对象将会存储在链表的下一个节点中,在链表的每个节点中存储 Entry 对象,在 JDK 1.8+ 中,当链表的节点个数超过一定值时会转为红黑树来进行存储),当通过 get 方法传入一个 key 来获取其对应的值时,也是先通过 key 的 hashcode 方法来定位其存储在数组的位置,然后通过键对象的 eqauls 方法找到对应的 value 值。接下来让我们看看其内部的一些实现细节。(PS:以下代码分析都是基于 JDK 1.8

-

1.2 为什么容量始终是 2 的整数次幂

因为获取 key 在数组中对应的下标是通过 key 的哈希值与数组的长度减一进行与运算来确定的(tab[(n - 1) & hash])。当数组的长度 n 为 2 的整数次幂,这样进行 n - 1 运算后,之前为 1 的位后面全是 1 ,这样就能保证 (n - 1) & hash 后相应位的值既可能是 1 又可能是 0 ,这完全取决于 key 的哈希值,这样就能保证散列的均匀,同时与运算(位运算)效率高。如果数组的长度 n 不是 2 的整数次幂,会造成更多的 hash 冲突。HashMap 提供了如下四个重载的构造方法来满足不同的使用场景:

+

线程池简介

使用线程池可以很好的提高性能,线程池在运行之初就会创建一定数量的空闲线程,我们将一个任务提交给线程池,线程池就会使用一个空闲的线程来执行这个任务,该任务执行完后,该线程不会死亡,而是再次变成空闲状态返回线程池,等待下一个任务的到来。在使用线程池时,我们把要执行的任务提交给整个线程池,而不是提交给某个线程,线程池拿到提交的任务后,会在内部寻找是否还有空闲的线程,如果有,就将这个任务提交给某个空闲的线程,虽然一个线程同一时刻只能执行一个任务,但是我们可以向线程池提交多个任务。合理使用线程池有以下几个优点:
降低资源消耗 多线程运行期间,系统不断的启动和关闭新线程,成本高,会过度消耗系统资源,通过重用存在的线程,减少对象创建、消亡的开销
提高响应速度 当有任务到达时,任务可以不需要等待线程的创建,可以直接从线程池中取出空闲的线程来执行任务
方便线程管理 线程对计算机来说是很稀缺的资源,如果让他无限制创建,它不仅消耗系统的资源,还会降低系统的稳定性,我们使用线程池后可以统一进行分配和监控
谈到线程池就会想到池化技术,核心思想就是把宝贵的资源放到一个池子中,每次要使用都从池子里面取,用完之后又放回池子让别人用。那么线程池在 Java 中是如何实现的呢?

+

Java 四种线程池

在 Java 中 Executors 工具类给我们提供了四种不同使用场景的线程池的创建方法,分别为:

    -
  1. 无参构造:HashMap(),使用该方法表示全部使用 HashMap 的默认配置参数
  2. -
  3. 指定容量初始值构造:HashMap(int initialCapacity),在初始化 HashMap 时指定其容量大小
  4. -
  5. 指定容量初始值和扩容因子构造:HashMap(int initialCapacity, float loadFactor),使用自定义初始化容量和扩容因子
  6. -
  7. 通过 Map 来构造 HashMap:HashMap(Map<? extends K, ? extends V> m),使用默认的扩容因子,其容量大小有传入的 Map 大小来决定 +
  8. newSingleThreadExecutor 只有一个线程来执行任务,适用于有顺序的任务的应用场景。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,它可以保证任务按照指定顺序(FIFO,LIFO)执行,它还有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为
  9. +
  10. newFixedThreadPool 固定线程数的线程池,只有核心线程,核心线程的即为最大的线程数量,没有非核心线程。每次提交一个任务就创建一个线程,直到达到线程池的最大大小。线程池一旦达到最大值就会保持不变,如果当中的某个线程因为异常而结束,那么线程池会新建一个线程加入到线程池中。它还可以控制线程的最大并发数,超出的线程会在阻塞队列(LinkedBlockingQueue)中等待,同样它也有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为。
  11. +
  12. newCachedThreadPool 创建一个可缓存线程池,最大的线程个数为 2^31 - 1(Integer.MAX_VALUE),可以认为是无限大,若无可回收,则新建线程,如果线程池的大小超出了处理任务所需要的线程,那么就会回收部分空闲(60s 不执行任务)的线程。
  13. +
  14. newScheduledThreadPool 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大(Integer.MAX_VALUE:2^31 - 1),适用于执行周期性的任务。
  15. +
- + 阅读全文 »
- + @@ -1135,7 +1130,7 @@

- +

-

+

@@ -1281,22 +1276,23 @@

-

1.1 前言

同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程的控制流。在容器中,有些也可以作为同步工具类,其它类型的同步工具类还包括闭锁(Latch)、信号量(Semaphore)以及栅栏(Barrier)。阻塞队列(eg: BlockQueue)是一种独特的类:它们不仅能作为保存对象的容器,还能协调生产者和消费者之间的控制流,因为它提供的 takeput 等方法将会阻塞,直到队列达到期望的状态。所有的同步工具类都包含一些特定的属性:它们封装了一些状态,这些状态将决定同步工具类的线程是继续执行还是等待,此外还提供了一些方法对其状态进行操作,以及另一些方法用于高效地等待同步工具类进入到预期状态。

-

1.2 闭锁

闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态。闭锁的作用相当于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开并允许所有线程通过。当闭锁到达结束状态后,将不会再次改变状态,因此这扇门将永远保持打开状态。闭锁可以用来确保某些活动直到其它活动都完成后才继续执行。比如:

-
    -
  • 确保某个计算机在其需要的所有资源初始化后才能继续执行。
  • -
  • 确保某个服务在其依赖的所有服务都已经启动后才启动。
  • -
  • 等待直到某个操作的所有参与者都就绪后再继续执行。 +

    1.1 前言

    做过 java 开发的朋友们相信都很熟悉 HashMap 这个类,它是一个基于 hashing 原理用于存储 Key-Value 键值对的集合,其中的每一个键也叫做 Entry,这些键分别存储在一个数组当中,系统会根据 hash 方法来计算出 Key-Value 的存储位置,可以通过 key 快速存取 value。
    HashMap 基于 hashing 原理,当我们将一个键值对(Key-Value) 传入 put 方法时,它将调用这个 key 的 hashcode 方法计算出 key 的 hashcode 值,然后根据这个 hashcode 值来定位其存放数组的位置来存储对象(HashMap 使用链表来解决碰撞问题,当其发生碰撞了,对象将会存储在链表的下一个节点中,在链表的每个节点中存储 Entry 对象,在 JDK 1.8+ 中,当链表的节点个数超过一定值时会转为红黑树来进行存储),当通过 get 方法传入一个 key 来获取其对应的值时,也是先通过 key 的 hashcode 方法来定位其存储在数组的位置,然后通过键对象的 eqauls 方法找到对应的 value 值。接下来让我们看看其内部的一些实现细节。(PS:以下代码分析都是基于 JDK 1.8

    +

    1.2 为什么容量始终是 2 的整数次幂

    因为获取 key 在数组中对应的下标是通过 key 的哈希值与数组的长度减一进行与运算来确定的(tab[(n - 1) & hash])。当数组的长度 n 为 2 的整数次幂,这样进行 n - 1 运算后,之前为 1 的位后面全是 1 ,这样就能保证 (n - 1) & hash 后相应位的值既可能是 1 又可能是 0 ,这完全取决于 key 的哈希值,这样就能保证散列的均匀,同时与运算(位运算)效率高。如果数组的长度 n 不是 2 的整数次幂,会造成更多的 hash 冲突。HashMap 提供了如下四个重载的构造方法来满足不同的使用场景:

    +
      +
    1. 无参构造:HashMap(),使用该方法表示全部使用 HashMap 的默认配置参数
    2. +
    3. 指定容量初始值构造:HashMap(int initialCapacity),在初始化 HashMap 时指定其容量大小
    4. +
    5. 指定容量初始值和扩容因子构造:HashMap(int initialCapacity, float loadFactor),使用自定义初始化容量和扩容因子
    6. +
    7. 通过 Map 来构造 HashMap:HashMap(Map<? extends K, ? extends V> m),使用默认的扩容因子,其容量大小有传入的 Map 大小来决定
      - + 阅读全文 »
      -
+ @@ -1342,7 +1338,7 @@

- +

-

+

@@ -1488,48 +1484,22 @@

-

1.1 为什么要进行内存区域划分

JVM规范 规定,JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途。以及创建和销毁的时间,有的区域随着虚拟机进程的启动就存在了,而有些区域则依赖用户线程的启动和结束而建立和销毁。JVM 规范对 JVM 定义了运行时统一的内存划分规范,统一了标准,类似于 JDBC 规范一样。JVM 也有许多厂商的不同产品。比如下面的这些:

- - - - - - - - - - - - - - - - - - - - - - - -
厂商JVM
Oracle-SUNHotspot
OracleJRocket
IBMJ9 JVM
阿里Taobao JVM
-

其内存区域划分规范对于 JVM 的含义类似于我们 Java 中的接口,都是起到了规范的作用,JVM 是一台可以运行 Java 应用程序的抽象的计算机。在 JVM 中存在三个重要的概念:

+

1.1 前言

同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程的控制流。在容器中,有些也可以作为同步工具类,其它类型的同步工具类还包括闭锁(Latch)、信号量(Semaphore)以及栅栏(Barrier)。阻塞队列(eg: BlockQueue)是一种独特的类:它们不仅能作为保存对象的容器,还能协调生产者和消费者之间的控制流,因为它提供的 takeput 等方法将会阻塞,直到队列达到期望的状态。所有的同步工具类都包含一些特定的属性:它们封装了一些状态,这些状态将决定同步工具类的线程是继续执行还是等待,此外还提供了一些方法对其状态进行操作,以及另一些方法用于高效地等待同步工具类进入到预期状态。

+

1.2 闭锁

闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态。闭锁的作用相当于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开并允许所有线程通过。当闭锁到达结束状态后,将不会再次改变状态,因此这扇门将永远保持打开状态。闭锁可以用来确保某些活动直到其它活动都完成后才继续执行。比如:

    -
  • JVM 规范:它定义了虚拟机运行的规范,但是由 Oracle(SUN)或者其它厂商实现
  • -
  • Java 运行时环境(JRE:Java Runtime Environment):它是 JVM 规范的具体实现
  • -
  • JVM 实例:编写好 Java 代码之后,运行 Java 程序,此时就会创建 JMV 实例
  • -
-

对于 Java 程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每一个对象去编写内存释放的代码,不要像 C 或者 C++ 要时刻注意着内存泄漏和内存溢出的问题,这种由虚拟机去管理一切看起来都很美好。不过,也正是因为 Java 设计者把内存控制全部交给了 JVM,一旦出现了内存泄漏和溢出方面的问题,如果不了解虚拟机是怎么分配运行时内存的,那么排查错误将是一项非常艰难的工作。

+
  • 确保某个计算机在其需要的所有资源初始化后才能继续执行。
  • +
  • 确保某个服务在其依赖的所有服务都已经启动后才启动。
  • +
  • 等待直到某个操作的所有参与者都就绪后再继续执行。
    - + 阅读全文 »
    -
  • + @@ -1575,7 +1545,7 @@

    - +

    -

    +

    @@ -1721,12 +1691,41 @@

    -

    1.1 什么是 ThreadLocal

    ThreadLocal 简单理解 Thread 即线程,Local 即本地,结合起来理解就是 每个线程都是本地独有的。在早期的计算机中不包含操作系统,从头到尾只执行一个程序,并且这个程序能访问计算中的所有资源,这对于计算机资源来说是一种浪费。要想充分发挥多处理器的强大计算能力,最简单的方式就是使用多线程。与串行程序相比,在并发程序中存在更多容易出错的地方。当访问共享数据时,通常需要使用同步来控制并发程序的访问。一种避免使用同步的方式就是让这部分共享数据变成不共享的,试想一下,如果只是在单个线程内对数据进行访问,那么就可以不用同步了,这种技术称为线程封闭(Thread Confinement),它是实现线程安全最简单的方式之一。
    当某个对象封闭在一个单个线程中时,这种用法会自动实现了线程安全,因为只有一个线程访问数据,从根本上避免了共享数据的线程安全问题,即使被封闭的对象本身不是线程安全的。要保证线程安全,并不是一定就需要同步,两者没有因果关系,同步只是保证共享数据征用时正确性的手段,如果一个方法本来就不涉及共享数据,那它就不需要任何同步措施去保证正确性。而维持线程封闭的一种规范用法就是使用 ThreadLoal,这个类能使当前线程中的某个值与保存的值关联起来。ThreadLocal 提供了 get()set(T value) 等方法,set 方法为每个使用了该变量的线程都存有一份独立的副本,因此当我们调用 get 方法时总是返回由当前线程在调用 set 方法的时候设置的最新值。

    -

    1.2 ThreadLocal 的用法

    接下来通过一个示例代码说明 ThreadLocal 的使用方式,该示例使用了三个不同的线程 Main ThreadThread-1Thread-2 分别对同一个 ThreadLocal 对象中存储副本。

    -
    1
    2
    3
    4
    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
    30
    31
    /**
    * @author mghio
    * @date: 2019-10-20
    * @version: 1.0
    * @description: Java 并发之 ThreadLocal
    * @since JDK 1.8
    */
    public class ThreadLocalDemoTests {
    private ThreadLocal<String> boolThreadLocal = ThreadLocal.withInitial(() -> "");

    @Test
    public void testUseCase() {
    boolThreadLocal.set("main-thread-set");
    System.out.printf("Main Thread: %s\n", boolThreadLocal.get());

    new Thread("Thread-1") {
    @Override
    public void run() {
    boolThreadLocal.set("thread-1-set");
    System.out.printf("Thread-1: %s\n", boolThreadLocal.get());
    }
    }.start();

    new Thread("Thread-2") {
    @Override
    public void run() {
    System.out.printf("Thread-2: %s\n", boolThreadLocal.get());
    }
    }.start();
    }
    }
    +

    1.1 为什么要进行内存区域划分

    JVM规范 规定,JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途。以及创建和销毁的时间,有的区域随着虚拟机进程的启动就存在了,而有些区域则依赖用户线程的启动和结束而建立和销毁。JVM 规范对 JVM 定义了运行时统一的内存划分规范,统一了标准,类似于 JDBC 规范一样。JVM 也有许多厂商的不同产品。比如下面的这些:

    + + + + + + + + + + + + + + + + + + + + + + + +
    厂商JVM
    Oracle-SUNHotspot
    OracleJRocket
    IBMJ9 JVM
    阿里Taobao JVM
    +

    其内存区域划分规范对于 JVM 的含义类似于我们 Java 中的接口,都是起到了规范的作用,JVM 是一台可以运行 Java 应用程序的抽象的计算机。在 JVM 中存在三个重要的概念:

    +
      +
    • JVM 规范:它定义了虚拟机运行的规范,但是由 Oracle(SUN)或者其它厂商实现
    • +
    • Java 运行时环境(JRE:Java Runtime Environment):它是 JVM 规范的具体实现
    • +
    • JVM 实例:编写好 Java 代码之后,运行 Java 程序,此时就会创建 JMV 实例
    • +
    +

    对于 Java 程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每一个对象去编写内存释放的代码,不要像 C 或者 C++ 要时刻注意着内存泄漏和内存溢出的问题,这种由虚拟机去管理一切看起来都很美好。不过,也正是因为 Java 设计者把内存控制全部交给了 JVM,一旦出现了内存泄漏和溢出方面的问题,如果不了解虚拟机是怎么分配运行时内存的,那么排查错误将是一项非常艰难的工作。

    - + 阅读全文 »
    @@ -1779,7 +1778,7 @@

    - +

    -

    +

    @@ -1914,12 +1924,12 @@

    -

    1.1 split 的坑

    前几天在公司对通过 FTP 方式上传的数据文件按照事先规定的格式进行解析后入库,代码的大概实现思路是这样的:先使用流进行文件读取,对文件的每一行数据解析封装成一个个对象,然后进行入库操作。本以为很简单的一个操作,然后写完代码后自己测试发现对文件的每一行进行字符串分割的时候存在问题,在这里做个简单的记录总结。在 Java 中使用 split 方法对字符串进行分割是经常使用的方法,经常在一些文本处理、字符串分割的逻辑中,需要按照一定的分隔符进行分割拆解。这样的功能,大多数情况下我们都会使用 String 中的 split 方法。关于这个方法,稍不注意很容易踩坑。

    -

    (1)split 的参数是正则表达式
    首先一个常见的问题,就是忘记了 String 的 split 方法的参数不是普通的字符串,而是正则表达式,例如下面的这两种使用方式都达不到我们的预期:

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * @author mghio
    * @date: 2019-10-13
    * @version: 1.0
    * @description: Java 字符串 split 踩坑记
    * @since JDK 1.8
    */
    public class JavaStringSplitTests {

    @Test
    public void testStringSplitRegexArg() {
    System.out.println(Arrays.toString("m.g.h.i.o".split(".")));
    System.out.println(Arrays.toString("m|g|h|i|o".split("|")));
    }

    }
    +

    1.1 什么是 ThreadLocal

    ThreadLocal 简单理解 Thread 即线程,Local 即本地,结合起来理解就是 每个线程都是本地独有的。在早期的计算机中不包含操作系统,从头到尾只执行一个程序,并且这个程序能访问计算中的所有资源,这对于计算机资源来说是一种浪费。要想充分发挥多处理器的强大计算能力,最简单的方式就是使用多线程。与串行程序相比,在并发程序中存在更多容易出错的地方。当访问共享数据时,通常需要使用同步来控制并发程序的访问。一种避免使用同步的方式就是让这部分共享数据变成不共享的,试想一下,如果只是在单个线程内对数据进行访问,那么就可以不用同步了,这种技术称为线程封闭(Thread Confinement),它是实现线程安全最简单的方式之一。
    当某个对象封闭在一个单个线程中时,这种用法会自动实现了线程安全,因为只有一个线程访问数据,从根本上避免了共享数据的线程安全问题,即使被封闭的对象本身不是线程安全的。要保证线程安全,并不是一定就需要同步,两者没有因果关系,同步只是保证共享数据征用时正确性的手段,如果一个方法本来就不涉及共享数据,那它就不需要任何同步措施去保证正确性。而维持线程封闭的一种规范用法就是使用 ThreadLoal,这个类能使当前线程中的某个值与保存的值关联起来。ThreadLocal 提供了 get()set(T value) 等方法,set 方法为每个使用了该变量的线程都存有一份独立的副本,因此当我们调用 get 方法时总是返回由当前线程在调用 set 方法的时候设置的最新值。

    +

    1.2 ThreadLocal 的用法

    接下来通过一个示例代码说明 ThreadLocal 的使用方式,该示例使用了三个不同的线程 Main ThreadThread-1Thread-2 分别对同一个 ThreadLocal 对象中存储副本。

    +
    1
    2
    3
    4
    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
    30
    31
    /**
    * @author mghio
    * @date: 2019-10-20
    * @version: 1.0
    * @description: Java 并发之 ThreadLocal
    * @since JDK 1.8
    */
    public class ThreadLocalDemoTests {
    private ThreadLocal<String> boolThreadLocal = ThreadLocal.withInitial(() -> "");

    @Test
    public void testUseCase() {
    boolThreadLocal.set("main-thread-set");
    System.out.printf("Main Thread: %s\n", boolThreadLocal.get());

    new Thread("Thread-1") {
    @Override
    public void run() {
    boolThreadLocal.set("thread-1-set");
    System.out.printf("Thread-1: %s\n", boolThreadLocal.get());
    }
    }.start();

    new Thread("Thread-2") {
    @Override
    public void run() {
    System.out.printf("Thread-2: %s\n", boolThreadLocal.get());
    }
    }.start();
    }
    }
    - + 阅读全文 »
    @@ -1972,7 +1982,7 @@

    - +

    -

    +

    @@ -2107,10 +2117,12 @@

    -

    1.1 什么是字节码?

    Java 在刚刚诞生之时曾经提出过一个非常著名的口号: “一次编写,到处运行(write once,run anywhere)”,这句话充分表达了软件开发人员对冲破平台界限的渴求。“与平台无关”的理想最终实现在操作系统的运用层上: 虚拟机提供商开发了许多可以运行在不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码,从而实现了程序的“一次编写到处运行”。

    各种不同平台的虚拟机与所有平台都统一使用的程序存储格式—字节码(ByteCode),因此,可以看出字节码对 Java 生态的重要性。之所以被称为字节码,是因为字节码是由十六进制组成的,而 JVM(Java Virtual Machine)以两个十六进制为一组,即以字节为单位进行读取。在 Java 中使用 javac 命令把源代码编译成字节码文件,一个 .java 源文件从编译成 .class 字节码文件的示例如图 1 所示:
    图1

    图 1

    +

    1.1 split 的坑

    前几天在公司对通过 FTP 方式上传的数据文件按照事先规定的格式进行解析后入库,代码的大概实现思路是这样的:先使用流进行文件读取,对文件的每一行数据解析封装成一个个对象,然后进行入库操作。本以为很简单的一个操作,然后写完代码后自己测试发现对文件的每一行进行字符串分割的时候存在问题,在这里做个简单的记录总结。在 Java 中使用 split 方法对字符串进行分割是经常使用的方法,经常在一些文本处理、字符串分割的逻辑中,需要按照一定的分隔符进行分割拆解。这样的功能,大多数情况下我们都会使用 String 中的 split 方法。关于这个方法,稍不注意很容易踩坑。

    +

    (1)split 的参数是正则表达式
    首先一个常见的问题,就是忘记了 String 的 split 方法的参数不是普通的字符串,而是正则表达式,例如下面的这两种使用方式都达不到我们的预期:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * @author mghio
    * @date: 2019-10-13
    * @version: 1.0
    * @description: Java 字符串 split 踩坑记
    * @since JDK 1.8
    */
    public class JavaStringSplitTests {

    @Test
    public void testStringSplitRegexArg() {
    System.out.println(Arrays.toString("m.g.h.i.o".split(".")));
    System.out.println(Arrays.toString("m|g|h|i|o".split("|")));
    }

    }
    - + 阅读全文 »
    @@ -2163,7 +2175,7 @@

    - +

    -

    +

    @@ -2298,10 +2310,10 @@

    -
    1
    2
    3
    4
    5
    6
    7
    public class HelloWorld {

    public static void main(String[] args) {
    System.out.println("Hello World ~~~");
    }

    }
    +

    1.1 什么是字节码?

    Java 在刚刚诞生之时曾经提出过一个非常著名的口号: “一次编写,到处运行(write once,run anywhere)”,这句话充分表达了软件开发人员对冲破平台界限的渴求。“与平台无关”的理想最终实现在操作系统的运用层上: 虚拟机提供商开发了许多可以运行在不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码,从而实现了程序的“一次编写到处运行”。

    各种不同平台的虚拟机与所有平台都统一使用的程序存储格式—字节码(ByteCode),因此,可以看出字节码对 Java 生态的重要性。之所以被称为字节码,是因为字节码是由十六进制组成的,而 JVM(Java Virtual Machine)以两个十六进制为一组,即以字节为单位进行读取。在 Java 中使用 javac 命令把源代码编译成字节码文件,一个 .java 源文件从编译成 .class 字节码文件的示例如图 1 所示:
    图1

    图 1

    - + 阅读全文 »
    @@ -2345,7 +2357,7 @@

    @@ -2393,7 +2405,7 @@

    - 30 + 31 日志 @@ -2404,7 +2416,7 @@

    @@ -2415,7 +2427,7 @@

    diff --git a/page/4/index.html b/page/4/index.html new file mode 100644 index 00000000..cba93a32 --- /dev/null +++ b/page/4/index.html @@ -0,0 +1,1407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/post/102cd3d9.html b/post/102cd3d9.html index 7f30ce86..2fe0bc5f 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -847,7 +847,7 @@

    总结 - 30 + 31 日志 @@ -858,7 +858,7 @@

    总结 - 30 + 31 分类 @@ -869,7 +869,7 @@

    总结 - 27 + 28 标签 diff --git a/post/11cb7677.html b/post/11cb7677.html index a900d1f4..8082e6bf 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -698,7 +698,7 @@

    总结 - 30 + 31 日志 @@ -709,7 +709,7 @@

    总结 - 30 + 31 分类 @@ -720,7 +720,7 @@

    总结 - 27 + 28 标签 diff --git a/post/192cb539.html b/post/192cb539.html index f31b06dc..c4ea72c6 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -762,7 +762,7 @@

    - 30 + 31 日志 @@ -773,7 +773,7 @@

    @@ -784,7 +784,7 @@

    diff --git a/post/24042edf.html b/post/24042edf.html index c2f8cb09..62407fc1 100644 --- a/post/24042edf.html +++ b/post/24042edf.html @@ -770,7 +770,7 @@

    总结 - 30 + 31 日志 @@ -781,7 +781,7 @@

    总结 - 30 + 31 分类 @@ -792,7 +792,7 @@

    总结 - 27 + 28 标签 diff --git a/post/34755d6c.html b/post/34755d6c.html index e72b8a79..3b00aa4f 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -677,7 +677,7 @@

    总结 - 30 + 31 日志 @@ -688,7 +688,7 @@

    总结 - 30 + 31 分类 @@ -699,7 +699,7 @@

    总结 - 27 + 28 标签 diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index 9a371c0e..1da1293e 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -744,7 +744,7 @@

    总结 - 30 + 31 日志 @@ -755,7 +755,7 @@

    总结 - 30 + 31 分类 @@ -766,7 +766,7 @@

    总结 - 27 + 28 标签 diff --git a/post/4615256d.html b/post/4615256d.html index 7269938e..68d1c2f3 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -753,7 +753,7 @@

    - 30 + 31 日志 @@ -764,7 +764,7 @@

    - 30 + 31 分类 @@ -775,7 +775,7 @@

    - 27 + 28 标签 diff --git a/post/4b00e13c.html b/post/4b00e13c.html index 93befd47..a29385db 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -852,7 +852,7 @@

    总结 - 30 + 31 日志 @@ -863,7 +863,7 @@

    总结 - 30 + 31 分类 @@ -874,7 +874,7 @@

    总结 - 27 + 28 标签 diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index fdb662fe..b17b2727 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -685,7 +685,7 @@

    总结 - 30 + 31 日志 @@ -696,7 +696,7 @@

    总结 - 30 + 31 分类 @@ -707,7 +707,7 @@

    总结 - 27 + 28 标签 diff --git a/post/51e5bd99.html b/post/51e5bd99.html index b7558ebb..93ee3cba 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -726,7 +726,7 @@

    - 30 + 31 日志 @@ -737,7 +737,7 @@

    - 30 + 31 分类 @@ -748,7 +748,7 @@

    - 27 + 28 标签 diff --git a/post/710bd10b.html b/post/710bd10b.html index cf1bcb0e..2e44a4bb 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -732,7 +732,7 @@

    总结 - 30 + 31 日志 @@ -743,7 +743,7 @@

    总结 - 30 + 31 分类 @@ -754,7 +754,7 @@

    总结 - 27 + 28 标签 diff --git a/post/7528c810.html b/post/7528c810.html index 821fcd80..48b30844 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -715,7 +715,7 @@

    总结 - 30 + 31 日志 @@ -726,7 +726,7 @@

    总结 - 30 + 31 分类 @@ -737,7 +737,7 @@

    总结 - 27 + 28 标签 diff --git a/post/7b9ead86.html b/post/7b9ead86.html index 0a7f1c64..2ea1365a 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -715,7 +715,7 @@

    总结 - 30 + 31 日志 @@ -726,7 +726,7 @@

    总结 - 30 + 31 分类 @@ -737,7 +737,7 @@

    总结 - 27 + 28 标签 diff --git a/post/7eb2637f.html b/post/7eb2637f.html index bcf0444e..efab65b9 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -754,7 +754,7 @@

    - 30 + 31 日志 @@ -765,7 +765,7 @@

    - 30 + 31 分类 @@ -776,7 +776,7 @@

    - 27 + 28 标签 diff --git a/post/817c7d82.html b/post/817c7d82.html index f17f66cf..f1dd99c4 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1323,7 +1323,7 @@

    - 30 + 31 日志 @@ -1334,7 +1334,7 @@
    - 30 + 31 分类 @@ -1345,7 +1345,7 @@
    - 27 + 28 标签 diff --git a/post/8a061473.html b/post/8a061473.html index ece0a027..17140a47 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -791,7 +791,7 @@
    - 30 + 31 日志 @@ -802,7 +802,7 @@
    - 30 + 31 分类 @@ -813,7 +813,7 @@
    - 27 + 28 标签 diff --git a/post/8bd965a0.html b/post/8bd965a0.html index 007436a2..20b67169 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -714,7 +714,7 @@

    - 30 + 31 日志 @@ -725,7 +725,7 @@

    @@ -736,7 +736,7 @@

    diff --git a/post/99ea2970.html b/post/99ea2970.html index 75c58eae..333bb4b7 100644 --- a/post/99ea2970.html +++ b/post/99ea2970.html @@ -710,7 +710,7 @@

    - 30 + 31 日志 @@ -721,7 +721,7 @@

    @@ -732,7 +732,7 @@

    diff --git a/post/a38c0645.html b/post/a38c0645.html index 989dd491..2b5875bc 100644 --- a/post/a38c0645.html +++ b/post/a38c0645.html @@ -694,7 +694,7 @@

    总结 - 30 + 31 日志 @@ -705,7 +705,7 @@

    总结 - 30 + 31 分类 @@ -716,7 +716,7 @@

    总结 - 27 + 28 标签 diff --git a/post/ab706eb5.html b/post/ab706eb5.html index 64f2ce45..883769a2 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -697,7 +697,7 @@

    总结 - 30 + 31 日志 @@ -708,7 +708,7 @@

    总结 - 30 + 31 分类 @@ -719,7 +719,7 @@

    总结 - 27 + 28 标签 diff --git a/post/b1d4025b.html b/post/b1d4025b.html index 8b825710..79a2a8a9 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -627,7 +627,7 @@

    hello world

    - 30 + 31 日志 @@ -638,7 +638,7 @@

    hello world

    @@ -649,7 +649,7 @@

    hello world

    diff --git a/post/bc557e1a.html b/post/bc557e1a.html index 798108f1..a6b7e0b8 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -762,7 +762,7 @@
    - 30 + 31 日志 @@ -773,7 +773,7 @@
    - 30 + 31 分类 @@ -784,7 +784,7 @@
    - 27 + 28 标签 diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index 8cc88259..8b08c349 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -714,7 +714,7 @@

    - 30 + 31 日志 @@ -725,7 +725,7 @@

    @@ -736,7 +736,7 @@

    diff --git a/post/c34b451f.html b/post/c34b451f.html index 860b9476..98d91714 100644 --- a/post/c34b451f.html +++ b/post/c34b451f.html @@ -753,7 +753,7 @@

    总结 - 30 + 31 日志 @@ -764,7 +764,7 @@

    总结 - 30 + 31 分类 @@ -775,7 +775,7 @@

    总结 - 27 + 28 标签 diff --git a/post/d7d0fc76.html b/post/d7d0fc76.html index 14749f43..300fba31 100644 --- a/post/d7d0fc76.html +++ b/post/d7d0fc76.html @@ -588,6 +588,10 @@

    + + @@ -675,7 +679,7 @@

    - 30 + 31 日志 @@ -686,7 +690,7 @@

    - 30 + 31 分类 @@ -697,7 +701,7 @@

    - 27 + 28 标签 diff --git a/post/e09f0428.html b/post/e09f0428.html index 6751e8b6..1f1e9f12 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -684,7 +684,7 @@

    - 30 + 31 日志 @@ -695,7 +695,7 @@

    - 30 + 31 分类 @@ -706,7 +706,7 @@

    - 27 + 28 标签 diff --git a/post/ee27c07f.html b/post/ee27c07f.html index ce5ac068..a2dd455c 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -677,7 +677,7 @@

    - 30 + 31 日志 @@ -688,7 +688,7 @@

    @@ -699,7 +699,7 @@

    diff --git a/post/f440d00b.html b/post/f440d00b.html index b7bbaceb..087c1548 100644 --- a/post/f440d00b.html +++ b/post/f440d00b.html @@ -713,7 +713,7 @@

    总结 - 30 + 31 日志 @@ -724,7 +724,7 @@

    总结 - 30 + 31 分类 @@ -735,7 +735,7 @@

    总结 - 27 + 28 标签 diff --git a/post/f92758d8.html b/post/f92758d8.html index f850e4f2..3ab7260a 100644 --- a/post/f92758d8.html +++ b/post/f92758d8.html @@ -701,7 +701,7 @@

    总结 - 30 + 31 日志 @@ -712,7 +712,7 @@

    总结 - 30 + 31 分类 @@ -723,7 +723,7 @@

    总结 - 27 + 28 标签 diff --git a/post/fa75f5d7.html b/post/fa75f5d7.html new file mode 100644 index 00000000..564a15a7 --- /dev/null +++ b/post/fa75f5d7.html @@ -0,0 +1,1612 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 从 CPU 缓存看缓存的套路 | mghio + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    +
    +
    +
    + + +
    + + + + + + + + +
    + + + +
    + + + + + + + +
    + + + +

    从 CPU 缓存看缓存的套路

    + + + +
    + + + + + +
    + + + + + +

    一、前言

    不同存储技术的访问时间差异很大,从 计算机层次结构 可知,通常情况下,从高层往底层走,存储设备变得更慢、更便宜同时体积也会更大,CPU 和内存之间的速度存在着巨大的差异,此时就会想到计算机科学界中一句著名的话:计算机科学的任何一个问题,都可以通过增加一个中间层来解决。

    +

    二、引入缓存层

    为了解决速度不匹配问题,可以通过引入一个缓存中间层来解决问题,但是也会引入一些新的问题。现代计算机系统中,从硬件到操作系统、再到一些应用程序,绝大部分的设计都用到了著名的局部性原理,局部性通常有如下两种不同的形式:

    +
    +

    时间局部性:在一个具有良好的时间局部性的程序当中,被引用过一次的内存位置,在将来一个不久的时间内很可能会被再次引用到。

    +
    +
    +

    空间局部性:在一个具有良好的空间局部性的程序当中,一个内存位置被引用了一次,那么在不久的时间内很可能会引用附近的位置。

    +
    + + +

    有上面这个局部性原理为理论指导,为了解决二者速度不匹配问题就可以在 CPU 和内存之间加一个缓存层,于是就有了如下的结构:

    +

    Xnip2020-08-16_22-51-12.jpg

    +

    三、何时更新缓存

    CPU 中引入缓存中间层后,虽然可以解决和内存速度不一致的问题,但是同时也面临着一个问题:当 CPU 更新了其缓存中的数据之后,要什么时候去写入到内存中呢?,比较容易想到的一个解决方案就是,CPU 更新了缓存的数据之后就立即更新到内存中,也就是说当 CPU 更新了缓存的数据之后就会从上到下更新,直到内存为止,英文称之为write through,这种方式的优点是比较简单,但是缺点也很明显,由于每次都需要访问内存,所以速度会比较慢。还有一种方法就是,当 CPU 更新了缓存之后并不马上更新到内存中去,在适当的时候再执行写入内存的操作,因为有很多的缓存只是存储一些中间结果,没必要每次都更新到内存中去,英文称之为write back,这种方式的优点是 CPU 执行更新的效率比较高,缺点就是实现起来会比较复杂。

    +

    上面说的在适当的时候写入内存,如果是单核 CPU 的话,可以在缓存要被新进入的数据取代时,才更新内存,但是在多核 CPU 的情况下就比较复杂了,由于 CPU 的运算速度超越了 1 级缓存的数据 I\O 能力,CPU 厂商又引入了多级的缓存结构,比如常见的 L1、L2、L3 三级缓存结构,L1 和 L2 为 CPU 核心独有,L3 为 CPU 共享缓存。

    +

    Xnip2020-08-16_23-39-28.jpg

    +

    如果现在分别有两个线程运行在两个不同的核 Core 1Core 2 上,内存中 i 的值为 1,这两个分别运行在两个不同核上的线程要对 i 进行加 1 操作,如果不加一些限制,两个核心同时从内存中读取 i 的值,然后进行加 1 操作后再分别写入内存中,可能会出现相互覆盖的情况,解决的方法相信大家都能想得到,第一种是只要有一个核心修改了缓存的数据之后,就立即把内存和其它核心更新。第二种是当一个核心修改了缓存的数据之后,就把其它同样复制了该数据的 CPU 核心失效掉这些数据,等到合适的时机再更新,通常是下一次读取该缓存的时候发现已经无效,才从内存中加载最新的值。

    +

    四、缓存一致性协议

    不难看出第一种需要频繁访问内存更新数据,执行效率比较低,而第二种会把更新数据推迟到最后一刻才会更新,读取内存,效率高(类似于懒加载)。 缓存一致性协议(MESI) 就是使用第二种方案,该协议主要是保证缓存内部数据的一致,不让系统数据混乱。MESI 是指 4 种状态的首字母。每个缓存存储数据单元(Cache line)有 4 种不同的状态,用 2 个 bit 表示,状态和对应的描述如下:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    状态描述监听任务
    M 修改 (Modified)该 Cache line 有效,数据被修改了,和内存中的数据不一致,数据只存在于本 Cache 中Cache line 必须时刻监听所有试图读该缓存行相对就主存的操作,这种操作必须在缓存将该缓存行写回主存并将状态变成 S(共享)状态之前被延迟执行
    E 独享、互斥 (Exclusive)该 Cache line 有效,数据和内存中的数据一致,数据只存在于本 Cache 中Cache line 必须监听其它缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行需要变成 S(共享)状态
    S 共享 (Shared)该 Cache line 有效,数据和内存中的数据一致,数据存在于很多 Cache 中Cache line 必须监听其它缓存使该缓存行无效或者独享该缓存行的请求,并将该 Cache line 变成无效
    I 无效 (Invalid)该 Cache line 无效无监听任务
    +

    下面看看基于缓存一致性协议是如何进行读取和写入操作的, 假设现在有一个双核的 CPU,为了描述方便,简化一下只看其逻辑结构:

    +

    Xnip2020-08-17_08-44-37.jpg

    +

    单核读取步骤Core 0 发出一条从内存中读取 a 的指令,从内存通过 BUS 读取 a 到 Core 0 的缓存中,因为此时数据只在 Core 0 的缓存中,所以将 Cache line 修改为 E 状态(独享),该过程用示意图表示如下:

    +

    dnmKYQ.jpg

    +

    双核读取步骤:首先 Core 0 发出一条从内存中读取 a 的指令,从内存通过 BUS 读取 a 到 Core 0 的缓存中,然后将 Cache line 置为 E 状态,此时 Core 1 发出一条指令,也是要从内存中读取 a,当 Core 1 试图从内存读取 a 的时候, Core 0 检测到了发生地址冲突(其它缓存读主存中该缓存行的操作),然后 Core 0 对相关数据做出响应,a 存储于这两个核心 Core 0Core 1 的缓存行中,然后设置其状态为 S 状态(共享),该过程示意图如下:

    +

    dnQsoV.jpg

    +

    假设此时 Core 0 核心需要对 a 进行修改了,首先 Core 0 会将其缓存的 a 设置为 M(修改)状态,然后通知其它缓存了 a 的其它核 CPU(比如这里的 Core 1)将内部缓存的 a 的状态置为 I(无效)状态,最后才对 a 进行赋值操作。该过程如下所示:

    +

    dnQxeI.jpg

    +

    细心的朋友们可能已经注意到了,上图中内存中 a 的值(值为 1)并不等于 Core 0 核心中缓存的最新值(值为 2),那么要什么时候才会把该值更新到内存中去呢?就是当 Core 1 需要读取 a 的值的时候,此时会通知 Core 0a 的修改后的最新值同步到内存(Memory)中去,在这个同步的过程中 Core 0 中缓存的 a 的状态会置为 E(独享)状态,同步完成后将 Core 0Core 1 中缓存的 a 置为 S(共享)状态,示意图描述该过程如下所示:

    +

    dn8HHA.jpg

    +

    至此,变量 aCPU 的两个核 Core 0Core 1 中回到了 S(共享)状态了,以上只是简单的描述了一下大概的过程,实际上这些都是在 CPU 的硬件层面上去保证的,而且操作比较复杂。

    +

    五、总结

    现在很多一些实现缓存功能的应用程序都是基于这些思想设计的,缓存把数据库中的数据进行缓存到速度更快的内存中,可以加快我们应用程序的响应速度,比如我们使用常见的 Redis 数据库可能是采用下面这些策略:① 首先应用程序从缓存中查询数据,如果有就直接使用该数据进行相应操作后返回,如果没有则查询数据库,更新缓存并且返回。② 当我们需要更新数据时,先更新数据库,然后再让缓存失效,这样下次就会先查询数据库再回填到缓存中去,可以发现,实际上底层的一些思想都是相通的,不同的只是对于特定的场景可能需要增加一些额外的约束。基础知识才是技术这颗大树的根,我们先把根栽好了,剩下的那些枝和叶都是比较容易得到的东西了。

    + + +
    + + + + + +
    +
    -------------本文结束感谢您的阅读-------------
    +
    + + + +
    +
    + mghio wechat +
    微信公众号「mghio」
    +
    + +
    + + + +
    +
    +
    请我吃🍗
    + + +
    + +
    + + + +
    + +
    + + + +
    + + + +
    + + + +
    + +
    +
    + + +
    + + + + + + +
    +
    + +
    +
    + + + + + +
    + + + + + + + + + +
    +
    + +
    + +
    + + +
    + + +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/post/fe76043.html b/post/fe76043.html index d2e36217..5b7b1b8d 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -680,7 +680,7 @@

    总结 - 30 + 31 日志 @@ -691,7 +691,7 @@

    总结 - 30 + 31 分类 @@ -702,7 +702,7 @@

    总结 - 27 + 28 标签 diff --git a/search.xml b/search.xml index de51bfa3..6f91a006 100644 --- a/search.xml +++ b/search.xml @@ -1,5 +1,18 @@ + + <![CDATA[从 CPU 缓存看缓存的套路]]> + %2Fpost%2Ffa75f5d7.html + + + Java + 缓存 + + + Java + 缓存 + + <![CDATA[Java 集合类 List 的那些坑]]> %2Fpost%2Fd7d0fc76.html diff --git a/sitemap.xml b/sitemap.xml index 67627114..6db64bd3 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,13 @@ + + https://www.mghio.cn/post/fa75f5d7.html + + 2020-09-24T15:15:59.031Z + + + https://www.mghio.cn/post/d7d0fc76.html diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index af95d6aa..6b27bda3 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index f8e41708..722fc78d 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index d889ea0f..b002a919 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/GC/index.html b/tags/GC/index.html index 1901a3fc..8fc02d85 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/Guava/index.html b/tags/Guava/index.html index 33d75df2..be5e3052 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index 5ec688fc..61cb3622 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index 52579210..84ae4171 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/JDK/index.html b/tags/JDK/index.html index aaec5748..fc5f4bde 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/JVM/index.html b/tags/JVM/index.html index 99f84e22..b6b73726 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -412,7 +412,7 @@

    - 30 + 31 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index 8bf627e2..351e27cd 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index 5c0da6ce..cb34af71 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/Java/index.html b/tags/Java/index.html index 4dc48778..e1816458 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -309,6 +309,32 @@

    Java标签 + + + + + +
    @@ -541,32 +567,6 @@

    - - - - - - @@ -624,7 +624,7 @@

    - 30 + 31 日志 @@ -635,7 +635,7 @@

    @@ -646,7 +646,7 @@

    diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index a475b71d..571d4e75 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -309,6 +309,32 @@

    Java标签 + + + + + +
    @@ -541,32 +567,6 @@

    - - - - - - @@ -624,7 +624,7 @@

    - 30 + 31 日志 @@ -635,7 +635,7 @@

    @@ -646,7 +646,7 @@

    diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index ae853de8..b7e8f544 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -309,6 +309,32 @@

    Java标签 + + + + + +
    @@ -520,7 +546,7 @@

    - 30 + 31 日志 @@ -531,7 +557,7 @@

    @@ -542,7 +568,7 @@

    diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index 9b0dfaa0..4f3149ab 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/List/index.html b/tags/List/index.html index accf28fd..8dc3f09f 100644 --- a/tags/List/index.html +++ b/tags/List/index.html @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/RabbitMQ/index.html b/tags/RabbitMQ/index.html index 985958d4..11e1516e 100644 --- a/tags/RabbitMQ/index.html +++ b/tags/RabbitMQ/index.html @@ -412,7 +412,7 @@

    - 30 + 31 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git a/tags/String/index.html b/tags/String/index.html index cff5b96c..88c7cd99 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/index.html b/tags/index.html index 2bde9de3..c7af2b69 100644 --- a/tags/index.html +++ b/tags/index.html @@ -317,10 +317,10 @@

    @@ -378,7 +378,7 @@

    - 30 + 31 日志 @@ -389,7 +389,7 @@

    @@ -400,7 +400,7 @@

    diff --git a/tags/mockito/index.html b/tags/mockito/index.html index 4c191d95..26641acf 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/test/index.html b/tags/test/index.html index b697d951..7a1e2489 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index a1573bda..a04c8faf 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index 7043055f..d7cb1352 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -412,7 +412,7 @@

    - 30 + 31 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 26bc1d21..424764a7 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -412,7 +412,7 @@

    - 30 + 31 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index 7fc8f418..ceedec65 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index c6067acb..c48dee2c 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -412,7 +412,7 @@

    - 30 + 31 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index cee08a40..9b34f122 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index d9dc4664..1a0384a0 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 1020cded..4c1de589 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\347\274\223\345\255\230/index.html" "b/tags/\347\274\223\345\255\230/index.html" new file mode 100644 index 00000000..cff19276 --- /dev/null +++ "b/tags/\347\274\223\345\255\230/index.html" @@ -0,0 +1,1253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: 缓存 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index 3820e906..5ee56246 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -386,7 +386,7 @@

    - 30 + 31 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    From 3afb1ce7f8db85b53fcba61996b986e059e4d843 Mon Sep 17 00:00:00 2001 From: maguihai Date: Thu, 8 Oct 2020 15:35:42 +0800 Subject: [PATCH 09/19] Site updated: 2020-10-08 15:35:41 --- about/index.html | 6 +- archives/2019/10/index.html | 8 +- archives/2019/11/index.html | 8 +- archives/2019/12/index.html | 8 +- archives/2019/index.html | 8 +- archives/2019/page/2/index.html | 8 +- archives/2020/01/index.html | 8 +- archives/2020/02/index.html | 8 +- archives/2020/03/index.html | 8 +- archives/2020/04/index.html | 8 +- archives/2020/05/index.html | 8 +- archives/2020/06/index.html | 8 +- archives/2020/07/index.html | 8 +- archives/2020/08/index.html | 8 +- archives/2020/09/index.html | 8 +- archives/2020/10/index.html | 1272 +++++++++++++ archives/2020/index.html | 78 +- archives/2020/page/2/index.html | 43 +- archives/index.html | 78 +- archives/page/2/index.html | 78 +- archives/page/3/index.html | 78 +- archives/page/4/index.html | 43 +- atom.xml | 89 +- baidusitemap.xml | 3 + categories/JDK/Java/index.html | 6 +- .../index.html" | 6 +- categories/JDK/index.html | 6 +- categories/Java/Bloom-filter/index.html | 6 +- categories/Java/GC/index.html | 6 +- categories/Java/Guava/String/index.html | 6 +- categories/Java/Guava/index.html | 6 +- categories/Java/IDEA/index.html | 6 +- .../IDEA/\345\267\245\345\205\267/index.html" | 6 +- .../IO\346\250\241\345\236\213/index.html" | 6 +- categories/Java/JVM/index.html | 6 +- categories/Java/List/index.html | 6 +- categories/Java/index.html | 6 +- categories/Java/page/2/index.html | 6 +- categories/Java/page/3/index.html | 6 +- categories/Java/unit-test/index.html | 6 +- categories/Java/unit-test/mockito/index.html | 6 +- .../Java/\345\216\237\347\220\206/index.html" | 6 +- .../Java/\345\217\215\345\260\204/index.html" | 6 +- .../index.html" | 6 +- .../Java/\345\271\266\345\217\221/index.html" | 6 +- .../\350\277\233\351\230\266/index.html" | 6 +- .../Java/\345\274\202\346\255\245/index.html" | 6 +- .../Eureka/index.html" | 6 +- .../index.html" | 6 +- .../index.html" | 6 +- .../Java/\347\274\223\345\255\230/index.html" | 6 +- .../Java/\351\207\215\346\236\204/index.html" | 6 +- .../Linux\347\254\224\350\256\260/index.html" | 6 +- categories/RabbitMQ/Java/index.html | 6 +- categories/RabbitMQ/index.html | 6 +- categories/Spring/Java/index.html | 1254 +++++++++++++ categories/Spring/index.html | 1254 +++++++++++++ categories/index.html | 10 +- .../CAP\345\256\232\347\220\206/index.html" | 6 +- .../index.html" | 6 +- css/main.css | 2 +- index.html | 338 ++-- page/2/index.html | 376 ++-- page/3/index.html | 407 +++-- page/4/index.html | 197 +- post/102cd3d9.html | 6 +- post/11cb7677.html | 6 +- post/192cb539.html | 6 +- post/24042edf.html | 6 +- post/34755d6c.html | 6 +- post/3ae0ff4e.html | 6 +- post/4615256d.html | 6 +- post/4b00e13c.html | 6 +- post/4ea48fa7.html | 6 +- post/51e5bd99.html | 6 +- post/558ca0bd.html | 1582 +++++++++++++++++ post/710bd10b.html | 6 +- post/7528c810.html | 6 +- post/7b9ead86.html | 6 +- post/7eb2637f.html | 6 +- post/817c7d82.html | 6 +- post/8a061473.html | 6 +- post/8bd965a0.html | 6 +- post/99ea2970.html | 6 +- post/a38c0645.html | 6 +- post/ab706eb5.html | 6 +- post/b1d4025b.html | 6 +- post/bc557e1a.html | 6 +- post/bfcdfeaf.html | 6 +- post/c34b451f.html | 6 +- post/d7d0fc76.html | 6 +- post/e09f0428.html | 6 +- post/ee27c07f.html | 6 +- post/f440d00b.html | 6 +- post/f92758d8.html | 6 +- post/fa75f5d7.html | 10 +- post/fe76043.html | 6 +- search.xml | 13 + sitemap.xml | 7 + tags/Bloom-filter/index.html | 6 +- "tags/CAP\345\256\232\347\220\206/index.html" | 6 +- tags/Eureka/index.html | 6 +- tags/GC/index.html | 6 +- tags/Guava/index.html | 6 +- tags/IDEA/index.html | 6 +- "tags/IO\346\250\241\345\236\213/index.html" | 6 +- tags/JDK/index.html | 6 +- tags/JVM/index.html | 6 +- .../Java-\345\216\237\347\220\206/index.html" | 6 +- .../Java-\345\271\266\345\217\221/index.html" | 6 +- tags/Java/index.html | 58 +- tags/Java/page/2/index.html | 58 +- tags/Java/page/3/index.html | 32 +- .../Linux\347\254\224\350\256\260/index.html" | 6 +- tags/List/index.html | 6 +- tags/RabbitMQ/index.html | 6 +- tags/Spring/index.html | 1253 +++++++++++++ tags/String/index.html | 6 +- tags/index.html | 10 +- tags/mockito/index.html | 6 +- tags/test/index.html | 6 +- .../index.html" | 6 +- "tags/\345\217\215\345\260\204/index.html" | 6 +- .../index.html" | 6 +- "tags/\345\267\245\345\205\267/index.html" | 6 +- "tags/\345\271\266\345\217\221/index.html" | 6 +- "tags/\345\274\202\346\255\245/index.html" | 6 +- .../index.html" | 6 +- .../index.html" | 6 +- "tags/\347\274\223\345\255\230/index.html" | 6 +- "tags/\351\207\215\346\236\204/index.html" | 6 +- 131 files changed, 8094 insertions(+), 1187 deletions(-) create mode 100644 archives/2020/10/index.html create mode 100644 categories/Spring/Java/index.html create mode 100644 categories/Spring/index.html create mode 100644 post/558ca0bd.html create mode 100644 tags/Spring/index.html diff --git a/about/index.html b/about/index.html index e5d9541a..25e789b1 100644 --- a/about/index.html +++ b/about/index.html @@ -408,7 +408,7 @@

    - 31 + 32 日志 @@ -419,7 +419,7 @@

    - 31 + 33 分类 @@ -430,7 +430,7 @@

    - 28 + 29 标签 diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html index 85c36519..98dc27d3 100644 --- a/archives/2019/10/index.html +++ b/archives/2019/10/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -545,7 +545,7 @@

    - 31 + 32 日志 @@ -556,7 +556,7 @@

    @@ -567,7 +567,7 @@

    diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html index 9d71bcb2..43ccaf4c 100644 --- a/archives/2019/11/index.html +++ b/archives/2019/11/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -510,7 +510,7 @@

    - 31 + 32 日志 @@ -521,7 +521,7 @@

    @@ -532,7 +532,7 @@

    diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html index 578e54bb..c0165fd5 100644 --- a/archives/2019/12/index.html +++ b/archives/2019/12/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -510,7 +510,7 @@

    - 31 + 32 日志 @@ -521,7 +521,7 @@

    @@ -532,7 +532,7 @@

    diff --git a/archives/2019/index.html b/archives/2019/index.html index c095e26a..565dd679 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -724,7 +724,7 @@

    - 31 + 32 日志 @@ -735,7 +735,7 @@

    @@ -746,7 +746,7 @@

    diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html index cb93e6f0..4da03d49 100644 --- a/archives/2019/page/2/index.html +++ b/archives/2019/page/2/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -479,7 +479,7 @@

    - 31 + 32 日志 @@ -490,7 +490,7 @@

    @@ -501,7 +501,7 @@

    diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html index e19f1fb7..d59713b4 100644 --- a/archives/2020/01/index.html +++ b/archives/2020/01/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -440,7 +440,7 @@

    - 31 + 32 日志 @@ -451,7 +451,7 @@

    @@ -462,7 +462,7 @@

    diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html index c5917293..45fe85d3 100644 --- a/archives/2020/02/index.html +++ b/archives/2020/02/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -405,7 +405,7 @@

    - 31 + 32 日志 @@ -416,7 +416,7 @@

    @@ -427,7 +427,7 @@

    diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index 7194a09a..365ef03c 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -510,7 +510,7 @@

    - 31 + 32 日志 @@ -521,7 +521,7 @@

    @@ -532,7 +532,7 @@

    diff --git a/archives/2020/04/index.html b/archives/2020/04/index.html index adf60188..79023dad 100644 --- a/archives/2020/04/index.html +++ b/archives/2020/04/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -510,7 +510,7 @@

    - 31 + 32 日志 @@ -521,7 +521,7 @@

    @@ -532,7 +532,7 @@

    diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index a2f7b353..d0afe6d2 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -440,7 +440,7 @@

    - 31 + 32 日志 @@ -451,7 +451,7 @@

    @@ -462,7 +462,7 @@

    diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html index 3ec73864..178cc4d4 100644 --- a/archives/2020/06/index.html +++ b/archives/2020/06/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -405,7 +405,7 @@

    - 31 + 32 日志 @@ -416,7 +416,7 @@

    @@ -427,7 +427,7 @@

    diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html index 970cf453..b15bf6b7 100644 --- a/archives/2020/07/index.html +++ b/archives/2020/07/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -405,7 +405,7 @@

    - 31 + 32 日志 @@ -416,7 +416,7 @@

    @@ -427,7 +427,7 @@

    diff --git a/archives/2020/08/index.html b/archives/2020/08/index.html index 659fab34..9e2f5e27 100644 --- a/archives/2020/08/index.html +++ b/archives/2020/08/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -440,7 +440,7 @@

    - 31 + 32 日志 @@ -451,7 +451,7 @@

    @@ -462,7 +462,7 @@

    diff --git a/archives/2020/09/index.html b/archives/2020/09/index.html index 8e098b51..a4591784 100644 --- a/archives/2020/09/index.html +++ b/archives/2020/09/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -405,7 +405,7 @@

    - 31 + 32 日志 @@ -416,7 +416,7 @@

    @@ -427,7 +427,7 @@

    diff --git a/archives/2020/10/index.html b/archives/2020/10/index.html new file mode 100644 index 00000000..6b64d44d --- /dev/null +++ b/archives/2020/10/index.html @@ -0,0 +1,1272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/index.html b/archives/2020/index.html index 51edc251..e7d014f0 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2020

    + + + + + + + + + + + + + + +
    @@ -632,41 +667,6 @@

    - - - - - - - - - - - - - - - @@ -724,7 +724,7 @@

    - 31 + 32 日志 @@ -735,7 +735,7 @@

    @@ -746,7 +746,7 @@

    diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html index b008c840..55079ecf 100644 --- a/archives/2020/page/2/index.html +++ b/archives/2020/page/2/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2020

    + + + + + + + + + + + + + + +
    @@ -654,7 +689,7 @@

    - 31 + 32 日志 @@ -665,7 +700,7 @@

    @@ -676,7 +711,7 @@

    diff --git a/archives/index.html b/archives/index.html index 4bfe24e0..b4e5cc7c 100644 --- a/archives/index.html +++ b/archives/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2020

    + + + + + + + + + + + + + + +
    @@ -632,41 +667,6 @@

    - - - - - - - - - - - - - - - @@ -724,7 +724,7 @@

    - 31 + 32 日志 @@ -735,7 +735,7 @@

    @@ -746,7 +746,7 @@

    diff --git a/archives/page/2/index.html b/archives/page/2/index.html index eb0393df..396a4845 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2020

    + + + + + + + + + + + + + + +
    @@ -637,41 +672,6 @@

    - - - - - - - - - - - - - - - @@ -729,7 +729,7 @@

    - 31 + 32 日志 @@ -740,7 +740,7 @@

    @@ -751,7 +751,7 @@

    diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 9ce4e478..1dc2e418 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2019

    + + + + + + + + + + + + + + +
    @@ -632,41 +667,6 @@

    - - - - - - - - - - - - - - - @@ -724,7 +724,7 @@

    - 31 + 32 日志 @@ -735,7 +735,7 @@

    @@ -746,7 +746,7 @@

    diff --git a/archives/page/4/index.html b/archives/page/4/index.html index a93cdc19..026012f3 100644 --- a/archives/page/4/index.html +++ b/archives/page/4/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 31 篇日志。 继续努力。 + OK! 目前共计 32 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2019

    + + + + + + + + + + + + + + +
    @@ -409,7 +444,7 @@

    - 31 + 32 日志 @@ -420,7 +455,7 @@

    @@ -431,7 +466,7 @@

    diff --git a/atom.xml b/atom.xml index 9f85e4f9..18a909bd 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2020-09-24T15:15:59.031Z + 2020-10-08T07:31:37.322Z https://www.mghio.cn/ @@ -16,6 +16,33 @@ Hexo + + Spring 是如何造出一个 Bean 的 + + https://www.mghio.cn/post/558ca0bd.html + 2020-10-08T07:26:10.000Z + 2020-10-08T07:31:37.322Z + + 前言

    使用 Java 作为第一开发语言的朋友们,相信大家或多或少的都使用过 Spring 这个开发框架,可以说 Spring 框架真是我们 Java 程序员的春天,在 SpringBean 是其中最重要的概念之一,是学习其它高级知识的基础,Bean 本质上其实就是一个被 Spring 框架管理的对象,今天我们来看看 BeanSpring 中是如何被造出来的。

    1. Bean 要如何定义

    假如你有如下这样的一个 Programmer 类,这个程序员类有三个属性: 姓名(name)年龄(age)是否有女朋友(hasGirlFriend)(P.S. 正常情况下 hasGirlFriend 属性应该都是 false),还有一个显示个人资料的方法 showMaterial

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
    * @Author: mghio
    * @Date: 2020-10-05
    * @Description: Programmer.
    */
    public class Programmer {

    private String name;

    private Integer age;

    private Boolean hasGirlFriend;

    public void showMaterial() {
    System.out.println("name: " + name + ", age: " + age + ", hasGirlFriend: " + hasGirlFriend);
    }
    }

    现在请你思考一下,如果让你来设计该如何在一个 Spring 容器中描述这样的一个 Programmer 对象呢?

    无非就是需要如下这些信息:

    1.1 类名

    首先类名肯定是需要的,这样到时候才能通过类名加载到这个类。

    1.2 实例别名

    当我们在一个容器中如果一个类有多个实例或者不想通过一个类名来描述一个实例时,这时通过设置一个别名就可以很方便的描述该实例了。

    1.3 构造函数

    我们知道 Java 中创建一个类的实例首先就会调用该类的构造函数,当有多个构造函数时,需要明确的描述要使用哪个构造函数来创建对象,比如通过传入不同的参数类型来选择不同的构造函数。

    1.4 类的属性设置

    当我们没有在构造函数中传入属性,比如上面的 Programmer 可以直接通过无参构造函数就可以创建出来了,后面如果需要设置实例的属性则需要调用其设置属性的方式来进行设置,所以属性方法也是必要的。

    1.5 初始化方法

    有时候我们需要在一个实例化完成之后做一些我们自定义的业务逻辑,比如想让上面例子中的 Programmer 在实例化完成之后就显示个人资料(调用 showMaterial() 方法),这种场景使用初始化方法就很合适了。

    1.6 销毁方法

    说到销毁,大家可能都会想到和资源有关,比如一个共识就是大家一般都把资源释放类的工作放在 finally 代码块中确保资源可以得到释放,同样当一个 Bean 之后连接使用了某些资源时,当销毁后想要对这些资源进行释放,这时候就可以通过其 销毁方法 来释放资源。

    1.7 作用域

    有些 Bean 可能需要在整个容器中只有一个,也就是单例,而有些可能要求每一次请求对应的 Bean 都不一样,这时可以通过一个 作用域 的概念,来区分不同要求的 Bean,当容器发现这个类是 单例 的,就会复用已存在的 Bean,否则才重新创建。

    当然这里只是列举一些个人觉得比较重要的属性,还有其它的一些属性需要增加。在 Spring 框架中 Bean 的定义是通过一个 BeanDefinition 类来描述的。

    spring-bean-create-1.jpg

    在没有使用 SpringBoot 之前我们都是通过 XML 配置然后 Spring 来解析生成 Bean 的,同时我们也可以通过代码方式使用 BeanDefinitionBuilder 生成 Bean,具体代码如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /**
    * @Author: guihai
    * @Date: 2020-10-05
    * @Description:
    */
    public class ProgrammerTest {

    public static void main(String[] args) {
    new Programmer().showMaterial();

    BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Programmer.class);
    beanDefinitionBuilder.addPropertyValue("name", "mghio");
    beanDefinitionBuilder.addPropertyValue("age", 18);
    beanDefinitionBuilder.addPropertyValue("hasGirlFriend", false);

    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    beanFactory.registerBeanDefinition("programmer", beanDefinitionBuilder.getBeanDefinition());

    Programmer programmer = (Programmer) beanFactory.getBean("programmer");
    programmer.showMaterial();
    }

    }

    运行结果如下:

    spring-bean-create-2.jpg

    在使用 XML 方式时一般是通过调用 ClassPathXmlApplicationContext 来注册 Bean 的,其构造函数可以传入具体的 XMl配置文件的路径,可以是一个或者多个,甚至还可以是通配符。在构造函数内部就会调用熟悉的 refresh 方法了。

    spring-bean-create-3.jpg

    深入 refresh 方法可以发现,在该方法中调用了 obtainFreshBeanFactory 方法来获取生成的 Bean,这个方法实际上是调用了抽象实现类 AbstractRefreshableApplicationContextrefreshBeanFactory 方法,该方法首先会先判断此时是否还有 beanFactory ,如果有的话会先销毁 beanFactory,然后再重新创建一个 BeanFactory(实际上是 DefaultListableBeanFactory 类型),最后会调用 loadBeanDefinitions 加载我们定义的 XMl 配置,方法使用的是 XmlBeanDefinitionReader 来读取的 XMl 配置,下面一起来深入的了解一下 Spring 生成 Bean 的过程。

    2. 创建 Bean 的过程

    首先我们看看 BeanFactory 类图,如下所示:

    spring-bean-create-4.jpg

    Bean 的整体创建流程如下所示:

    spring-create-bean.png

    3. 总结

    本文简要的讲述了 Spring 创建 Bean 的主要流程,还有许多细节的地方需要深入研读源码才能了解,在这里先给自己一个小目标,后续会自己实现一个简易版本的 SpringIOCAOP),预知后事如何,请看下篇博文。。。

    ]]> + + + + <h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>使用 <code>Java</code> 作为第一开发语言的朋友们,相信大家或多或少的都使用过 <code>Spring</code> 这个开发框架,可以说 <code>Spring</code> 框架真是我们 <code>Java</code> 程序员的春天,在 <code>Spring</code> 中 <code>Bean</code> 是其中最重要的概念之一,是学习其它高级知识的基础,<code>Bean</code> 本质上其实就是一个被 <code>Spring</code> 框架管理的对象,今天我们来看看 <code>Bean</code> 在 <code>Spring</code> 中是如何被造出来的。</p> + + + + + + + + + + + + + + + 从 CPU 缓存看缓存的套路 @@ -586,64 +613,4 @@ - - Linux 常用命令 - - https://www.mghio.cn/post/817c7d82.html - 2019-12-21T04:00:49.000Z - 2019-12-21T15:52:44.260Z - - 1.1 前言

    作为 Java 后端开发的我们,开发的项目绝大部分都是部署在 Linux 系统上的,因此熟练使用一些常用的 Linux 命令不管是对于日常开发、服务部署或者查找问题都非常有用。以下整理了一些常用的 Linux 常用命令。

    1.2 文件管理

    1.2.1 ls 命令

    ls 命令是 Linux 最常用的命令之一,其功能是列出指定目录下的内容及其相关属性信息。默认状态下,ls 命令会列出当前目录的内容,它也可以带上一些参数来实现更多的功能。
    语法格式:ls [选项] [文件]
    常用参数

    参数描述
    -a显示所有文件及目录(包括以 . 开头的隐藏文件)
    -l使用长格式列出文件及目录
    -r将文件以相反次序显示(默认按照英文字母次序)
    -t根据最后的修改时间排序
    -A-a,但是不列出 .(当前目录)以及 ..(父级目录)
    -S根据文件大小排序
    -R递归列出所有子目录

    Examples

    1
    2
    3
    4
    5
    ls -a       # 列出所有文件(包括隐藏文件)
    ls -l # 列出文件的详细信息
    ls / # 列出根目录(/)下的所有目录
    ls -ltr s* # 列出当前目录下所有名称是 s 开头的文件
    ls -AS # 列出当前目录下所有文件及目录并以文件大小进行排序
    1.2.2 chown 命令

    Linux 是一种多用户多任务的操作系统,所有的文件都有一个拥有者。chown 命令就是用来将指定文件的拥有者改为指定的用户或者组(PS:用户和组都可以是名称或者其 ID),文件是以空格分开的要改变权限的文件列表,支持通配符。
    语法格式:chown [参数]
    常用参数

    参数描述
    -R对当前目录下的所有文件与子目录进行相同的拥有者变更
    -c若该文件拥有者确实已经更改,才显示其更改动作
    -f若该文件拥有者无法更改也不显示错误信息
    -v显示拥有者变更的详细信息
    –version显示版本

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 将 change_usergroup_and_user_demo.txt 文件用户组与用户都改为 mghio

    [root@mghio ~]# ll change_usergroup_and_user_demo.txt
    -rw-r--r-- 1 root root 56 Dec 21 10:17 change_usergroup_and_user_demo.txt
    [root@mghio ~]# chown mghio:mghio change_usergroup_and_user_demo.txt
    [root@mghio ~]# ll change_usergroup_and_user_demo.txt
    -rw-r--r-- 1 mghio mghio 56 Dec 21 10:17 change_usergroup_and_user_demo.txt


    # 显示其更改动作

    [root@mghio ~]# ll change_usergroup_and_user_demo.txt
    -rw-r--r-- 1 root root 45 Dec 21 10:30 change_usergroup_and_user_demo.txt
    [root@mghio ~]# chown -c mghio:mghio change_usergroup_and_user_demo.txt
    changed ownership of 'change_usergroup_and_user_demo.txt' to mghio:mghio
    1.2.3 cp 命令

    cp 命令为英文单词 copy 的缩写,功能为复制文件或目录。cp 命令可以将多个文件复制到一个具体的文件名或者一个已经存在的目录下,也可以同时复制多个文件到一个指定的目录中。
    语法格式:cp [参数] [文件]
    常用参数

    参数描述
    -f若目标文件已经存在,则直接覆盖原文件
    -i若目标文件已经存在,则会询问是否覆盖
    -p保留原文件或者目录的属性
    -r递归复制文件和目录
    -d当复制符号链接时,把目标文件或者目录也建立符号链接,并指向和原文件或目录连接的原始文件或目录
    -l对原文件建立连接,而非复制文件
    -s对原文件建立符合连接,而非复制文件
    -b覆盖已经存在的文件目标前将目标文件备份
    -v详细显示 cp 命令的执行过程

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    # 复制目录
    cp -R source_dir1 dest_dir2/

    # 将文件 demo1.txt 改名为 demo2.txt
    cp -f demo1.txt demo2.txt

    # 复制多个文件
    cp -r file1 file2 file3 dest_dir
    1.2.4 mkdir 命令

    mkdir 命令是 make directories 的缩写,其功能是用来创建目录。默认状态下,如果要创建的目录如果已经存在,则提示已存在,而不会继续创建目录。所有我们在创建目录时,应该要保证新建的目录与它所在的目录下的文件没有重名,同时该命令还可以一次性创建多个目录。
    语法格式:mkdir [参数] [目录]
    常用参数

    参数描述
    -p递归创建多级目录
    -m建立目录的同时设置目录的权限
    -v显示目录的常见过程

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 在当前目录下,创建一个名为 dir 的子目录
    mkdir dir

    # 在目录 /usr/mghio 下建立子目录 dir,并且设置文件属主有读(4)、写(2)和执行(1)权限,其它用户无法访问
    mkdir -m 700 /usr/mghio/dir

    # 一次性创建目录 dir1、dir2、dir3
    mkdir dir1 dir2 dir3

    # 递归创建目录
    mkdir -p /mghio/dir
    1.2.5 mv 命令

    mv 命令为英文单词 move 的缩写,功能为移动文件或者对文件重新命名。mvcp 命令的结果不同。mv 命令是将文件整个移走,文件名发生改变,但是个数没有增加。而 cp 命令是对文件进行复制操作,文件个数增加。
    语法格式:mv [参数]
    常用参数

    参数描述
    -i若存在同名文件,则会询问是否覆盖
    -f覆盖已经存在的文件时,不进行任何提示
    -b当文件存在时,覆盖前为其创建一个备份
    -u当原文件比目标文件新或者目标文件不存在时,才会执行

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    # 将文件 file1 重命名为 file2
    mv file1 file2

    # 将文件 file 移动到目录 dest_dir
    mv file /dest_dir

    # 将目录 dir 下的所有文件移到当前目录
    mv /dir/* .

    1.3 文档编辑

    1.3.1 cat 命令

    Linux 系统中有很多用于查看文件内容的命令,cat 命令就是用来查看内容较少的纯文本内容文件的。当文件内容较大时,文本内容会在屏幕上快速滚屏,我们通常都看不到所显示的内容。对于较长文件内容可以按 Ctrl+S 键来停止滚屏,以及 Ctrl+Q 键来恢复滚屏,按 Ctrl+C(中断)键则可以终止该命令的执行。对于大文件,推荐使用下文说的 more 命令。
    语法格式:cat [参数] [文件]
    常用参数

    参数描述
    -n显示行数(一个空行显示一个编号)
    -s显示行数(多个空行只算一个编号)
    -b显示行数(空行不编号)
    -E每行结束显示 $ 符号
    -TTAB 字符显示为 ^| 符号
    –version显示版本信息

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 查看文件内容 
    cat demo.txt

    # 查看文件内容,并显示行号
    cat -n demo.txt

    # 产查看文件的内容,并添加行数编号后输出到另外一个文件中
    cat -n mghio.log > mghio_with_line_number.log

    # 清空文件内容
    cat /dev/null > /mghio/demo.txt

    # 持续写入文件内容,直到碰到 `EOF` 符号后结束并保存
    cat > demo.txt << EOF
    > Hello, World
    > mghio
    > EOF
    1.3.2 more 命令

    more 命令用于将内容较长的文本文件内容(无法在一屏显示完)进行分屏显示,并且支持显示时定位关键字。对于内容比较少的文本内容推荐使用 cat 命令查看。
    语法格式:more [参数] [文件]
    常用参数

    参数描述
    -num指定每屏显示的内容行数
    -lmore 在通常情况下把 ^L 当遇到这个字符就会暂停,这个参数可以屏蔽这个特性
    -f计算实际的行数,而非自动换行的行数
    -p先清除屏幕在显示文本文件的剩余内容
    -c-p 相似,不滚屏,先显示内容在清除内容
    -s多个空行压缩成一行显示
    -u禁止下划线
    +/pattern在每个文档显示前搜寻该字(pattern),然后该字串之后开始显示
    +num从第 num 行开始显示

    查看时的命令操作

    命令描述
    Space 键显示文本的下一屏内容
    Enter 键向下 n 行,需要定义,默认为 1 行
    \接着输入一个模式,可以在文本中寻找下一个相匹配的模式
    H 键显示帮助屏
    B 键显示上一屏内容
    Q 键退出 more 命令
    Ctrl + F、空格键向下滚动一屏
    Ctrl + B返回上一屏
    =输出当前的行号
    :f输出文件名和当前的行号
    V调用 vi 编辑器
    !调用 Shell, 并执行命令

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 显示文件 demo.txt 的内容和已显示的百分比,显示之前先清屏
    more -dc demo.txt

    # 显示文件 demo.txt 的内容,每 10 行显示一次,而且在显示之前先清屏
    more -c -10 demo.txt

    # 显示文件 demo.txt 的内容,每 5 行显示一次,而且在显示之后再清屏
    more -p -5 demo.txt

    # 从第 20 行开始显示文件 demo.txt 的内容
    more +20 demo.txt
    1.3.3 tail 命令

    tial 命令用于显示文件尾部的内容,默认在屏幕上显示指定文件的末尾 10 行。如果给定的文件不止一个,则在显示的每个文件前面加一个文件名标题,如果没有指定文件或者文件名为 -,则读取标准输入。
    语法格式:tail [参数]
    常用参数

    命令描述
    –retry即是在 tail 命令启动时,文件不可访问或者文件稍后变得不可访问,都始终尝试打开文件。使用此选项时需要与 —f 一起使用
    -c 输出文件尾部的 NN 为整数) 个字节内容
    -f显示文件最新追加的内容
    -n 输出文件的尾部 NN 为整数) 行内容

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    # 显示文件 demo.txt 的最后 10
    tail demo.txt

    # 显示文件 demo.txt 的内容,从第 20 行至文件末尾
    tail +20 demo.txt

    # 显示文件 demo.txt 的最后 10 个字符
    tail -c 10 demo.txt
    1.3.4 grep 命令

    grep 是英文 global search regular expression and print out the line 的简称。是全面搜索正则表达式,并将其打印出来。这个命令可以结合正则表达式使用,使用非常广泛。grep 命令的选项用于对搜索过程的补充,而其命令的模式十分灵活,可以是变量、字符串、正则表达式,需要注意的是,当我们的模式中包含了空格的话,要使用双引号将其引起来。
    语法格式:grep [参数]
    参数列表

    命令描述
    -i搜索时,忽略大小写
    -c只输出匹配行的数量
    -l只列出符合匹配的文件名,不列出具体匹配行
    -n列出所有匹配行,显示行号
    -h查询多文件时不显示文件名
    -s不显示不存在、没有匹配文本的错误信息
    -v显示不包含匹配文本的所有行
    -w匹配整词
    -x匹配整行
    -r递归搜索
    -q禁止输出任何结果,已退出状态表示搜索是否成功
    -b打印匹配行距文件头部的偏移量(以字节为单位)
    -o-b 结合使用,打印匹配的词距文件头部的偏移量(以字节为单位)

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # 支持多文件查询并支持使用通配符

    [root@mghio ~]# grep mghio file_* /usr/demo
    file_1:mghio
    file_1:mghioddkjflkdjfdlkfjlsdkj
    file_2:mghio
    file_4:dkfjlmghioejfkds
    file_4:mghio djftgf
    file_4:twetmghioedkfgj


    # 列出所有的匹配行,并显示行号
    [root@mghio ~]# grep mghio file_* /usr/demo
    file_1:1:mghio
    file_1:3:mghioddkjflkdjfdlkfjlsdkj
    file_2:4:mghio
    file_4:8:dkfjlmghioejfkds
    file_4:11:mghio djftgf
    file_4:20:twetmghioedkfgj
    1.3.5 echo 命令

    echo 命令用于在终端设备上输出字符串或者变量提取后的值,这是在 Linux 系统中最常用的几个命令之一,在 Linux 系统中,人们一般使用在变量前加上 $ 符号的方式提取出变量的值,例如:$PATH,然后再用 echo 命令予以输出。或者直接使用 echo 命令输出一段字符串到屏幕上,起到给用户提示的作用。
    语法格式:echo [参数] [字符串]
    常用参数

    命令描述
    -n不输出结尾的换行符
    -e”\a”发出警告音
    -e”\b”删除前面的一个字符
    -e”\c”结尾不加换行符
    -e”\f”换行,光标仍然停留在原来的坐标位置
    -e”\n”换行,光标移至行首
    -e”\r”光标移至首行,但是不换行
    -E禁止反斜杠转义,与 -e 参数功能相反

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 输出一段字符串
    [root@mghio ~]# echo "mghio.cn"
    mghio.cn

    # 输出变量提取后的值
    [root@mghio ~]# echo $PATH
    /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

    # 对内容进行转义,不让$符号的提取变量值功能生效
    [root@mghio ~]# echo \$PATH
    $PATH

    # 使用反引号符执行命令,并输出其结果到终端
    [root@mghio ~]# echo `date`
    Sat Dec 21 15:30:24 CST 2019

    1.4 网络通讯

    1.4.1 ssh 命令

    ssh 命令是 openssh 套件中的客户端连接工具,可以给予 ssh 加密协议实现安全的远程登录服务器,实现对服务器的管理。
    语法格式:ssh [参数] [主机]
    常用参数

    命令描述
    -1强制使用 ssh 协议版本 1
    -2强制使用 ssh 协议版本 2
    -4强制使用 IPv4 地址
    -6强制使用 IPv6 地址
    -A开启认证代理连接转发功能
    -a关闭认证代理连接转发功能
    -b<IP地址>使用本机指定的地址作为对位连接的源 IP 地址
    -C请求压缩所有数据
    -F<配置文件>指定 ssh 指令的配置文件,默认的配置文件为 /etc/ssh/ssh_config
    -f后台执行 ssh指令
    -g允许远程主机连接本机的转发端口
    -i<身份文件>指定身份文件(即私钥文件)
    -l<登录名>指定连接远程服务器的登录用户名
    -N不执行远程指令
    -o<选项>指定配置选项
    -p<端口>指定远程服务器上的端口
    -q静默模式,所有的警告和诊断信息被禁止输出

    Examples

    1
    2
    3
    4
    5
    # 登录远程服务器
    [root@mghio ~]# ssh 112.67.239.127

    # 用 mghio 用户连接远程服务器
    [root@linuxcool ~]# ssh -l mghio 112.67.239.127
    1.4.2 sftp 命令

    sftp 命令全称是 Secure File Transfer Protocol。是一个交互式的文件传输程序,sftp 命令的运行和使用与 ftp 相似,但是 sftp 命令对传输的所有信息使用 ssh 加密 ,它还支持公钥认证和压缩等功能。
    语法格式:sftp [参数] [IP或主机名]
    常用参数

    命令描述
    -B指定传输文件缓冲区的大小
    -l使用 ssh 协议版本 1
    -b指定批处理文件
    -C使用压缩
    -o指定 ssh 选项
    -F指定 ssh 配置文件
    -R指定一次可以容忍多少请求数

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    # 使用 sftp 命令连接到服务器
    [root@mghio ~]# sftp 112.67.239.127

    # 指定传输文件是缓冲区大小
    [root@mghio ~]# sftp -B 256 112.67.239.127

    # 在传输过程中使用压缩
    [root@linuxcool ~]# sftp -C 112.67.239.127
    1.4.3 telnet 命令

    telnet 命令的功能是远端登入,执行 telnet 指令开启终端机阶段作业,并登入远端主机。telnet 命令可以帮助你从这台路由器远程登陆到远端开启了 telnet 服务的设备,包括路由器、交换机、Linux 服务器等,并且配置当前路由器的 telnet 服务。
    语法格式:telnet [参数]
    常用参数

    命令描述
    -8允许使用 8 位字符资料,包括输入与输出
    -a尝试自动登入远端系统
    -b使用别名指定远端主机名称
    -c不读取用户专属目录里的 .telnetrc 文件
    -d启动排错模式
    -e设置脱离字符
    -E滤除脱离字符
    -f此参数的效果和指定 -F 参数相同
    -F使用 Kerberos V5 认证时,加上此参数可把本地主机的认证数据上传到远端主机
    -k使用 Kerberos 认证时,加上此参数让远端主机采用指定的领域名,而非该主机的域名
    -K不自动登入远端主机
    -l指定要登入远端主机的用户名称
    -L允许输出8位字符资料
    -n指定文件记录相关信息
    -r使用类似 rlogin 指令的用户界面
    -S设置 telnet 连线所需的 IP TOS 信息
    -x假设主机有支持数据加密的功能,就使用它
    -X关闭指定的认证形态

    Examples

    1
    2
    3
    4
    5
    # 登录远程主机
    [root@mghio ~]# telnet 112.67.239.127

    # 连接本地主机,端口号为 23
    [root@mghio ~]# telnet localhost 23
    1.4.4 netstat 命令

    netstat 命令用于显示各种网络相关信息,如网络连接、路由表、接口状态、多播成员等。从整体上看,netstat 的输出结果为两部分:一个是 Active Internet connections 称为 有源 TCP 连接,其中 Recv-QSend-Q%OA 的是接收队列和发送队列。另一个是 Active UNIX domain sockets,称为有源Unix域套接口(和网络套接字一样,但是只能用于本机通信,性能可以提高一倍)。
    语法格式:netstat [参数]
    常用参数

    命令描述
    -a显示所有连线中的 Socket
    -p显示正在使用 Socket 的程序识别码和程序名称
    -u显示 UDP 传输协议的连线状况
    -i显示网络界面信息表单
    -n直接使用 IP 地址,不通过域名服务器

    Examples

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 显示详细的网络状况
    [root@mghio ~]# netstat -a

    # 显示当前 UDP 连接状况
    [root@mghio ~]# netstat -nu

    # 显示网卡列表
    [root@mghio ~]# netstat -i
    Kernel Interface table
    Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
    eth0 1500 0 181864 0 0 0 141278 0 0 0 BMRU
    lo 16436 0 3362 0 0 0 3362 0 0 0 LRU
    ]]> - - - - <h4 id="1-1-前言"><a href="#1-1-前言" class="headerlink" title="1.1 前言"></a>1.1 前言</h4><p>作为 <code>Java</code> 后端开发的我们,开发的项目绝大部分都是部署在 <code>Linux</code> 系统上的,因此熟练使用一些常用的 <code>Linux</code> 命令不管是对于日常开发、服务部署或者查找问题都非常有用。以下整理了一些常用的 <code>Linux</code> 常用命令。</p> -<h4 id="1-2-文件管理"><a href="#1-2-文件管理" class="headerlink" title="1.2 文件管理"></a>1.2 文件管理</h4><h5 id="1-2-1-ls-命令"><a href="#1-2-1-ls-命令" class="headerlink" title="1.2.1 ls 命令"></a>1.2.1 ls 命令</h5><p><code>ls</code> 命令是 <code>Linux</code> 最常用的命令之一,其功能是列出指定目录下的内容及其相关属性信息。默认状态下,<code>ls</code> 命令会列出当前目录的内容,它也可以带上一些参数来实现更多的功能。<br><strong>语法格式</strong>:ls [选项] [文件]<br><strong>常用参数</strong></p> -<table> -<thead> -<tr> -<th align="center">参数</th> -<th align="center">描述</th> -</tr> -</thead> -<tbody><tr> -<td align="center">-a</td> -<td align="center">显示所有文件及目录(包括以 <code>.</code> 开头的隐藏文件)</td> -</tr> -<tr> -<td align="center">-l</td> -<td align="center">使用长格式列出文件及目录</td> -</tr> -<tr> -<td align="center">-r</td> -<td align="center">将文件以相反次序显示(默认按照英文字母次序)</td> -</tr> -<tr> -<td align="center">-t</td> -<td align="center">根据最后的修改时间排序</td> -</tr> -<tr> -<td align="center">-A</td> -<td align="center">同 <code>-a</code>,但是不列出 <code>.</code>(当前目录)以及 <code>..</code>(父级目录)</td> -</tr> -<tr> -<td align="center">-S</td> -<td align="center">根据文件大小排序</td> -</tr> -<tr> -<td align="center">-R</td> -<td align="center">递归列出所有子目录</td> -</tr> -</tbody></table> - - - - - - - - - - - diff --git a/baidusitemap.xml b/baidusitemap.xml index 6da54f4d..f361a3c2 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -1,6 +1,9 @@ + https://www.mghio.cn/post/558ca0bd.html + 2020-10-08 + https://www.mghio.cn/post/fa75f5d7.html 2020-09-24 diff --git a/categories/JDK/Java/index.html b/categories/JDK/Java/index.html index de9ac3e1..6c1c5f73 100644 --- a/categories/JDK/Java/index.html +++ b/categories/JDK/Java/index.html @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index a7a49663..dd4ed64e 100644 --- "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/JDK/index.html b/categories/JDK/index.html index 33ba5878..01edd1f4 100644 --- a/categories/JDK/index.html +++ b/categories/JDK/index.html @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/Bloom-filter/index.html b/categories/Java/Bloom-filter/index.html index b6ac357d..a70835be 100644 --- a/categories/Java/Bloom-filter/index.html +++ b/categories/Java/Bloom-filter/index.html @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/GC/index.html b/categories/Java/GC/index.html index 9a1e1a39..ba411f3f 100644 --- a/categories/Java/GC/index.html +++ b/categories/Java/GC/index.html @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/Guava/String/index.html b/categories/Java/Guava/String/index.html index 1d4f95ca..fe3e2f0b 100644 --- a/categories/Java/Guava/String/index.html +++ b/categories/Java/Guava/String/index.html @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/Guava/index.html b/categories/Java/Guava/index.html index 0b7ad810..95cec47c 100644 --- a/categories/Java/Guava/index.html +++ b/categories/Java/Guava/index.html @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/IDEA/index.html b/categories/Java/IDEA/index.html index 1af29da5..304ceeb5 100644 --- a/categories/Java/IDEA/index.html +++ b/categories/Java/IDEA/index.html @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" index 0ababdc1..fc72a422 100644 --- "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" +++ "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/IO\346\250\241\345\236\213/index.html" "b/categories/Java/IO\346\250\241\345\236\213/index.html" index 33252416..f052515a 100644 --- "a/categories/Java/IO\346\250\241\345\236\213/index.html" +++ "b/categories/Java/IO\346\250\241\345\236\213/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/JVM/index.html b/categories/Java/JVM/index.html index abb5820a..2a4ed421 100644 --- a/categories/Java/JVM/index.html +++ b/categories/Java/JVM/index.html @@ -413,7 +413,7 @@

    - 31 + 32 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git a/categories/Java/List/index.html b/categories/Java/List/index.html index 5b48666d..37458cd1 100644 --- a/categories/Java/List/index.html +++ b/categories/Java/List/index.html @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/index.html b/categories/Java/index.html index 22063189..957efaba 100644 --- a/categories/Java/index.html +++ b/categories/Java/index.html @@ -625,7 +625,7 @@

    - 31 + 32 日志 @@ -636,7 +636,7 @@

    @@ -647,7 +647,7 @@

    diff --git a/categories/Java/page/2/index.html b/categories/Java/page/2/index.html index 022b5403..58bf8cfb 100644 --- a/categories/Java/page/2/index.html +++ b/categories/Java/page/2/index.html @@ -625,7 +625,7 @@

    - 31 + 32 日志 @@ -636,7 +636,7 @@

    @@ -647,7 +647,7 @@

    diff --git a/categories/Java/page/3/index.html b/categories/Java/page/3/index.html index d7056d51..89b63421 100644 --- a/categories/Java/page/3/index.html +++ b/categories/Java/page/3/index.html @@ -521,7 +521,7 @@

    - 31 + 32 日志 @@ -532,7 +532,7 @@

    @@ -543,7 +543,7 @@

    diff --git a/categories/Java/unit-test/index.html b/categories/Java/unit-test/index.html index 195959a5..606f59ba 100644 --- a/categories/Java/unit-test/index.html +++ b/categories/Java/unit-test/index.html @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/unit-test/mockito/index.html b/categories/Java/unit-test/mockito/index.html index 968e0199..d1e8e0cb 100644 --- a/categories/Java/unit-test/mockito/index.html +++ b/categories/Java/unit-test/mockito/index.html @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\345\216\237\347\220\206/index.html" "b/categories/Java/\345\216\237\347\220\206/index.html" index c6782fc7..8f0e0e34 100644 --- "a/categories/Java/\345\216\237\347\220\206/index.html" +++ "b/categories/Java/\345\216\237\347\220\206/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\345\217\215\345\260\204/index.html" "b/categories/Java/\345\217\215\345\260\204/index.html" index 1e0f76c4..baf67cfa 100644 --- "a/categories/Java/\345\217\215\345\260\204/index.html" +++ "b/categories/Java/\345\217\215\345\260\204/index.html" @@ -413,7 +413,7 @@

    - 31 + 32 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" index 662f5475..b9eb6346 100644 --- "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" @@ -413,7 +413,7 @@

    - 31 + 32 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git "a/categories/Java/\345\271\266\345\217\221/index.html" "b/categories/Java/\345\271\266\345\217\221/index.html" index 5cc37865..b0a603ab 100644 --- "a/categories/Java/\345\271\266\345\217\221/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/index.html" @@ -439,7 +439,7 @@

    - 31 + 32 日志 @@ -450,7 +450,7 @@

    @@ -461,7 +461,7 @@

    diff --git "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" index d37837fc..1f343af1 100644 --- "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\345\274\202\346\255\245/index.html" "b/categories/Java/\345\274\202\346\255\245/index.html" index 9a971d0f..b0a4c145 100644 --- "a/categories/Java/\345\274\202\346\255\245/index.html" +++ "b/categories/Java/\345\274\202\346\255\245/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" index d8e72d2e..d750b8db 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index ba58ae65..5459f3a6 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" index dda3dc00..3f482c7d 100644 --- "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" +++ "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" @@ -413,7 +413,7 @@

    - 31 + 32 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git "a/categories/Java/\347\274\223\345\255\230/index.html" "b/categories/Java/\347\274\223\345\255\230/index.html" index b1c22aff..b405556f 100644 --- "a/categories/Java/\347\274\223\345\255\230/index.html" +++ "b/categories/Java/\347\274\223\345\255\230/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\351\207\215\346\236\204/index.html" "b/categories/Java/\351\207\215\346\236\204/index.html" index 0bfff56e..bbbe1f31 100644 --- "a/categories/Java/\351\207\215\346\236\204/index.html" +++ "b/categories/Java/\351\207\215\346\236\204/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Linux\347\254\224\350\256\260/index.html" "b/categories/Linux\347\254\224\350\256\260/index.html" index f3f10322..1f3fe42a 100644 --- "a/categories/Linux\347\254\224\350\256\260/index.html" +++ "b/categories/Linux\347\254\224\350\256\260/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/RabbitMQ/Java/index.html b/categories/RabbitMQ/Java/index.html index eda1aaed..33c59e75 100644 --- a/categories/RabbitMQ/Java/index.html +++ b/categories/RabbitMQ/Java/index.html @@ -413,7 +413,7 @@

    - 31 + 32 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git a/categories/RabbitMQ/index.html b/categories/RabbitMQ/index.html index 15e96743..4b97d22e 100644 --- a/categories/RabbitMQ/index.html +++ b/categories/RabbitMQ/index.html @@ -413,7 +413,7 @@

    - 31 + 32 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git a/categories/Spring/Java/index.html b/categories/Spring/Java/index.html new file mode 100644 index 00000000..44824e0f --- /dev/null +++ b/categories/Spring/Java/index.html @@ -0,0 +1,1254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: Java | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/Spring/index.html b/categories/Spring/index.html new file mode 100644 index 00000000..4831cff6 --- /dev/null +++ b/categories/Spring/index.html @@ -0,0 +1,1254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: Spring | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/index.html b/categories/index.html index b6a4c739..090e8329 100644 --- a/categories/index.html +++ b/categories/index.html @@ -317,10 +317,10 @@

    @@ -378,7 +378,7 @@

    - 31 + 32 日志 @@ -389,7 +389,7 @@

    @@ -400,7 +400,7 @@

    diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" index 0e556de8..16e27bb6 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 212d3fc9..7980cd95 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -387,7 +387,7 @@

    - 31 + 32 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/css/main.css b/css/main.css index 253c0026..35887419 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #ff6feb; + background: #c99aa4; } .links-of-blogroll { font-size: 13px; diff --git a/index.html b/index.html index 8f908ed3..10065b01 100644 --- a/index.html +++ b/index.html @@ -310,7 +310,7 @@

    Java 搬运工 & 终身学习
    - +

    @@ -456,17 +456,10 @@

    -

    一、前言

    不同存储技术的访问时间差异很大,从 计算机层次结构 可知,通常情况下,从高层往底层走,存储设备变得更慢、更便宜同时体积也会更大,CPU 和内存之间的速度存在着巨大的差异,此时就会想到计算机科学界中一句著名的话:计算机科学的任何一个问题,都可以通过增加一个中间层来解决。

    -

    二、引入缓存层

    为了解决速度不匹配问题,可以通过引入一个缓存中间层来解决问题,但是也会引入一些新的问题。现代计算机系统中,从硬件到操作系统、再到一些应用程序,绝大部分的设计都用到了著名的局部性原理,局部性通常有如下两种不同的形式:

    -
    -

    时间局部性:在一个具有良好的时间局部性的程序当中,被引用过一次的内存位置,在将来一个不久的时间内很可能会被再次引用到。

    -
    -
    -

    空间局部性:在一个具有良好的空间局部性的程序当中,一个内存位置被引用了一次,那么在不久的时间内很可能会引用附近的位置。

    -
    +

    前言

    使用 Java 作为第一开发语言的朋友们,相信大家或多或少的都使用过 Spring 这个开发框架,可以说 Spring 框架真是我们 Java 程序员的春天,在 SpringBean 是其中最重要的概念之一,是学习其它高级知识的基础,Bean 本质上其实就是一个被 Spring 框架管理的对象,今天我们来看看 BeanSpring 中是如何被造出来的。

    - + 阅读全文 »
    @@ -519,7 +512,7 @@

    - +

    -

    +

    @@ -665,12 +658,17 @@

    -

    现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑。

    -

    第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作

    例如我们执行以下代码:

    -
    1
    2
    List<String> strings = Arrays.asList("m", "g");
    strings.add("h");
    +

    一、前言

    不同存储技术的访问时间差异很大,从 计算机层次结构 可知,通常情况下,从高层往底层走,存储设备变得更慢、更便宜同时体积也会更大,CPU 和内存之间的速度存在着巨大的差异,此时就会想到计算机科学界中一句著名的话:计算机科学的任何一个问题,都可以通过增加一个中间层来解决。

    +

    二、引入缓存层

    为了解决速度不匹配问题,可以通过引入一个缓存中间层来解决问题,但是也会引入一些新的问题。现代计算机系统中,从硬件到操作系统、再到一些应用程序,绝大部分的设计都用到了著名的局部性原理,局部性通常有如下两种不同的形式:

    +
    +

    时间局部性:在一个具有良好的时间局部性的程序当中,被引用过一次的内存位置,在将来一个不久的时间内很可能会被再次引用到。

    +
    +
    +

    空间局部性:在一个具有良好的空间局部性的程序当中,一个内存位置被引用了一次,那么在不久的时间内很可能会引用附近的位置。

    +
    - + 阅读全文 »
    @@ -723,7 +721,7 @@

    - +

    @@ -869,11 +867,12 @@

    -

    上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

    -

    消息生产者发送的消息不可达时如何处理

    RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

    +

    现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑。

    +

    第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作

    例如我们执行以下代码:

    +
    1
    2
    List<String> strings = Arrays.asList("m", "g");
    strings.add("h");
    - + 阅读全文 »
    @@ -926,7 +925,7 @@

    - +

    -

    +

    @@ -1072,11 +1071,11 @@

    -

    什么是消息队列(MQ)

    消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

    -

    什么场景下考虑使用消息队列

    从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

    +

    上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

    +

    消息生产者发送的消息不可达时如何处理

    RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

    - + 阅读全文 »
    @@ -1129,7 +1128,7 @@

    - +

    -

    +

    @@ -1286,10 +1274,11 @@

    -

    前言

    Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
    Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

    +

    什么是消息队列(MQ)

    消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

    +

    什么场景下考虑使用消息队列

    从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

    - + 阅读全文 »
    @@ -1342,7 +1331,7 @@

    前言 - +

    @@ -1499,10 +1488,10 @@

    -

    前言

    在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

    +

    前言

    Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
    Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

    - + 阅读全文 »
    @@ -1555,7 +1544,7 @@

    前言 - +

    @@ -1712,10 +1701,10 @@

    -

    前言

    对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

    +

    前言

    在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

    - + 阅读全文 »
    @@ -1768,7 +1757,7 @@

    前言 - +

    @@ -1914,11 +1914,10 @@

    -

    前言

    在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

    -

    同步与异步

    首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

    +

    前言

    对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

    - + 阅读全文 »
    @@ -1971,7 +1970,7 @@

    - +

    -

    +

    @@ -2117,14 +2116,11 @@

    -

    前言

    在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

    -

    原理

    布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

    -
    -

    A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

    -
    +

    前言

    在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

    +

    同步与异步

    首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

    - + 阅读全文 »
    @@ -2177,7 +2173,7 @@

    原理 - +

    @@ -2334,15 +2319,14 @@

    -

    前言

    Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

    -

    如何使用

    Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

    -
    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.2-jre</version>
    </dependency>
    - -

    对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

    -
    1
    compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
    +

    前言

    在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

    +

    原理

    布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

    +
    +

    A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

    +
    - + 阅读全文 »
    @@ -2434,7 +2418,7 @@

    - 31 + 32 日志 @@ -2445,7 +2429,7 @@

    - 31 + 33 分类 @@ -2456,7 +2440,7 @@

    - 28 + 29 标签 diff --git a/page/2/index.html b/page/2/index.html index 914d4037..48aaf23a 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -310,7 +310,7 @@

    Java 搬运工 & 终身学习
    - +

    @@ -456,11 +467,15 @@

    -

    前言

    在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

    -

    什么是 CompletableFuture

    CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

    +

    前言

    Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

    +

    如何使用

    Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

    +
    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.2-jre</version>
    </dependency>
    + +

    对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

    +
    1
    compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
    - + 阅读全文 »
    @@ -513,7 +528,7 @@

    - +

    -

    +

    @@ -659,11 +674,11 @@

    -

    前言

    在日常生活中,当我们买的水果放久了之后会发出一种难闻的气味(“坏味道”),这个时候我们就应该把它扔掉。同样,代码也有“坏味道”,当然确定什么是和不是代码“坏味道”是主观的,它会随语言、开发人员和开发方法的不同而不同。在工作当中,很多时候都是在维护之前的项目和在此基础上增加一些新功能,为了能让项目代码易于理解和维护,要时刻注意代码中的“坏味道”,当发现代码如果有坏味道了,要及时去重构它使其变成优秀的整洁的代码。本文列举代码中一些常见的“坏味道”和相应的重构方案。

    -

    过长方法 (Long Method)

    这种“坏味道”表现为方法代码行数过长,方法行数越长,就越难以理解和维护它。一个比较有用的方案就是当你觉得需要对方法中的内容加注释的时候,你应该将这个代码段作为一个新方法提取出来,哪怕有时候仅仅是一行代码也可以这么做,而且方法的命名要尽量做到见名知意,如果局部变量和参数干扰到方法的提取,则可以使用引入参数对象来进行提取。一般情况下,方法中条件运算符和循环是可以将代码移至单独方法的一个很好的代码段,对于条件运算符,可以尝试分解条件,如果方法出现循环,可以尝试提取方法。

    +

    前言

    在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

    +

    什么是 CompletableFuture

    CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

    - + 阅读全文 »
    @@ -716,7 +731,7 @@

    - +

    -

    +

    @@ -2453,7 +2443,7 @@

    - 28 + 29 标签 diff --git a/page/3/index.html b/page/3/index.html index 1f7e9662..722f3708 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -310,7 +310,7 @@

    Java 搬运工 & 终身学习
    - +

    @@ -456,11 +445,47 @@

    -

    简介

    在上篇 Java 多线程基础(一) 我们提到了一些线程的常用方法,这篇我们具体看看其中一些方法的使用以及方法的区别,让我们在工作中更好的使用。

    -

    wait 方法与 notify 方法

    Object 类中定义了 wait 方法和 notify 方法,wait 方法的作用是让当前线程进入等待状态,将当前线程置入 预执行队列,会在 wait 方法所在代码处停止执行,直到被通知或者被中断,在调用 wait 方法之前,线程必须获取该对象的锁,因此只能在同步方法或者同步代码块中调用 wait 方法,并且该方法会释放当前线程锁持有的锁。notify 方法是唤醒在当前对象上等待的单个线程,如果有多个线程等待,那么线程调度器会挑出一个 wait 的线程,对其发出 notify ,并使它等待获取该对象的对象锁,这意味着,即使收到了通知,线程也不会立即获取到对象锁,必须等待 notify 方法的线程释放锁才可以。和 wait 方法一样,notify 方法也只能在同步方法或者同步代码块中调用。它还有个相似的方法 notifyAll,它的作用是唤醒在当前对象上等待的所有线程

    +

    1.1 前言

    作为 Java 后端开发的我们,开发的项目绝大部分都是部署在 Linux 系统上的,因此熟练使用一些常用的 Linux 命令不管是对于日常开发、服务部署或者查找问题都非常有用。以下整理了一些常用的 Linux 常用命令。

    +

    1.2 文件管理

    1.2.1 ls 命令

    ls 命令是 Linux 最常用的命令之一,其功能是列出指定目录下的内容及其相关属性信息。默认状态下,ls 命令会列出当前目录的内容,它也可以带上一些参数来实现更多的功能。
    语法格式:ls [选项] [文件]
    常用参数

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数描述
    -a显示所有文件及目录(包括以 . 开头的隐藏文件)
    -l使用长格式列出文件及目录
    -r将文件以相反次序显示(默认按照英文字母次序)
    -t根据最后的修改时间排序
    -A-a,但是不列出 .(当前目录)以及 ..(父级目录)
    -S根据文件大小排序
    -R递归列出所有子目录
    - + 阅读全文 »
    @@ -513,7 +538,7 @@

    - +

    -

    +

    @@ -659,12 +684,11 @@

    -

    简介

    在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

    -

    进程与线程的区别

    进程

    进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

    -
    线程

    线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

    +

    简介

    在上篇 Java 多线程基础(一) 我们提到了一些线程的常用方法,这篇我们具体看看其中一些方法的使用以及方法的区别,让我们在工作中更好的使用。

    +

    wait 方法与 notify 方法

    Object 类中定义了 wait 方法和 notify 方法,wait 方法的作用是让当前线程进入等待状态,将当前线程置入 预执行队列,会在 wait 方法所在代码处停止执行,直到被通知或者被中断,在调用 wait 方法之前,线程必须获取该对象的锁,因此只能在同步方法或者同步代码块中调用 wait 方法,并且该方法会释放当前线程锁持有的锁。notify 方法是唤醒在当前对象上等待的单个线程,如果有多个线程等待,那么线程调度器会挑出一个 wait 的线程,对其发出 notify ,并使它等待获取该对象的对象锁,这意味着,即使收到了通知,线程也不会立即获取到对象锁,必须等待 notify 方法的线程释放锁才可以。和 wait 方法一样,notify 方法也只能在同步方法或者同步代码块中调用。它还有个相似的方法 notifyAll,它的作用是唤醒在当前对象上等待的所有线程

    - + 阅读全文 »
    @@ -717,7 +741,7 @@
    线程 - +
    @@ -863,12 +887,12 @@

    -

    简介

    在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

    -

    线程池如何处理提交的任务

    我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
    通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
    }

    public <T> Future<T> submit(Runnable task, T result) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task, result);
    execute(ftask);
    return ftask;
    }

    public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
    }
    +

    简介

    在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

    +

    进程与线程的区别

    进程

    进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

    +
    线程

    线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

    - + 阅读全文 »
    @@ -921,7 +945,7 @@

    - +

    -

    +

    @@ -1067,17 +1091,12 @@

    -

    线程池简介

    使用线程池可以很好的提高性能,线程池在运行之初就会创建一定数量的空闲线程,我们将一个任务提交给线程池,线程池就会使用一个空闲的线程来执行这个任务,该任务执行完后,该线程不会死亡,而是再次变成空闲状态返回线程池,等待下一个任务的到来。在使用线程池时,我们把要执行的任务提交给整个线程池,而不是提交给某个线程,线程池拿到提交的任务后,会在内部寻找是否还有空闲的线程,如果有,就将这个任务提交给某个空闲的线程,虽然一个线程同一时刻只能执行一个任务,但是我们可以向线程池提交多个任务。合理使用线程池有以下几个优点:
    降低资源消耗 多线程运行期间,系统不断的启动和关闭新线程,成本高,会过度消耗系统资源,通过重用存在的线程,减少对象创建、消亡的开销
    提高响应速度 当有任务到达时,任务可以不需要等待线程的创建,可以直接从线程池中取出空闲的线程来执行任务
    方便线程管理 线程对计算机来说是很稀缺的资源,如果让他无限制创建,它不仅消耗系统的资源,还会降低系统的稳定性,我们使用线程池后可以统一进行分配和监控
    谈到线程池就会想到池化技术,核心思想就是把宝贵的资源放到一个池子中,每次要使用都从池子里面取,用完之后又放回池子让别人用。那么线程池在 Java 中是如何实现的呢?

    -

    Java 四种线程池

    在 Java 中 Executors 工具类给我们提供了四种不同使用场景的线程池的创建方法,分别为:

    -
      -
    1. newSingleThreadExecutor 只有一个线程来执行任务,适用于有顺序的任务的应用场景。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,它可以保证任务按照指定顺序(FIFO,LIFO)执行,它还有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为
    2. -
    3. newFixedThreadPool 固定线程数的线程池,只有核心线程,核心线程的即为最大的线程数量,没有非核心线程。每次提交一个任务就创建一个线程,直到达到线程池的最大大小。线程池一旦达到最大值就会保持不变,如果当中的某个线程因为异常而结束,那么线程池会新建一个线程加入到线程池中。它还可以控制线程的最大并发数,超出的线程会在阻塞队列(LinkedBlockingQueue)中等待,同样它也有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为。
    4. -
    5. newCachedThreadPool 创建一个可缓存线程池,最大的线程个数为 2^31 - 1(Integer.MAX_VALUE),可以认为是无限大,若无可回收,则新建线程,如果线程池的大小超出了处理任务所需要的线程,那么就会回收部分空闲(60s 不执行任务)的线程。
    6. -
    7. newScheduledThreadPool 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大(Integer.MAX_VALUE:2^31 - 1),适用于执行周期性的任务。
    8. -
    +

    简介

    在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

    +

    线程池如何处理提交的任务

    我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 nullexecute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Futureget 方法获取任务的返回结果时,才会抛出异常。
    通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
    }

    public <T> Future<T> submit(Runnable task, T result) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task, result);
    execute(ftask);
    return ftask;
    }

    public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
    }
    - + 阅读全文 »
    @@ -1130,7 +1149,7 @@

    - +

    -

    +

    @@ -1276,23 +1295,24 @@

    -

    1.1 前言

    做过 java 开发的朋友们相信都很熟悉 HashMap 这个类,它是一个基于 hashing 原理用于存储 Key-Value 键值对的集合,其中的每一个键也叫做 Entry,这些键分别存储在一个数组当中,系统会根据 hash 方法来计算出 Key-Value 的存储位置,可以通过 key 快速存取 value。
    HashMap 基于 hashing 原理,当我们将一个键值对(Key-Value) 传入 put 方法时,它将调用这个 key 的 hashcode 方法计算出 key 的 hashcode 值,然后根据这个 hashcode 值来定位其存放数组的位置来存储对象(HashMap 使用链表来解决碰撞问题,当其发生碰撞了,对象将会存储在链表的下一个节点中,在链表的每个节点中存储 Entry 对象,在 JDK 1.8+ 中,当链表的节点个数超过一定值时会转为红黑树来进行存储),当通过 get 方法传入一个 key 来获取其对应的值时,也是先通过 key 的 hashcode 方法来定位其存储在数组的位置,然后通过键对象的 eqauls 方法找到对应的 value 值。接下来让我们看看其内部的一些实现细节。(PS:以下代码分析都是基于 JDK 1.8

    -

    1.2 为什么容量始终是 2 的整数次幂

    因为获取 key 在数组中对应的下标是通过 key 的哈希值与数组的长度减一进行与运算来确定的(tab[(n - 1) & hash])。当数组的长度 n 为 2 的整数次幂,这样进行 n - 1 运算后,之前为 1 的位后面全是 1 ,这样就能保证 (n - 1) & hash 后相应位的值既可能是 1 又可能是 0 ,这完全取决于 key 的哈希值,这样就能保证散列的均匀,同时与运算(位运算)效率高。如果数组的长度 n 不是 2 的整数次幂,会造成更多的 hash 冲突。HashMap 提供了如下四个重载的构造方法来满足不同的使用场景:

    +

    线程池简介

    使用线程池可以很好的提高性能,线程池在运行之初就会创建一定数量的空闲线程,我们将一个任务提交给线程池,线程池就会使用一个空闲的线程来执行这个任务,该任务执行完后,该线程不会死亡,而是再次变成空闲状态返回线程池,等待下一个任务的到来。在使用线程池时,我们把要执行的任务提交给整个线程池,而不是提交给某个线程,线程池拿到提交的任务后,会在内部寻找是否还有空闲的线程,如果有,就将这个任务提交给某个空闲的线程,虽然一个线程同一时刻只能执行一个任务,但是我们可以向线程池提交多个任务。合理使用线程池有以下几个优点:
    降低资源消耗 多线程运行期间,系统不断的启动和关闭新线程,成本高,会过度消耗系统资源,通过重用存在的线程,减少对象创建、消亡的开销
    提高响应速度 当有任务到达时,任务可以不需要等待线程的创建,可以直接从线程池中取出空闲的线程来执行任务
    方便线程管理 线程对计算机来说是很稀缺的资源,如果让他无限制创建,它不仅消耗系统的资源,还会降低系统的稳定性,我们使用线程池后可以统一进行分配和监控
    谈到线程池就会想到池化技术,核心思想就是把宝贵的资源放到一个池子中,每次要使用都从池子里面取,用完之后又放回池子让别人用。那么线程池在 Java 中是如何实现的呢?

    +

    Java 四种线程池

    在 Java 中 Executors 工具类给我们提供了四种不同使用场景的线程池的创建方法,分别为:

      -
    1. 无参构造:HashMap(),使用该方法表示全部使用 HashMap 的默认配置参数
    2. -
    3. 指定容量初始值构造:HashMap(int initialCapacity),在初始化 HashMap 时指定其容量大小
    4. -
    5. 指定容量初始值和扩容因子构造:HashMap(int initialCapacity, float loadFactor),使用自定义初始化容量和扩容因子
    6. -
    7. 通过 Map 来构造 HashMap:HashMap(Map<? extends K, ? extends V> m),使用默认的扩容因子,其容量大小有传入的 Map 大小来决定 +
    8. newSingleThreadExecutor 只有一个线程来执行任务,适用于有顺序的任务的应用场景。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,它可以保证任务按照指定顺序(FIFO,LIFO)执行,它还有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为
    9. +
    10. newFixedThreadPool 固定线程数的线程池,只有核心线程,核心线程的即为最大的线程数量,没有非核心线程。每次提交一个任务就创建一个线程,直到达到线程池的最大大小。线程池一旦达到最大值就会保持不变,如果当中的某个线程因为异常而结束,那么线程池会新建一个线程加入到线程池中。它还可以控制线程的最大并发数,超出的线程会在阻塞队列(LinkedBlockingQueue)中等待,同样它也有可以指定线程工厂(ThreadFactory)的重载方法,可以自定义线程的创建行为。
    11. +
    12. newCachedThreadPool 创建一个可缓存线程池,最大的线程个数为 2^31 - 1(Integer.MAX_VALUE),可以认为是无限大,若无可回收,则新建线程,如果线程池的大小超出了处理任务所需要的线程,那么就会回收部分空闲(60s 不执行任务)的线程。
    13. +
    14. newScheduledThreadPool 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大(Integer.MAX_VALUE:2^31 - 1),适用于执行周期性的任务。
    15. +
    - + 阅读全文 »
    - + @@ -1338,7 +1358,7 @@

    - +

    -

    +

    @@ -1484,22 +1504,23 @@

    -

    1.1 前言

    同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程的控制流。在容器中,有些也可以作为同步工具类,其它类型的同步工具类还包括闭锁(Latch)、信号量(Semaphore)以及栅栏(Barrier)。阻塞队列(eg: BlockQueue)是一种独特的类:它们不仅能作为保存对象的容器,还能协调生产者和消费者之间的控制流,因为它提供的 takeput 等方法将会阻塞,直到队列达到期望的状态。所有的同步工具类都包含一些特定的属性:它们封装了一些状态,这些状态将决定同步工具类的线程是继续执行还是等待,此外还提供了一些方法对其状态进行操作,以及另一些方法用于高效地等待同步工具类进入到预期状态。

    -

    1.2 闭锁

    闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态。闭锁的作用相当于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开并允许所有线程通过。当闭锁到达结束状态后,将不会再次改变状态,因此这扇门将永远保持打开状态。闭锁可以用来确保某些活动直到其它活动都完成后才继续执行。比如:

    -
      -
    • 确保某个计算机在其需要的所有资源初始化后才能继续执行。
    • -
    • 确保某个服务在其依赖的所有服务都已经启动后才启动。
    • -
    • 等待直到某个操作的所有参与者都就绪后再继续执行。 +

      1.1 前言

      做过 java 开发的朋友们相信都很熟悉 HashMap 这个类,它是一个基于 hashing 原理用于存储 Key-Value 键值对的集合,其中的每一个键也叫做 Entry,这些键分别存储在一个数组当中,系统会根据 hash 方法来计算出 Key-Value 的存储位置,可以通过 key 快速存取 value。
      HashMap 基于 hashing 原理,当我们将一个键值对(Key-Value) 传入 put 方法时,它将调用这个 key 的 hashcode 方法计算出 key 的 hashcode 值,然后根据这个 hashcode 值来定位其存放数组的位置来存储对象(HashMap 使用链表来解决碰撞问题,当其发生碰撞了,对象将会存储在链表的下一个节点中,在链表的每个节点中存储 Entry 对象,在 JDK 1.8+ 中,当链表的节点个数超过一定值时会转为红黑树来进行存储),当通过 get 方法传入一个 key 来获取其对应的值时,也是先通过 key 的 hashcode 方法来定位其存储在数组的位置,然后通过键对象的 eqauls 方法找到对应的 value 值。接下来让我们看看其内部的一些实现细节。(PS:以下代码分析都是基于 JDK 1.8

      +

      1.2 为什么容量始终是 2 的整数次幂

      因为获取 key 在数组中对应的下标是通过 key 的哈希值与数组的长度减一进行与运算来确定的(tab[(n - 1) & hash])。当数组的长度 n 为 2 的整数次幂,这样进行 n - 1 运算后,之前为 1 的位后面全是 1 ,这样就能保证 (n - 1) & hash 后相应位的值既可能是 1 又可能是 0 ,这完全取决于 key 的哈希值,这样就能保证散列的均匀,同时与运算(位运算)效率高。如果数组的长度 n 不是 2 的整数次幂,会造成更多的 hash 冲突。HashMap 提供了如下四个重载的构造方法来满足不同的使用场景:

      +
        +
      1. 无参构造:HashMap(),使用该方法表示全部使用 HashMap 的默认配置参数
      2. +
      3. 指定容量初始值构造:HashMap(int initialCapacity),在初始化 HashMap 时指定其容量大小
      4. +
      5. 指定容量初始值和扩容因子构造:HashMap(int initialCapacity, float loadFactor),使用自定义初始化容量和扩容因子
      6. +
      7. 通过 Map 来构造 HashMap:HashMap(Map<? extends K, ? extends V> m),使用默认的扩容因子,其容量大小有传入的 Map 大小来决定
        - + 阅读全文 »
        -
    + @@ -1545,7 +1566,7 @@

    - +

    -

    +

    @@ -1691,48 +1712,22 @@

    -

    1.1 为什么要进行内存区域划分

    JVM规范 规定,JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途。以及创建和销毁的时间,有的区域随着虚拟机进程的启动就存在了,而有些区域则依赖用户线程的启动和结束而建立和销毁。JVM 规范对 JVM 定义了运行时统一的内存划分规范,统一了标准,类似于 JDBC 规范一样。JVM 也有许多厂商的不同产品。比如下面的这些:

    - - - - - - - - - - - - - - - - - - - - - - - -
    厂商JVM
    Oracle-SUNHotspot
    OracleJRocket
    IBMJ9 JVM
    阿里Taobao JVM
    -

    其内存区域划分规范对于 JVM 的含义类似于我们 Java 中的接口,都是起到了规范的作用,JVM 是一台可以运行 Java 应用程序的抽象的计算机。在 JVM 中存在三个重要的概念:

    +

    1.1 前言

    同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程的控制流。在容器中,有些也可以作为同步工具类,其它类型的同步工具类还包括闭锁(Latch)、信号量(Semaphore)以及栅栏(Barrier)。阻塞队列(eg: BlockQueue)是一种独特的类:它们不仅能作为保存对象的容器,还能协调生产者和消费者之间的控制流,因为它提供的 takeput 等方法将会阻塞,直到队列达到期望的状态。所有的同步工具类都包含一些特定的属性:它们封装了一些状态,这些状态将决定同步工具类的线程是继续执行还是等待,此外还提供了一些方法对其状态进行操作,以及另一些方法用于高效地等待同步工具类进入到预期状态。

    +

    1.2 闭锁

    闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态。闭锁的作用相当于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开并允许所有线程通过。当闭锁到达结束状态后,将不会再次改变状态,因此这扇门将永远保持打开状态。闭锁可以用来确保某些活动直到其它活动都完成后才继续执行。比如:

      -
    • JVM 规范:它定义了虚拟机运行的规范,但是由 Oracle(SUN)或者其它厂商实现
    • -
    • Java 运行时环境(JRE:Java Runtime Environment):它是 JVM 规范的具体实现
    • -
    • JVM 实例:编写好 Java 代码之后,运行 Java 程序,此时就会创建 JMV 实例
    • -
    -

    对于 Java 程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每一个对象去编写内存释放的代码,不要像 C 或者 C++ 要时刻注意着内存泄漏和内存溢出的问题,这种由虚拟机去管理一切看起来都很美好。不过,也正是因为 Java 设计者把内存控制全部交给了 JVM,一旦出现了内存泄漏和溢出方面的问题,如果不了解虚拟机是怎么分配运行时内存的,那么排查错误将是一项非常艰难的工作。

    +
  • 确保某个计算机在其需要的所有资源初始化后才能继续执行。
  • +
  • 确保某个服务在其依赖的所有服务都已经启动后才启动。
  • +
  • 等待直到某个操作的所有参与者都就绪后再继续执行。
    - + 阅读全文 »
    -
  • + @@ -1778,7 +1773,7 @@

    - +

    -

    +

    @@ -1924,12 +1919,41 @@

    -

    1.1 什么是 ThreadLocal

    ThreadLocal 简单理解 Thread 即线程,Local 即本地,结合起来理解就是 每个线程都是本地独有的。在早期的计算机中不包含操作系统,从头到尾只执行一个程序,并且这个程序能访问计算中的所有资源,这对于计算机资源来说是一种浪费。要想充分发挥多处理器的强大计算能力,最简单的方式就是使用多线程。与串行程序相比,在并发程序中存在更多容易出错的地方。当访问共享数据时,通常需要使用同步来控制并发程序的访问。一种避免使用同步的方式就是让这部分共享数据变成不共享的,试想一下,如果只是在单个线程内对数据进行访问,那么就可以不用同步了,这种技术称为线程封闭(Thread Confinement),它是实现线程安全最简单的方式之一。
    当某个对象封闭在一个单个线程中时,这种用法会自动实现了线程安全,因为只有一个线程访问数据,从根本上避免了共享数据的线程安全问题,即使被封闭的对象本身不是线程安全的。要保证线程安全,并不是一定就需要同步,两者没有因果关系,同步只是保证共享数据征用时正确性的手段,如果一个方法本来就不涉及共享数据,那它就不需要任何同步措施去保证正确性。而维持线程封闭的一种规范用法就是使用 ThreadLoal,这个类能使当前线程中的某个值与保存的值关联起来。ThreadLocal 提供了 get()set(T value) 等方法,set 方法为每个使用了该变量的线程都存有一份独立的副本,因此当我们调用 get 方法时总是返回由当前线程在调用 set 方法的时候设置的最新值。

    -

    1.2 ThreadLocal 的用法

    接下来通过一个示例代码说明 ThreadLocal 的使用方式,该示例使用了三个不同的线程 Main ThreadThread-1Thread-2 分别对同一个 ThreadLocal 对象中存储副本。

    -
    1
    2
    3
    4
    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
    30
    31
    /**
    * @author mghio
    * @date: 2019-10-20
    * @version: 1.0
    * @description: Java 并发之 ThreadLocal
    * @since JDK 1.8
    */
    public class ThreadLocalDemoTests {
    private ThreadLocal<String> boolThreadLocal = ThreadLocal.withInitial(() -> "");

    @Test
    public void testUseCase() {
    boolThreadLocal.set("main-thread-set");
    System.out.printf("Main Thread: %s\n", boolThreadLocal.get());

    new Thread("Thread-1") {
    @Override
    public void run() {
    boolThreadLocal.set("thread-1-set");
    System.out.printf("Thread-1: %s\n", boolThreadLocal.get());
    }
    }.start();

    new Thread("Thread-2") {
    @Override
    public void run() {
    System.out.printf("Thread-2: %s\n", boolThreadLocal.get());
    }
    }.start();
    }
    }
    +

    1.1 为什么要进行内存区域划分

    JVM规范 规定,JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途。以及创建和销毁的时间,有的区域随着虚拟机进程的启动就存在了,而有些区域则依赖用户线程的启动和结束而建立和销毁。JVM 规范对 JVM 定义了运行时统一的内存划分规范,统一了标准,类似于 JDBC 规范一样。JVM 也有许多厂商的不同产品。比如下面的这些:

    + + + + + + + + + + + + + + + + + + + + + + + +
    厂商JVM
    Oracle-SUNHotspot
    OracleJRocket
    IBMJ9 JVM
    阿里Taobao JVM
    +

    其内存区域划分规范对于 JVM 的含义类似于我们 Java 中的接口,都是起到了规范的作用,JVM 是一台可以运行 Java 应用程序的抽象的计算机。在 JVM 中存在三个重要的概念:

    +
      +
    • JVM 规范:它定义了虚拟机运行的规范,但是由 Oracle(SUN)或者其它厂商实现
    • +
    • Java 运行时环境(JRE:Java Runtime Environment):它是 JVM 规范的具体实现
    • +
    • JVM 实例:编写好 Java 代码之后,运行 Java 程序,此时就会创建 JMV 实例
    • +
    +

    对于 Java 程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每一个对象去编写内存释放的代码,不要像 C 或者 C++ 要时刻注意着内存泄漏和内存溢出的问题,这种由虚拟机去管理一切看起来都很美好。不过,也正是因为 Java 设计者把内存控制全部交给了 JVM,一旦出现了内存泄漏和溢出方面的问题,如果不了解虚拟机是怎么分配运行时内存的,那么排查错误将是一项非常艰难的工作。

    - + 阅读全文 »
    @@ -1982,7 +2006,7 @@

    - +

    -

    +

    @@ -2117,12 +2152,12 @@

    -

    1.1 split 的坑

    前几天在公司对通过 FTP 方式上传的数据文件按照事先规定的格式进行解析后入库,代码的大概实现思路是这样的:先使用流进行文件读取,对文件的每一行数据解析封装成一个个对象,然后进行入库操作。本以为很简单的一个操作,然后写完代码后自己测试发现对文件的每一行进行字符串分割的时候存在问题,在这里做个简单的记录总结。在 Java 中使用 split 方法对字符串进行分割是经常使用的方法,经常在一些文本处理、字符串分割的逻辑中,需要按照一定的分隔符进行分割拆解。这样的功能,大多数情况下我们都会使用 String 中的 split 方法。关于这个方法,稍不注意很容易踩坑。

    -

    (1)split 的参数是正则表达式
    首先一个常见的问题,就是忘记了 String 的 split 方法的参数不是普通的字符串,而是正则表达式,例如下面的这两种使用方式都达不到我们的预期:

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * @author mghio
    * @date: 2019-10-13
    * @version: 1.0
    * @description: Java 字符串 split 踩坑记
    * @since JDK 1.8
    */
    public class JavaStringSplitTests {

    @Test
    public void testStringSplitRegexArg() {
    System.out.println(Arrays.toString("m.g.h.i.o".split(".")));
    System.out.println(Arrays.toString("m|g|h|i|o".split("|")));
    }

    }
    +

    1.1 什么是 ThreadLocal

    ThreadLocal 简单理解 Thread 即线程,Local 即本地,结合起来理解就是 每个线程都是本地独有的。在早期的计算机中不包含操作系统,从头到尾只执行一个程序,并且这个程序能访问计算中的所有资源,这对于计算机资源来说是一种浪费。要想充分发挥多处理器的强大计算能力,最简单的方式就是使用多线程。与串行程序相比,在并发程序中存在更多容易出错的地方。当访问共享数据时,通常需要使用同步来控制并发程序的访问。一种避免使用同步的方式就是让这部分共享数据变成不共享的,试想一下,如果只是在单个线程内对数据进行访问,那么就可以不用同步了,这种技术称为线程封闭(Thread Confinement),它是实现线程安全最简单的方式之一。
    当某个对象封闭在一个单个线程中时,这种用法会自动实现了线程安全,因为只有一个线程访问数据,从根本上避免了共享数据的线程安全问题,即使被封闭的对象本身不是线程安全的。要保证线程安全,并不是一定就需要同步,两者没有因果关系,同步只是保证共享数据征用时正确性的手段,如果一个方法本来就不涉及共享数据,那它就不需要任何同步措施去保证正确性。而维持线程封闭的一种规范用法就是使用 ThreadLoal,这个类能使当前线程中的某个值与保存的值关联起来。ThreadLocal 提供了 get()set(T value) 等方法,set 方法为每个使用了该变量的线程都存有一份独立的副本,因此当我们调用 get 方法时总是返回由当前线程在调用 set 方法的时候设置的最新值。

    +

    1.2 ThreadLocal 的用法

    接下来通过一个示例代码说明 ThreadLocal 的使用方式,该示例使用了三个不同的线程 Main ThreadThread-1Thread-2 分别对同一个 ThreadLocal 对象中存储副本。

    +
    1
    2
    3
    4
    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
    30
    31
    /**
    * @author mghio
    * @date: 2019-10-20
    * @version: 1.0
    * @description: Java 并发之 ThreadLocal
    * @since JDK 1.8
    */
    public class ThreadLocalDemoTests {
    private ThreadLocal<String> boolThreadLocal = ThreadLocal.withInitial(() -> "");

    @Test
    public void testUseCase() {
    boolThreadLocal.set("main-thread-set");
    System.out.printf("Main Thread: %s\n", boolThreadLocal.get());

    new Thread("Thread-1") {
    @Override
    public void run() {
    boolThreadLocal.set("thread-1-set");
    System.out.printf("Thread-1: %s\n", boolThreadLocal.get());
    }
    }.start();

    new Thread("Thread-2") {
    @Override
    public void run() {
    System.out.printf("Thread-2: %s\n", boolThreadLocal.get());
    }
    }.start();
    }
    }
    - + 阅读全文 »
    @@ -2175,7 +2210,7 @@

    - +

    -

    +

    @@ -2310,10 +2345,12 @@

    -

    1.1 什么是字节码?

    Java 在刚刚诞生之时曾经提出过一个非常著名的口号: “一次编写,到处运行(write once,run anywhere)”,这句话充分表达了软件开发人员对冲破平台界限的渴求。“与平台无关”的理想最终实现在操作系统的运用层上: 虚拟机提供商开发了许多可以运行在不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码,从而实现了程序的“一次编写到处运行”。

    各种不同平台的虚拟机与所有平台都统一使用的程序存储格式—字节码(ByteCode),因此,可以看出字节码对 Java 生态的重要性。之所以被称为字节码,是因为字节码是由十六进制组成的,而 JVM(Java Virtual Machine)以两个十六进制为一组,即以字节为单位进行读取。在 Java 中使用 javac 命令把源代码编译成字节码文件,一个 .java 源文件从编译成 .class 字节码文件的示例如图 1 所示:
    图1

    图 1

    +

    1.1 split 的坑

    前几天在公司对通过 FTP 方式上传的数据文件按照事先规定的格式进行解析后入库,代码的大概实现思路是这样的:先使用流进行文件读取,对文件的每一行数据解析封装成一个个对象,然后进行入库操作。本以为很简单的一个操作,然后写完代码后自己测试发现对文件的每一行进行字符串分割的时候存在问题,在这里做个简单的记录总结。在 Java 中使用 split 方法对字符串进行分割是经常使用的方法,经常在一些文本处理、字符串分割的逻辑中,需要按照一定的分隔符进行分割拆解。这样的功能,大多数情况下我们都会使用 String 中的 split 方法。关于这个方法,稍不注意很容易踩坑。

    +

    (1)split 的参数是正则表达式
    首先一个常见的问题,就是忘记了 String 的 split 方法的参数不是普通的字符串,而是正则表达式,例如下面的这两种使用方式都达不到我们的预期:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * @author mghio
    * @date: 2019-10-13
    * @version: 1.0
    * @description: Java 字符串 split 踩坑记
    * @since JDK 1.8
    */
    public class JavaStringSplitTests {

    @Test
    public void testStringSplitRegexArg() {
    System.out.println(Arrays.toString("m.g.h.i.o".split(".")));
    System.out.println(Arrays.toString("m|g|h|i|o".split("|")));
    }

    }
    - + 阅读全文 »
    @@ -2405,7 +2442,7 @@

    - 31 + 32 日志 @@ -2416,7 +2453,7 @@

    - 31 + 33 分类 @@ -2427,7 +2464,7 @@

    - 28 + 29 标签 diff --git a/page/4/index.html b/page/4/index.html index cba93a32..b538adcf 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -305,6 +305,197 @@

    Java 搬运工 & 终身学习 +
    + + + +
    + + + + + + + +
    + + + +

    + +

    + + + +
    + + + + + +
    + + + + + + +

    1.1 什么是字节码?

    Java 在刚刚诞生之时曾经提出过一个非常著名的口号: “一次编写,到处运行(write once,run anywhere)”,这句话充分表达了软件开发人员对冲破平台界限的渴求。“与平台无关”的理想最终实现在操作系统的运用层上: 虚拟机提供商开发了许多可以运行在不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码,从而实现了程序的“一次编写到处运行”。

    各种不同平台的虚拟机与所有平台都统一使用的程序存储格式—字节码(ByteCode),因此,可以看出字节码对 Java 生态的重要性。之所以被称为字节码,是因为字节码是由十六进制组成的,而 JVM(Java Virtual Machine)以两个十六进制为一组,即以字节为单位进行读取。在 Java 中使用 javac 命令把源代码编译成字节码文件,一个 .java 源文件从编译成 .class 字节码文件的示例如图 1 所示:
    图1

    图 1

    + +
    + + 阅读全文 » + +
    + + + +
    + + + + + + + + + + + + +
    + + + + + + + + +
    + +
    +
    + + + +
    + + + + + + + + + + +
    @@ -540,7 +731,7 @@

    - 31 + 32 日志 @@ -551,7 +742,7 @@

    @@ -562,7 +753,7 @@

    diff --git a/post/102cd3d9.html b/post/102cd3d9.html index 2fe0bc5f..a8bb8bb4 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -847,7 +847,7 @@

    总结 - 31 + 32 日志 @@ -858,7 +858,7 @@

    总结 - 31 + 33 分类 @@ -869,7 +869,7 @@

    总结 - 28 + 29 标签 diff --git a/post/11cb7677.html b/post/11cb7677.html index 8082e6bf..3ae04fcc 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -698,7 +698,7 @@

    总结 - 31 + 32 日志 @@ -709,7 +709,7 @@

    总结 - 31 + 33 分类 @@ -720,7 +720,7 @@

    总结 - 28 + 29 标签 diff --git a/post/192cb539.html b/post/192cb539.html index c4ea72c6..7c0ad484 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -762,7 +762,7 @@

    - 31 + 32 日志 @@ -773,7 +773,7 @@

    @@ -784,7 +784,7 @@

    diff --git a/post/24042edf.html b/post/24042edf.html index 62407fc1..e861fd36 100644 --- a/post/24042edf.html +++ b/post/24042edf.html @@ -770,7 +770,7 @@

    总结 - 31 + 32 日志 @@ -781,7 +781,7 @@

    总结 - 31 + 33 分类 @@ -792,7 +792,7 @@

    总结 - 28 + 29 标签 diff --git a/post/34755d6c.html b/post/34755d6c.html index 3b00aa4f..a026ae59 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -677,7 +677,7 @@

    总结 - 31 + 32 日志 @@ -688,7 +688,7 @@

    总结 - 31 + 33 分类 @@ -699,7 +699,7 @@

    总结 - 28 + 29 标签 diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index 1da1293e..c90abf60 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -744,7 +744,7 @@

    总结 - 31 + 32 日志 @@ -755,7 +755,7 @@

    总结 - 31 + 33 分类 @@ -766,7 +766,7 @@

    总结 - 28 + 29 标签 diff --git a/post/4615256d.html b/post/4615256d.html index 68d1c2f3..6efe4677 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -753,7 +753,7 @@

    - 31 + 32 日志 @@ -764,7 +764,7 @@

    - 31 + 33 分类 @@ -775,7 +775,7 @@

    - 28 + 29 标签 diff --git a/post/4b00e13c.html b/post/4b00e13c.html index a29385db..1359e277 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -852,7 +852,7 @@

    总结 - 31 + 32 日志 @@ -863,7 +863,7 @@

    总结 - 31 + 33 分类 @@ -874,7 +874,7 @@

    总结 - 28 + 29 标签 diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index b17b2727..4e547c17 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -685,7 +685,7 @@

    总结 - 31 + 32 日志 @@ -696,7 +696,7 @@

    总结 - 31 + 33 分类 @@ -707,7 +707,7 @@

    总结 - 28 + 29 标签 diff --git a/post/51e5bd99.html b/post/51e5bd99.html index 93ee3cba..5edf9fa5 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -726,7 +726,7 @@

    - 31 + 32 日志 @@ -737,7 +737,7 @@

    - 31 + 33 分类 @@ -748,7 +748,7 @@

    - 28 + 29 标签 diff --git a/post/558ca0bd.html b/post/558ca0bd.html new file mode 100644 index 00000000..f7313418 --- /dev/null +++ b/post/558ca0bd.html @@ -0,0 +1,1582 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Spring 是如何造出一个 Bean 的 | mghio + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    +
    +
    +
    + + +
    + + + + + + + + +
    + + + +
    + + + + + + + +
    + + + +

    Spring 是如何造出一个 Bean 的

    + + + +
    + + + + + +
    + + + + + +

    前言

    使用 Java 作为第一开发语言的朋友们,相信大家或多或少的都使用过 Spring 这个开发框架,可以说 Spring 框架真是我们 Java 程序员的春天,在 SpringBean 是其中最重要的概念之一,是学习其它高级知识的基础,Bean 本质上其实就是一个被 Spring 框架管理的对象,今天我们来看看 BeanSpring 中是如何被造出来的。

    + + +

    1. Bean 要如何定义

    假如你有如下这样的一个 Programmer 类,这个程序员类有三个属性: 姓名(name)年龄(age)是否有女朋友(hasGirlFriend)(P.S. 正常情况下 hasGirlFriend 属性应该都是 false),还有一个显示个人资料的方法 showMaterial

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
    * @Author: mghio
    * @Date: 2020-10-05
    * @Description: Programmer.
    */
    public class Programmer {

    private String name;

    private Integer age;

    private Boolean hasGirlFriend;

    public void showMaterial() {
    System.out.println("name: " + name + ", age: " + age + ", hasGirlFriend: " + hasGirlFriend);
    }
    }
    + +

    现在请你思考一下,如果让你来设计该如何在一个 Spring 容器中描述这样的一个 Programmer 对象呢?

    +

    无非就是需要如下这些信息:

    +
    1.1 类名

    首先类名肯定是需要的,这样到时候才能通过类名加载到这个类。

    +
    1.2 实例别名

    当我们在一个容器中如果一个类有多个实例或者不想通过一个类名来描述一个实例时,这时通过设置一个别名就可以很方便的描述该实例了。

    +
    1.3 构造函数

    我们知道 Java 中创建一个类的实例首先就会调用该类的构造函数,当有多个构造函数时,需要明确的描述要使用哪个构造函数来创建对象,比如通过传入不同的参数类型来选择不同的构造函数。

    +
    1.4 类的属性设置

    当我们没有在构造函数中传入属性,比如上面的 Programmer 可以直接通过无参构造函数就可以创建出来了,后面如果需要设置实例的属性则需要调用其设置属性的方式来进行设置,所以属性方法也是必要的。

    +
    1.5 初始化方法

    有时候我们需要在一个实例化完成之后做一些我们自定义的业务逻辑,比如想让上面例子中的 Programmer 在实例化完成之后就显示个人资料(调用 showMaterial() 方法),这种场景使用初始化方法就很合适了。

    +
    1.6 销毁方法

    说到销毁,大家可能都会想到和资源有关,比如一个共识就是大家一般都把资源释放类的工作放在 finally 代码块中确保资源可以得到释放,同样当一个 Bean 之后连接使用了某些资源时,当销毁后想要对这些资源进行释放,这时候就可以通过其 销毁方法 来释放资源。

    +
    1.7 作用域

    有些 Bean 可能需要在整个容器中只有一个,也就是单例,而有些可能要求每一次请求对应的 Bean 都不一样,这时可以通过一个 作用域 的概念,来区分不同要求的 Bean,当容器发现这个类是 单例 的,就会复用已存在的 Bean,否则才重新创建。

    +

    当然这里只是列举一些个人觉得比较重要的属性,还有其它的一些属性需要增加。在 Spring 框架中 Bean 的定义是通过一个 BeanDefinition 类来描述的。

    +

    spring-bean-create-1.jpg

    +

    在没有使用 SpringBoot 之前我们都是通过 XML 配置然后 Spring 来解析生成 Bean 的,同时我们也可以通过代码方式使用 BeanDefinitionBuilder 生成 Bean,具体代码如下所示:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /**
    * @Author: guihai
    * @Date: 2020-10-05
    * @Description:
    */
    public class ProgrammerTest {

    public static void main(String[] args) {
    new Programmer().showMaterial();

    BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Programmer.class);
    beanDefinitionBuilder.addPropertyValue("name", "mghio");
    beanDefinitionBuilder.addPropertyValue("age", 18);
    beanDefinitionBuilder.addPropertyValue("hasGirlFriend", false);

    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    beanFactory.registerBeanDefinition("programmer", beanDefinitionBuilder.getBeanDefinition());

    Programmer programmer = (Programmer) beanFactory.getBean("programmer");
    programmer.showMaterial();
    }

    }
    + +

    运行结果如下:

    +

    spring-bean-create-2.jpg

    +

    在使用 XML 方式时一般是通过调用 ClassPathXmlApplicationContext 来注册 Bean 的,其构造函数可以传入具体的 XMl配置文件的路径,可以是一个或者多个,甚至还可以是通配符。在构造函数内部就会调用熟悉的 refresh 方法了。

    +

    spring-bean-create-3.jpg

    +

    深入 refresh 方法可以发现,在该方法中调用了 obtainFreshBeanFactory 方法来获取生成的 Bean,这个方法实际上是调用了抽象实现类 AbstractRefreshableApplicationContextrefreshBeanFactory 方法,该方法首先会先判断此时是否还有 beanFactory ,如果有的话会先销毁 beanFactory,然后再重新创建一个 BeanFactory(实际上是 DefaultListableBeanFactory 类型),最后会调用 loadBeanDefinitions 加载我们定义的 XMl 配置,方法使用的是 XmlBeanDefinitionReader 来读取的 XMl 配置,下面一起来深入的了解一下 Spring 生成 Bean 的过程。

    +

    2. 创建 Bean 的过程

    首先我们看看 BeanFactory 类图,如下所示:

    +

    spring-bean-create-4.jpg

    +

    Bean 的整体创建流程如下所示:

    +

    spring-create-bean.png

    +

    3. 总结

    本文简要的讲述了 Spring 创建 Bean 的主要流程,还有许多细节的地方需要深入研读源码才能了解,在这里先给自己一个小目标,后续会自己实现一个简易版本的 SpringIOCAOP),预知后事如何,请看下篇博文。。。

    + + +
    + + + + + +
    +
    -------------本文结束感谢您的阅读-------------
    +
    + + + +
    +
    + mghio wechat +
    微信公众号「mghio」
    +
    + +
    + + + +
    +
    +
    请我吃🍗
    + + +
    + +
    + + + +
    + +
    + + + +
    + + + +
    + + + +
    + +
    +
    + + +
    + + + + + + +
    +
    + +
    +
    + + + + + +
    + + + + + + + + + +
    +
    + +
    + +
    + + +
    + + +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/post/710bd10b.html b/post/710bd10b.html index 2e44a4bb..1dbab620 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -732,7 +732,7 @@

    总结 - 31 + 32 日志 @@ -743,7 +743,7 @@

    总结 - 31 + 33 分类 @@ -754,7 +754,7 @@

    总结 - 28 + 29 标签 diff --git a/post/7528c810.html b/post/7528c810.html index 48b30844..0fac7c0b 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -715,7 +715,7 @@

    总结 - 31 + 32 日志 @@ -726,7 +726,7 @@

    总结 - 31 + 33 分类 @@ -737,7 +737,7 @@

    总结 - 28 + 29 标签 diff --git a/post/7b9ead86.html b/post/7b9ead86.html index 2ea1365a..80a20857 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -715,7 +715,7 @@

    总结 - 31 + 32 日志 @@ -726,7 +726,7 @@

    总结 - 31 + 33 分类 @@ -737,7 +737,7 @@

    总结 - 28 + 29 标签 diff --git a/post/7eb2637f.html b/post/7eb2637f.html index efab65b9..1e2dbc07 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -754,7 +754,7 @@

    - 31 + 32 日志 @@ -765,7 +765,7 @@

    - 31 + 33 分类 @@ -776,7 +776,7 @@

    - 28 + 29 标签 diff --git a/post/817c7d82.html b/post/817c7d82.html index f1dd99c4..0c6f37b6 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1323,7 +1323,7 @@

    - 31 + 32 日志 @@ -1334,7 +1334,7 @@
    - 31 + 33 分类 @@ -1345,7 +1345,7 @@
    - 28 + 29 标签 diff --git a/post/8a061473.html b/post/8a061473.html index 17140a47..210eb51d 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -791,7 +791,7 @@
    - 31 + 32 日志 @@ -802,7 +802,7 @@
    - 31 + 33 分类 @@ -813,7 +813,7 @@
    - 28 + 29 标签 diff --git a/post/8bd965a0.html b/post/8bd965a0.html index 20b67169..e9fea2ef 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -714,7 +714,7 @@

    - 31 + 32 日志 @@ -725,7 +725,7 @@

    @@ -736,7 +736,7 @@

    diff --git a/post/99ea2970.html b/post/99ea2970.html index 333bb4b7..6a07ceb2 100644 --- a/post/99ea2970.html +++ b/post/99ea2970.html @@ -710,7 +710,7 @@

    - 31 + 32 日志 @@ -721,7 +721,7 @@

    @@ -732,7 +732,7 @@

    diff --git a/post/a38c0645.html b/post/a38c0645.html index 2b5875bc..2ef88b65 100644 --- a/post/a38c0645.html +++ b/post/a38c0645.html @@ -694,7 +694,7 @@

    总结 - 31 + 32 日志 @@ -705,7 +705,7 @@

    总结 - 31 + 33 分类 @@ -716,7 +716,7 @@

    总结 - 28 + 29 标签 diff --git a/post/ab706eb5.html b/post/ab706eb5.html index 883769a2..236a48b2 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -697,7 +697,7 @@

    总结 - 31 + 32 日志 @@ -708,7 +708,7 @@

    总结 - 31 + 33 分类 @@ -719,7 +719,7 @@

    总结 - 28 + 29 标签 diff --git a/post/b1d4025b.html b/post/b1d4025b.html index 79a2a8a9..ff4586c0 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -627,7 +627,7 @@

    hello world

    - 31 + 32 日志 @@ -638,7 +638,7 @@

    hello world

    @@ -649,7 +649,7 @@

    hello world

    diff --git a/post/bc557e1a.html b/post/bc557e1a.html index a6b7e0b8..95bb8c0f 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -762,7 +762,7 @@
    - 31 + 32 日志 @@ -773,7 +773,7 @@
    - 31 + 33 分类 @@ -784,7 +784,7 @@
    - 28 + 29 标签 diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index 8b08c349..08153497 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -714,7 +714,7 @@

    - 31 + 32 日志 @@ -725,7 +725,7 @@

    @@ -736,7 +736,7 @@

    diff --git a/post/c34b451f.html b/post/c34b451f.html index 98d91714..303a6003 100644 --- a/post/c34b451f.html +++ b/post/c34b451f.html @@ -753,7 +753,7 @@

    总结 - 31 + 32 日志 @@ -764,7 +764,7 @@

    总结 - 31 + 33 分类 @@ -775,7 +775,7 @@

    总结 - 28 + 29 标签 diff --git a/post/d7d0fc76.html b/post/d7d0fc76.html index 300fba31..398d9996 100644 --- a/post/d7d0fc76.html +++ b/post/d7d0fc76.html @@ -679,7 +679,7 @@

    - 31 + 32 日志 @@ -690,7 +690,7 @@

    - 31 + 33 分类 @@ -701,7 +701,7 @@

    - 28 + 29 标签 diff --git a/post/e09f0428.html b/post/e09f0428.html index 1f1e9f12..a211b512 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -684,7 +684,7 @@

    - 31 + 32 日志 @@ -695,7 +695,7 @@

    - 31 + 33 分类 @@ -706,7 +706,7 @@

    - 28 + 29 标签 diff --git a/post/ee27c07f.html b/post/ee27c07f.html index a2dd455c..5a633e3f 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -677,7 +677,7 @@

    - 31 + 32 日志 @@ -688,7 +688,7 @@

    @@ -699,7 +699,7 @@

    diff --git a/post/f440d00b.html b/post/f440d00b.html index 087c1548..d7b4130d 100644 --- a/post/f440d00b.html +++ b/post/f440d00b.html @@ -713,7 +713,7 @@

    总结 - 31 + 32 日志 @@ -724,7 +724,7 @@

    总结 - 31 + 33 分类 @@ -735,7 +735,7 @@

    总结 - 28 + 29 标签 diff --git a/post/f92758d8.html b/post/f92758d8.html index 3ab7260a..3716b188 100644 --- a/post/f92758d8.html +++ b/post/f92758d8.html @@ -701,7 +701,7 @@

    总结 - 31 + 32 日志 @@ -712,7 +712,7 @@

    总结 - 31 + 33 分类 @@ -723,7 +723,7 @@

    总结 - 28 + 29 标签 diff --git a/post/fa75f5d7.html b/post/fa75f5d7.html index 564a15a7..37b7f43f 100644 --- a/post/fa75f5d7.html +++ b/post/fa75f5d7.html @@ -626,6 +626,10 @@

    + + @@ -713,7 +717,7 @@

    - 31 + 32 日志 @@ -724,7 +728,7 @@

    - 31 + 33 分类 @@ -735,7 +739,7 @@

    - 28 + 29 标签 diff --git a/post/fe76043.html b/post/fe76043.html index 5b7b1b8d..a0a6d1ea 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -680,7 +680,7 @@

    总结 - 31 + 32 日志 @@ -691,7 +691,7 @@

    总结 - 31 + 33 分类 @@ -702,7 +702,7 @@

    总结 - 28 + 29 标签 diff --git a/search.xml b/search.xml index 6f91a006..34b847df 100644 --- a/search.xml +++ b/search.xml @@ -1,5 +1,18 @@ + + <![CDATA[Spring 是如何造出一个 Bean 的]]> + %2Fpost%2F558ca0bd.html + + + Spring + Java + + + Java + Spring + + <![CDATA[从 CPU 缓存看缓存的套路]]> %2Fpost%2Ffa75f5d7.html diff --git a/sitemap.xml b/sitemap.xml index 6db64bd3..933d8aad 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,13 @@ + + https://www.mghio.cn/post/558ca0bd.html + + 2020-10-08T07:31:37.322Z + + + https://www.mghio.cn/post/fa75f5d7.html diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index 6b27bda3..f038547b 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index 722fc78d..2e71d920 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index b002a919..16c65747 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/GC/index.html b/tags/GC/index.html index 8fc02d85..e2443953 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/Guava/index.html b/tags/Guava/index.html index be5e3052..e7544077 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index 61cb3622..9bc497b3 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index 84ae4171..136bbdd3 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/JDK/index.html b/tags/JDK/index.html index fc5f4bde..9cbb6a9a 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/JVM/index.html b/tags/JVM/index.html index b6b73726..bde66927 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -412,7 +412,7 @@

    - 31 + 32 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index 351e27cd..5d202d39 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index cb34af71..22c5b248 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/Java/index.html b/tags/Java/index.html index e1816458..b234f87d 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -309,6 +309,32 @@

    Java标签 + + + + + +
    @@ -541,32 +567,6 @@

    - - - - - - @@ -624,7 +624,7 @@

    - 31 + 32 日志 @@ -635,7 +635,7 @@

    @@ -646,7 +646,7 @@

    diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index 571d4e75..200e11da 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -309,6 +309,32 @@

    Java标签 + + + + + +
    @@ -541,32 +567,6 @@

    - - - - - - @@ -624,7 +624,7 @@

    - 31 + 32 日志 @@ -635,7 +635,7 @@

    @@ -646,7 +646,7 @@

    diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index b7e8f544..1b3b45dc 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -309,6 +309,32 @@

    Java标签 + + + + + +
    @@ -546,7 +572,7 @@

    - 31 + 32 日志 @@ -557,7 +583,7 @@

    @@ -568,7 +594,7 @@

    diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index 4f3149ab..9178b3f2 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/List/index.html b/tags/List/index.html index 8dc3f09f..556b0031 100644 --- a/tags/List/index.html +++ b/tags/List/index.html @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/RabbitMQ/index.html b/tags/RabbitMQ/index.html index 11e1516e..bfc71138 100644 --- a/tags/RabbitMQ/index.html +++ b/tags/RabbitMQ/index.html @@ -412,7 +412,7 @@

    - 31 + 32 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git a/tags/Spring/index.html b/tags/Spring/index.html new file mode 100644 index 00000000..2c98c3da --- /dev/null +++ b/tags/Spring/index.html @@ -0,0 +1,1253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: Spring | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/String/index.html b/tags/String/index.html index 88c7cd99..6ecb4abf 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/index.html b/tags/index.html index c7af2b69..ee62de01 100644 --- a/tags/index.html +++ b/tags/index.html @@ -317,10 +317,10 @@

    @@ -378,7 +378,7 @@

    - 31 + 32 日志 @@ -389,7 +389,7 @@

    @@ -400,7 +400,7 @@

    diff --git a/tags/mockito/index.html b/tags/mockito/index.html index 26641acf..495aaaa2 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/test/index.html b/tags/test/index.html index 7a1e2489..2821a198 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index a04c8faf..3f39c0e2 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index d7cb1352..6bdde673 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -412,7 +412,7 @@

    - 31 + 32 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 424764a7..12be18e4 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -412,7 +412,7 @@

    - 31 + 32 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index ceedec65..64c294b2 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index c48dee2c..570ce642 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -412,7 +412,7 @@

    - 31 + 32 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index 9b34f122..689b56de 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 1a0384a0..5ac17f4c 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 4c1de589..66c00126 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\347\274\223\345\255\230/index.html" "b/tags/\347\274\223\345\255\230/index.html" index cff19276..0206d783 100644 --- "a/tags/\347\274\223\345\255\230/index.html" +++ "b/tags/\347\274\223\345\255\230/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index 5ee56246..db81c437 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -386,7 +386,7 @@

    - 31 + 32 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    From f4cd29da7b1913c66a0d63219a003dd13b860694 Mon Sep 17 00:00:00 2001 From: maguihai Date: Sun, 25 Oct 2020 10:04:44 +0800 Subject: [PATCH 10/19] Site updated: 2020-10-25 10:04:44 --- about/index.html | 8 ++++---- css/main.css | 2 +- sitemap.xml | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/about/index.html b/about/index.html index 25e789b1..d7dc2b43 100644 --- a/about/index.html +++ b/about/index.html @@ -103,8 +103,8 @@ - - + + @@ -328,8 +328,8 @@

    如何联系我

    javafm

    微信公众号「mghio」

    - -
    微信号「MGH5023344123」
    + +
    微信号「mghiodev」
    diff --git a/css/main.css b/css/main.css index 35887419..a3a0896e 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #c99aa4; + background: #e57fec; } .links-of-blogroll { font-size: 13px; diff --git a/sitemap.xml b/sitemap.xml index 933d8aad..874fbd26 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,13 @@ + + https://www.mghio.cn/about/index.html + + 2020-10-25T02:02:12.038Z + + + https://www.mghio.cn/post/558ca0bd.html @@ -127,13 +134,6 @@ - - https://www.mghio.cn/about/index.html - - 2020-01-13T13:05:57.872Z - - - https://www.mghio.cn/post/f440d00b.html From bfe20628da4742bd65cfdb739ffa074e7802e07c Mon Sep 17 00:00:00 2001 From: mghio Date: Sun, 29 Nov 2020 16:00:07 +0800 Subject: [PATCH 11/19] Site updated: 2020-11-29 16:00:06 --- about/index.html | 6 +- archives/2019/10/index.html | 8 +- archives/2019/11/index.html | 8 +- archives/2019/12/index.html | 8 +- archives/2019/index.html | 8 +- archives/2019/page/2/index.html | 8 +- archives/2020/01/index.html | 8 +- archives/2020/02/index.html | 8 +- archives/2020/03/index.html | 8 +- archives/2020/04/index.html | 8 +- archives/2020/05/index.html | 8 +- archives/2020/06/index.html | 8 +- archives/2020/07/index.html | 8 +- archives/2020/08/index.html | 8 +- archives/2020/09/index.html | 8 +- archives/2020/10/index.html | 8 +- archives/2020/11/index.html | 1272 +++++++++++++ archives/2020/index.html | 78 +- archives/2020/page/2/index.html | 43 +- archives/index.html | 78 +- archives/page/2/index.html | 83 +- archives/page/3/index.html | 78 +- archives/page/4/index.html | 43 +- atom.xml | 57 +- baidusitemap.xml | 3 + categories/JDK/Java/index.html | 6 +- .../index.html" | 6 +- categories/JDK/index.html | 6 +- categories/Java/Bloom-filter/index.html | 6 +- categories/Java/GC/index.html | 6 +- categories/Java/Guava/String/index.html | 6 +- categories/Java/Guava/index.html | 6 +- categories/Java/IDEA/index.html | 6 +- .../IDEA/\345\267\245\345\205\267/index.html" | 6 +- .../IO\346\250\241\345\236\213/index.html" | 6 +- categories/Java/JVM/index.html | 6 +- categories/Java/List/index.html | 6 +- categories/Java/Spring/index.html | 1254 +++++++++++++ categories/Java/index.html | 58 +- categories/Java/page/2/index.html | 58 +- categories/Java/page/3/index.html | 32 +- categories/Java/unit-test/index.html | 6 +- categories/Java/unit-test/mockito/index.html | 6 +- .../Java/\345\216\237\347\220\206/index.html" | 6 +- .../Java/\345\217\215\345\260\204/index.html" | 6 +- .../index.html" | 6 +- .../Java/\345\271\266\345\217\221/index.html" | 6 +- .../\350\277\233\351\230\266/index.html" | 6 +- .../Java/\345\274\202\346\255\245/index.html" | 6 +- .../Eureka/index.html" | 6 +- .../index.html" | 6 +- .../index.html" | 6 +- .../Java/\347\274\223\345\255\230/index.html" | 6 +- .../Java/\351\207\215\346\236\204/index.html" | 6 +- .../Linux\347\254\224\350\256\260/index.html" | 6 +- categories/RabbitMQ/Java/index.html | 6 +- categories/RabbitMQ/index.html | 6 +- categories/Spring/Java/index.html | 6 +- categories/Spring/index.html | 6 +- categories/index.html | 10 +- .../CAP\345\256\232\347\220\206/index.html" | 6 +- .../index.html" | 6 +- css/main.css | 2 +- index.html | 322 ++-- page/2/index.html | 347 ++-- page/3/index.html | 402 +++-- page/4/index.html | 199 +- post/102cd3d9.html | 6 +- post/11cb7677.html | 6 +- post/192cb539.html | 6 +- post/24042edf.html | 6 +- post/24cb2421.html | 1598 +++++++++++++++++ post/34755d6c.html | 6 +- post/3ae0ff4e.html | 6 +- post/4615256d.html | 6 +- post/4b00e13c.html | 6 +- post/4ea48fa7.html | 6 +- post/51e5bd99.html | 6 +- post/558ca0bd.html | 10 +- post/710bd10b.html | 6 +- post/7528c810.html | 6 +- post/7b9ead86.html | 6 +- post/7eb2637f.html | 6 +- post/817c7d82.html | 6 +- post/8a061473.html | 6 +- post/8bd965a0.html | 6 +- post/99ea2970.html | 6 +- post/a38c0645.html | 6 +- post/ab706eb5.html | 6 +- post/b1d4025b.html | 6 +- post/bc557e1a.html | 6 +- post/bfcdfeaf.html | 6 +- post/c34b451f.html | 6 +- post/d7d0fc76.html | 6 +- post/e09f0428.html | 6 +- post/ee27c07f.html | 6 +- post/f440d00b.html | 6 +- post/f92758d8.html | 6 +- post/fa75f5d7.html | 6 +- post/fe76043.html | 6 +- search.xml | 13 + sitemap.xml | 7 + tags/Bloom-filter/index.html | 6 +- "tags/CAP\345\256\232\347\220\206/index.html" | 6 +- tags/Eureka/index.html | 6 +- tags/GC/index.html | 6 +- tags/Guava/index.html | 6 +- tags/IDEA/index.html | 6 +- "tags/IO\346\250\241\345\236\213/index.html" | 6 +- tags/IoC/index.html | 1253 +++++++++++++ tags/JDK/index.html | 6 +- tags/JVM/index.html | 6 +- .../Java-\345\216\237\347\220\206/index.html" | 6 +- .../Java-\345\271\266\345\217\221/index.html" | 6 +- tags/Java/index.html | 6 +- tags/Java/page/2/index.html | 6 +- tags/Java/page/3/index.html | 6 +- .../Linux\347\254\224\350\256\260/index.html" | 6 +- tags/List/index.html | 6 +- tags/RabbitMQ/index.html | 6 +- tags/Spring/index.html | 32 +- tags/String/index.html | 6 +- tags/index.html | 10 +- tags/mockito/index.html | 6 +- tags/test/index.html | 6 +- .../index.html" | 6 +- "tags/\345\217\215\345\260\204/index.html" | 6 +- .../index.html" | 6 +- "tags/\345\267\245\345\205\267/index.html" | 6 +- "tags/\345\271\266\345\217\221/index.html" | 6 +- "tags/\345\274\202\346\255\245/index.html" | 6 +- .../index.html" | 6 +- .../index.html" | 6 +- "tags/\347\274\223\345\255\230/index.html" | 6 +- "tags/\351\207\215\346\236\204/index.html" | 6 +- 135 files changed, 6874 insertions(+), 1152 deletions(-) create mode 100644 archives/2020/11/index.html create mode 100644 categories/Java/Spring/index.html create mode 100644 post/24cb2421.html create mode 100644 tags/IoC/index.html diff --git a/about/index.html b/about/index.html index d7dc2b43..4101a7e9 100644 --- a/about/index.html +++ b/about/index.html @@ -408,7 +408,7 @@

    - 32 + 33 日志 @@ -419,7 +419,7 @@

    - 33 + 34 分类 @@ -430,7 +430,7 @@

    - 29 + 30 标签 diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html index 98dc27d3..75562d54 100644 --- a/archives/2019/10/index.html +++ b/archives/2019/10/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -545,7 +545,7 @@

    - 32 + 33 日志 @@ -556,7 +556,7 @@

    @@ -567,7 +567,7 @@

    diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html index 43ccaf4c..2fed47fa 100644 --- a/archives/2019/11/index.html +++ b/archives/2019/11/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -510,7 +510,7 @@

    - 32 + 33 日志 @@ -521,7 +521,7 @@

    @@ -532,7 +532,7 @@

    diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html index c0165fd5..38a2807f 100644 --- a/archives/2019/12/index.html +++ b/archives/2019/12/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -510,7 +510,7 @@

    - 32 + 33 日志 @@ -521,7 +521,7 @@

    @@ -532,7 +532,7 @@

    diff --git a/archives/2019/index.html b/archives/2019/index.html index 565dd679..37c9d71a 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -724,7 +724,7 @@

    - 32 + 33 日志 @@ -735,7 +735,7 @@

    @@ -746,7 +746,7 @@

    diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html index 4da03d49..5a580dfa 100644 --- a/archives/2019/page/2/index.html +++ b/archives/2019/page/2/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -479,7 +479,7 @@

    - 32 + 33 日志 @@ -490,7 +490,7 @@

    @@ -501,7 +501,7 @@

    diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html index d59713b4..82089bcd 100644 --- a/archives/2020/01/index.html +++ b/archives/2020/01/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -440,7 +440,7 @@

    - 32 + 33 日志 @@ -451,7 +451,7 @@

    @@ -462,7 +462,7 @@

    diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html index 45fe85d3..eabc866c 100644 --- a/archives/2020/02/index.html +++ b/archives/2020/02/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -405,7 +405,7 @@

    - 32 + 33 日志 @@ -416,7 +416,7 @@

    @@ -427,7 +427,7 @@

    diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index 365ef03c..c6b4c05b 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -510,7 +510,7 @@

    - 32 + 33 日志 @@ -521,7 +521,7 @@

    @@ -532,7 +532,7 @@

    diff --git a/archives/2020/04/index.html b/archives/2020/04/index.html index 79023dad..a77738dc 100644 --- a/archives/2020/04/index.html +++ b/archives/2020/04/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -510,7 +510,7 @@

    - 32 + 33 日志 @@ -521,7 +521,7 @@

    @@ -532,7 +532,7 @@

    diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index d0afe6d2..bff8ee7c 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -440,7 +440,7 @@

    - 32 + 33 日志 @@ -451,7 +451,7 @@

    @@ -462,7 +462,7 @@

    diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html index 178cc4d4..7fcf1ecc 100644 --- a/archives/2020/06/index.html +++ b/archives/2020/06/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -405,7 +405,7 @@

    - 32 + 33 日志 @@ -416,7 +416,7 @@

    @@ -427,7 +427,7 @@

    diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html index b15bf6b7..7b7b168b 100644 --- a/archives/2020/07/index.html +++ b/archives/2020/07/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -405,7 +405,7 @@

    - 32 + 33 日志 @@ -416,7 +416,7 @@

    @@ -427,7 +427,7 @@

    diff --git a/archives/2020/08/index.html b/archives/2020/08/index.html index 9e2f5e27..7971b7b0 100644 --- a/archives/2020/08/index.html +++ b/archives/2020/08/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -440,7 +440,7 @@

    - 32 + 33 日志 @@ -451,7 +451,7 @@

    @@ -462,7 +462,7 @@

    diff --git a/archives/2020/09/index.html b/archives/2020/09/index.html index a4591784..6e02c594 100644 --- a/archives/2020/09/index.html +++ b/archives/2020/09/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -405,7 +405,7 @@

    - 32 + 33 日志 @@ -416,7 +416,7 @@

    @@ -427,7 +427,7 @@

    diff --git a/archives/2020/10/index.html b/archives/2020/10/index.html index 6b64d44d..cc66abf9 100644 --- a/archives/2020/10/index.html +++ b/archives/2020/10/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -405,7 +405,7 @@

    - 32 + 33 日志 @@ -416,7 +416,7 @@

    @@ -427,7 +427,7 @@

    diff --git a/archives/2020/11/index.html b/archives/2020/11/index.html new file mode 100644 index 00000000..10ade8a3 --- /dev/null +++ b/archives/2020/11/index.html @@ -0,0 +1,1272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/index.html b/archives/2020/index.html index e7d014f0..7a8aca18 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2020

    + + + + + + + + + + + + + + +
    @@ -632,41 +667,6 @@

    - - - - - - - - - - - - - - - @@ -724,7 +724,7 @@

    - 32 + 33 日志 @@ -735,7 +735,7 @@

    @@ -746,7 +746,7 @@

    diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html index 55079ecf..cb97474a 100644 --- a/archives/2020/page/2/index.html +++ b/archives/2020/page/2/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2020

    + + + + + + + + + + + + + + +
    @@ -689,7 +724,7 @@

    - 32 + 33 日志 @@ -700,7 +735,7 @@

    @@ -711,7 +746,7 @@

    diff --git a/archives/index.html b/archives/index.html index b4e5cc7c..b0f5659e 100644 --- a/archives/index.html +++ b/archives/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2020

    + + + + + + + + + + + + + + +
    @@ -632,41 +667,6 @@

    - - - - - - - - - - - - - - - @@ -724,7 +724,7 @@

    - 32 + 33 日志 @@ -735,7 +735,7 @@

    @@ -746,7 +746,7 @@

    diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 396a4845..aa1aac11 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2020

    + + + + + + + + + + + + + + +
    @@ -632,46 +667,6 @@

    - - - - - - -
    -

    2019

    -
    - - - - - - - - - - - @@ -729,7 +724,7 @@

    - 32 + 33 日志 @@ -740,7 +735,7 @@

    @@ -751,7 +746,7 @@

    diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 1dc2e418..b531bd65 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2019

    + + + + + + + + + + + + + + +
    @@ -632,41 +667,6 @@

    - - - - - - - - - - - - - - - @@ -724,7 +724,7 @@

    - 32 + 33 日志 @@ -735,7 +735,7 @@

    @@ -746,7 +746,7 @@

    diff --git a/archives/page/4/index.html b/archives/page/4/index.html index 026012f3..bd8b4f73 100644 --- a/archives/page/4/index.html +++ b/archives/page/4/index.html @@ -307,7 +307,7 @@

    Java 搬运工 & 终身学习 - OK! 目前共计 32 篇日志。 继续努力。 + OK! 目前共计 33 篇日志。 继续努力。 @@ -326,6 +326,41 @@

    2019

    + + + + + + + + + + + + + + +
    @@ -444,7 +479,7 @@

    - 32 + 33 日志 @@ -455,7 +490,7 @@

    @@ -466,7 +501,7 @@

    diff --git a/atom.xml b/atom.xml index 18a909bd..56c473bd 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2020-10-08T07:31:37.322Z + 2020-11-29T07:58:43.606Z https://www.mghio.cn/ @@ -16,6 +16,33 @@ Hexo + + 如何实现一个简易版的 Spring - 如何实现 Setter 注入 + + https://www.mghio.cn/post/24cb2421.html + 2020-11-28T06:52:27.000Z + 2020-11-29T07:58:43.606Z + + 前言

    之前在 上篇 提到过会实现一个简易版的 IoCAOP,今天它终于来了。。。相信对于使用 Java 开发语言的朋友们都使用过或者听说过 Spring 这个开发框架,绝大部分的企业级开发中都离不开它,通过 官网 可以了解到其生态非常庞大,针对不同方面的开发提供了一些解决方案,可以说 Spring 框架的诞生是对 Java 开发人员的一大福利,自 2004 年发布以来,Spring 为了解决一些企业开发中的痛点先后引入了很多的特性和功能,其中最重要的就是我们经常听到的 IoCAOP 特性,由于涉及到的知识和细节比较多,会分为几篇文章来介绍,今天这篇(也是第一篇)我们来看看如何实现基于 XML 配置方式的 Setter 注入

    预备知识

    既然是通过 XML 配置文件的方式,首先第一件事就是要读取 XML 文件然后转换为我们需要的数据结构,解析 XML 文件有但不限于这些方式(JDOMXOMdom4j),这里使用的是简单易上手的 dom4j,所你得对其基础知识有一些简单了解,其实都是一些很简单的方法基础使用而已,第二个就是你要有一些 Spring 框架的使用经验,这里实现的简易版本质上是对 Spring 的一个精简后的核心部分的简单实现,是的,没错,你只需要有了这些基础预备知识就可以了。

    基础数据结构抽象

    在开始编码实现前先要做一些简单的构思和设计,首先在 Spring 中把一个被其管理的对象称之为 Bean,然后其它的操作都是围绕这个 Bean 来展开设计的,所以为了能在程序中统一并且规范的表示一个 Bean 的定义,于是第一个接口 BeanDefinition 就出来了,本次需要的一些基本信息包含 Bean 的名称、所属类名称、是否单例、作用域等,如下所示:

    spring-injection-beandefinition-1.png

    现在 BeanDefinition 有了,接下来就是要根据这个 BeanDefinition 去创建出对应的 Bean 实例了,很显然这需要一个 Factory 工厂接口去完成这个创建的工作,这个创建 Bean 的接口命名为 BeanFactory,其提供根据不同条件去创建相对应的 Bean 实例功能(比如 beanId),但是创建的前提是需要先注册这个 BeanDefinition,然后根据一定条件再从中去获取 BeanDefinition,根据 单一职责 原则,这个功能应该由一个新的接口去完成,主要是做注册和获取 BeanDefinition 的工作,故将其命名为 BeanDefinitionRegistry,我们需要的 BeanDefinition 要从哪里获取呢?很显然我们是基于 XML 配置的方式,当然是从 XML 配置文件中获取到的,同样根据单一职责原则,也需要一个类去完成这个事情,将其命名为 XMLBeanDefinitionReader,这部分的整体结构如下所示:

    spring-injection-beanfactory-2.png

    接下来面临的一个问题就是,像 XML 这种配置文件资源要如何表示呢,这些配置对于程序来说是一种资源,可以统一抽象为 Resource,然后提供一个返回资源对应流(InputStream)对象接口,这种资源可以从项目中获取、本地文件获取甚至是从远程获取,它们都是一种 Resource,结构如下:

    spring-injection-resource-3.png

    最后就是要一个提供去组合调用上面的那些类去完成 XML 配置文件解析为 BeanDefinition 并注入到容器中了的功能,担任这程序上下文的职责,将其命名为 ApplicationContext,这里同样也可以根据 Resource 的类型分为多种不同的类,比如:FileSystmXmlApplicationContextClassPathXmlApplicationContext 等,这些内部都有一个将配置文件转换为 Resource 的过程,可以使用 模板方法 抽象出一个公共父类抽象类,如下所示:

    spring-injection-applicationcontext.png

    总结以上分析结果,得出初步类图设计如下:

    spring-injection-all-4.png

    最终要实现 Setter 注入这个目标,可以将其分解为以下两个步骤:

    1. XML 配置文件中的 <bean> 标签解析为 BeanDefinition 并注入到容器中
    2. 实现 Setter 注入

    下面我们分为这两个部分来分别讲述如何实现。

    配置文件解析

    假设有如下内容的配置文件 applicationcontext-config1.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.e3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="orderService" class="cn.mghio.service.version1.OrderService" />

    </beans>

    最终需要解析出一个 idorderService 类型为 cn.mghio.service.version1.OrderServiceBeanDefinition,翻译成测试类的话也就是需要让如下测试类可以运行通过:

    1
    2
    3
    4
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    /**
    * @author mghio
    */
    public class BeanFactoryTest {

    private Resource resource;
    private DefaultBeanFactory beanFactory;
    private XmlBeanDefinitionReader reader;

    @BeforeEach
    public void beforeEach() {
    resource = new ClassPathResource("applicationcontext-config1.xml");
    beanFactory = new DefaultBeanFactory();
    reader = new XmlBeanDefinitionReader(beanFactory);
    }

    @Test
    public void testGetBeanFromXmlFile() {
    reader.loadBeanDefinition(resource);
    BeanDefinition bd = beanFactory.getBeanDefinition("orderService");

    assertEquals("cn.mghio.service.version1.OrderService", bd.getBeanClassNam());
    OrderService orderService = (OrderService) beanFactory.getBean("orderService");
    assertNotNull(orderService);
    }

    @Test
    public void testGetBeanFromXmlFileWithInvalidBeanId() {
    assertThrows(BeanCreationException.class, () -> beanFactory.getBean("notExistsBeanId"));
    }

    @Test
    public void testGetFromXmlFilWithFileNotExists() {
    resource = new ClassPathResource("notExists.xml");
    assertThrows(BeanDefinitionException.class, () -> reader.loadBeanDefinition(resource));
    }

    }

    可以看到这里面的关键就是如何去实现 XmlBeanDefinitionReader 类的 loadBeanDefinition 从配置中加载和注入 BeanDefinition,思考分析后不然发现这里主要是两步,第一步是解析 XML 配置转换为 BeanDefinition,这就需要上文提到的 dom4j 提供的能力了,第二步将解析出来的 BeanDefinition 注入到容器中,通过组合使用 BeanDefinitionRegistry 接口提供注册 BeanDefinition 的能力来完成。读取 XML 配置的类 XmlBeanDefinitionReader 的代码实现很快就可以写出来了,该类部分代码如下所示:

    1
    2
    3
    4
    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
    30
    31
    32
    33
    /**
    * @author mghio
    */
    public class XmlBeanDefinitionReader {

    private static final String BEAN_ID_ATTRIBUTE = "id";
    private static final String BEAN_CLASS_ATTRIBUTE = "class";

    private BeanDefinitionRegistry registry;

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
    this.registry = registry;
    }

    @SuppressWarnings("unchecked")
    public void loadBeanDefinition(Resource resource) {
    try (InputStream is = resource.getInputStream()) {
    SAXReader saxReader = new SAXReader();
    Document document = saxReader.read(is);
    Element root = document.getRootElement(); // <beans>
    Iterator<Element> iterator = root.elementIterator();
    while (iterator.hasNext()) {
    Element element = iterator.next();
    String beanId = element.attributeValue(BEAN_ID_ATTRIBUTE);
    String beanClassName = element.attributeValue(BEAN_CLASS_ATTRIBUTE);
    BeanDefinition bd = new GenericBeanDefinition(beanId, beanClassName);
    this.registry.registerBeanDefinition(beanId, bd);
    }
    } catch (DocumentException | IOException e) {
    throw new BeanDefinitionException("IOException parsing XML document:" + configurationFile, e);
    }
    }
    }

    然后当调用 BeanFactorygetBean 方法时就可以根据 Bean 的全限定名创建一个实例出来了(PS:暂时不考虑实例缓存),方法实现主要代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public Object getBean(String beanId) {
    BeanDefinition bd = getBeanDefinition(beanId);
    if (null == bd) {
    throw new BeanCreationException("BeanDefinition does not exists, beanId:" + beanId);
    }
    ClassLoader classLoader = this.getClassLoader();
    String beanClassName = bd.getBeanClassNam();
    try {
    Class<?> clazz = classLoader.loadClass(beanClassName);
    return clazz.newInstance();
    } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
    throw new BeanCreationException("Created bean for " + beanClassName + " fail.", e);
    }
    }

    到这里配置文件解析方面的工作已完成,接下来看看要如何实现 Setter 注入。

    如何实现 Setter 注入

    首先实现基于 XML 配置文件的 Setter 注入本质上也是解析 XML 配置文件,然后再调用对象属性的 setXXX 方法将配置的值设置进去,配置文件 applicationcontext-config2.xml 如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.e3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="stockDao" class="cn.mghio.dao.version2.StockDao"/>

    <bean id="tradeDao" class="cn.mghio.dao.version2.TradeDao"/>

    <bean id="orderService" class="cn.mghio.service.version2.OrderService">
    <property name="stockDao" ref="stockDao"/>
    <property name="tradeDao" ref="tradeDao"/>
    <property name="num" value="2"/>
    <property name="owner" value="mghio"/>
    <property name="orderTime" value="2020-11-24 18:42:32"/>
    </bean>

    </beans>

    我们之前使用了 BeanDefinition 去抽象了 <bean> 标签,这里面临的第一个问题就是要如何去表达配置文件中的 <property> 标签,其中 ref 属性表示一个 beanIdvalue 属性表示一个值(值类型为:IntegerStringDate 等)。观察后可以发现,<property> 标签本质上是一个 K-V 格式的数据(name 作为 Keyrefvalue 作为 Value),将这个类命名为 PropertyValue,很明显一个 BeanDefinition 会有多个 PropertyValue,结构如下:

    spring-injection-setter-property-1.png

    这里的 value 有两种不同的类型,一种是表示 Beanid 值,运行时会解析为一个 Bean 的引用,将其命名为 RuntimeBeanReference,还有一种是 String 类型,运行时会解析为不同的类型,将其命名为 TypeStringValue。第二个问题就是要如何将一个类型转换为另一个类型呢?比如将上面配置中的字符串 2 转换为整型的 2、字符串 2020-11-24 18:42:32 转换为日期,这类通用的问题前辈们已经开发好了类库处理了,这里我们使用 commons-beanutils 库提供的 BeanUtils.copyProperty(final Object bean, final String name, final Object value) 方法即可。然后只需在之前 XmlBeanDefinitionReader 类的 loadBeanDefinition 方法解析 XML 配置文件的时解析 <bean> 标签下的 <property> 标签并设置到 BeanDefinitionpropertyValues 属性中;DefaultBeanFactory 中的 getBean 方法分为实例化 Bean 和读取向实例化完成的 Bean 使用 Setter 注入配置文件中配置属性对应的值。XmlBeanDefinitionReaderloadBeanDefinition() 方法代码修改为:

    1
    2
    3
    4
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    public void loadBeanDefinition(Resource resource) {
    try (InputStream is = resource.getInputStream()) {
    SAXReader saxReader = new SAXReader();
    Document document = saxReader.read(is);
    Element root = document.getRootElement(); // <beans>
    Iterator<Element> iterator = root.elementIterator();
    while (iterator.hasNext()) {
    Element element = iterator.next();
    String beanId = element.attributeValue(BEAN_ID_ATTRIBUTE);
    String beanClassName = element.attributeValue(BEAN_CLASS_ATTRIBUTE);
    BeanDefinition bd = new GenericBeanDefinition(beanId, beanClassName);
    parsePropertyElementValue(element, bd); // parse <property>
    this.registry.registerBeanDefinition(beanId, bd);
    }
    } catch (DocumentException | IOException e) {
    throw new BeanDefinitionException("IOException parsing XML document:" + resource, e);
    }
    }

    private void parsePropertyElementValue(Element element, BeanDefinition bd) {
    Iterator<Element> iterator = element.elementIterator(PROPERTY_ATTRIBUTE);
    while (iterator.hasNext()) {
    Element propertyElement = iterator.next();
    String propertyName = propertyElement.attributeValue(NAME_ATTRIBUTE);
    if (!StringUtils.hasText(propertyName)) {
    return;
    }

    Object value = parsePropertyElementValue(propertyElement, propertyName);
    PropertyValue propertyValue = new PropertyValue(propertyName, value);
    bd.getPropertyValues().add(propertyValue);
    }

    }

    private Object parsePropertyElementValue(Element propertyElement, String propertyName) {
    String elementName = (propertyName != null) ?
    "<property> element for property '" + propertyName + "' " : "<constructor-arg> element";

    boolean hasRefAttribute = propertyElement.attribute(REF_ATTRIBUTE) != null;
    boolean hasValueAttribute = propertyElement.attribute(VALUE_ATTRIBUTE) != null;

    if (hasRefAttribute) {
    String refName = propertyElement.attributeValue(REF_ATTRIBUTE);
    RuntimeBeanReference ref = new RuntimeBeanReference(refName);
    return ref;
    } else if (hasValueAttribute) {
    String value = propertyElement.attributeValue(VALUE_ATTRIBUTE);
    TypedStringValue valueHolder = new TypedStringValue(value);
    return valueHolder;
    } else {
    throw new RuntimeException(elementName + " must specify a ref or value");
    }
    }

    DefaultBeanFactorygetBean 方法也增加 Bean 属性注入操作,部分代码如下:

    1
    2
    3
    4
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    public Object getBean(String beanId) {
    BeanDefinition bd = getBeanDefinition(beanId);
    // 1. instantiate bean
    Object bean = instantiateBean(bd);
    // 2. populate bean
    populateBean(bd, bean);
    return bean;
    }

    private Object instantiateBean(BeanDefinition bd) {
    ClassLoader classLoader = this.getClassLoader();
    String beanClassName = bd.getBeanClassName();
    try {
    Class<?> clazz = classLoader.loadClass(beanClassName);
    return clazz.newInstance();
    } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
    throw new BeanCreationException("Created bean for " + beanClassName + " fail.", e);
    }
    }

    private void populateBean(BeanDefinition bd, Object bean) {
    List<PropertyValue> propertyValues = bd.getPropertyValues();
    if (propertyValues == null || propertyValues.isEmpty()) {
    return;
    }

    BeanDefinitionResolver resolver = new BeanDefinitionResolver(this);
    SimpleTypeConverted converter = new SimpleTypeConverted();
    try {
    for (PropertyValue propertyValue : propertyValues) {
    String propertyName = propertyValue.getName();
    Object originalValue = propertyValue.getValue();
    Object resolvedValue = resolver.resolveValueIfNecessary(originalValue);

    BeanUtils.copyProperty(bean, propertyName, resolvedValue);
    }
    } catch (Exception e) {
    throw new BeanCreationException("Failed to obtain BeanInfo for class [" + bd.getBeanClassName() + "]");
    }
    }

    至此,简单的 Setter 注入功能已完成。

    总结

    本文简单概述了基于 XML 配置文件方式的 Setter 注入简单实现过程,整体实现 Setter 注入的思路就是先设计一个数据结构去表达 XML 配置文件中的标签数据(比如上面的 PropertyValue),然后再解析配置文件填充数据并利用这个数据结构完成一些功能(比如 Setter 注入等)。感兴趣的朋友可以到这里 mghio-spring 查看完整代码。

    ]]> + + + + <h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>之前在 <a href="https://www.mghio.cn/post/558ca0bd.html">上篇</a> 提到过会实现一个简易版的 <code>IoC</code> 和 <code>AOP</code>,今天它终于来了。。。相信对于使用 <code>Java</code> 开发语言的朋友们都使用过或者听说过 <code>Spring</code> 这个开发框架,绝大部分的企业级开发中都离不开它,通过 <a href="https://spring.io" target="_blank" rel="noopener">官网</a> 可以了解到其生态非常庞大,针对不同方面的开发提供了一些解决方案,可以说 <code>Spring</code> 框架的诞生是对 <code>Java</code> 开发人员的一大福利,自 <code>2004</code> 年发布以来,<code>Spring</code> 为了解决一些企业开发中的痛点先后引入了很多的特性和功能,其中最重要的就是我们经常听到的 <code>IoC</code> 和 <code>AOP</code> 特性,由于涉及到的知识和细节比较多,会分为几篇文章来介绍,今天这篇(也是第一篇)我们来看看如何实现基于 <code>XML</code> 配置方式的 <strong>Setter 注入</strong>。</p> + + + + + + + + + + + + + + + Spring 是如何造出一个 Bean 的 @@ -579,34 +606,6 @@ - - - - - - - - Java 反射机制(一) - - https://www.mghio.cn/post/102cd3d9.html - 2019-12-29T06:00:29.000Z - 2019-12-31T04:30:05.163Z - - 前言

    Java 中有两种方式可以让我们在运行时识别对象和类的信息。一种是 RTTI(运行时类型识别:Run-Time Type Identification),它假定了我们在编译时已经知道了所有的类型;另一种是我们本文要说的反射机制,它允许我们在运行时获取和使用类的信息。无论是 RTTI 还是反射,其本质都是一样的,都是去动态的获取类的信息。它们唯一不同的是,RTTI 在编译时期知道要解析的类型,而反射是在运行时才知道要解析的类型。

    反射概述

    反射就是把 Java 类中的各个部分(属性、方法、构造方法等)映射成一个个对象。Class 类与 java.lang.reflect 类库一起对反射的概念提供了支持,类库中包含了 FieldMethodConstructor 类,每个类都实现了 Member 接口。这些类型的对象都是由 JVM 运行时创建的,用来表示未知类里对应的成员。这样我们就可以使用 Constructor 创建新的对象,用 getset 方法读取和修改类中与 Field 对象关联的字段,用 invoke 方法调用类中与 Method 对象关联的方法等。
    Java 反射机制是在运行状态中的,对于任意一个类我们可以通过反射获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。重要的是,要认识到反射机制并没有什么特别之处,当我们通过反射和一个未知类型的对象打交道时,JVM 只是简单的对这个对象做检查,看它属于哪个类,在用它做其它事情之前必须先加载那个类 Class 对象。所以那个类的字节码文件对象对于 JVM 来说必须是可获取的,要么在本地机器上,要么通过网络获取。

    反射 API 的使用

    想要通过反射获取一个类的信息之前,首先要先获取这个类的 Class 对象,在 Java 中所有类型都有与之关联的 Class 对象。

    获取类的 Class 对象

    Java 中获取一个类的 Class 对象有三种方式:
    第 ① 种 使用 Class 类的 forName 静态方法,当我们知道一个类的全路径时,可以通过 Class.forName 方法获取类的 Class 对象。

    1
    2
    Class stringClass = Class.forName("java.lang.String");
    System.out.println(stringClass);

    运行结果

    1
    class java.lang.String

    第 ② 种 使用 .class 获取,这种方式只适合在编译前就已经知道了要操作的 Class

    1
    2
    Class stringClass = String.class;
    System.out.println(stringClass);

    运行结果

    1
    class java.lang.String

    第 ③ 种 使用 getClass() 方法获取

    1
    2
    Class stringClass = "mghio".getClass();
    System.out.println(stringClass);

    运行结果

    1
    class java.lang.String
    通过反射创建类对象

    通过反射创建类对象有两种方式:

    第 ① 种 通过调用 Class 对象的 newInstance() 方法创建

    1
    2
    Class<Person> personClass = Person.class;
    Person person = personClass.newInstance();

    第 ② 种 通过调用 Constructor 对象的 newInstance() 方法创建

    1
    2
    3
    Class<Person> personClass = Person.class;
    Constructor personConstructor = personClass.getConstructor();
    Person person = (Person) personConstructor.newInstance();

    两者的区别是,通过 ClassnewInstance 方法只能通过无参构造方法创建,这就要求这个类必须有一个无参的构造方法,而通过 ConstructornewInstance 可以指定参数来选择特定的构造方法来创建对象。以下代码就是指定参数然后通过特定的构造方法创建对象的。

    1
    2
    3
    Class<Person> personClass = Person.class;
    Constructor personConstructor = personClass.getConstructor();
    Person person = (Person) personConstructor.newInstance("mghio", "中国上海");
    通过反射获取类的属性

    Class 类提供了两种方式获取一个类的属性。
    第 ① 种 是通过 Class 对象的 getFields 方法获取类的属性,该方法只能获取类的 public 属性。

    1
    2
    3
    Class<Person> personClass = Person.class;
    Field[] fields = personClass.getFields();
    System.out.println(Arrays.toString(fields));

    运行结果

    1
    2
    [public java.lang.String cn.mghio.blogmghiocode.reflect.Person.id, 
    public java.lang.String cn.mghio.blogmghiocode.reflect.Person.name]

    第 ② 种 是通过 Class 对象的 getDeclaredFields 方法获取类的属性,该方法可以获取类的所有属性(包括 private 修饰的属性)。

    1
    2
    3
    Class<Person> personClass = Person.class;
    Field[] fields = personClass.getDeclaredFields();
    System.out.println(Arrays.toString(fields));

    运行结果

    1
    2
    3
    4
    [public java.lang.String cn.mghio.blogmghiocode.reflect.Person.id, 
    public java.lang.String cn.mghio.blogmghiocode.reflect.Person.name,
    protected java.lang.Integer cn.mghio.blogmghiocode.reflect.Person.age,
    private java.lang.String cn.mghio.blogmghiocode.reflect.Person.address]
    通过反射获取类的方法

    Class 也提供了两种方式获取类的方法。
    第 ① 种 是通过 Class 对象的 getMethods 方法获取类的方法(包括继承而得的方法)。

    1
    2
    3
    Class<Person> personClass = Person.class;
    Method[] methods = personClass.getMethods();
    System.out.println(Arrays.toString(methods));

    运行结果

    1
    2
    3
    4
    5
    [public java.lang.String cn.mghio.blogmghiocode.reflect.Person.toString(), 
    public java.lang.String cn.mghio.blogmghiocode.reflect.Person.getAddress(),
    ...
    public final native java.lang.Class java.lang.Object.getClass(),
    public final native void java.lang.Object.notify()]

    第 ② 种 是通过 Class 对象的 getDeclaredMethods 方法获取类的方法(只包含类中定义的方法,不包含继承而来的方法)。

    1
    2
    3
    Class<Person> personClass = Person.class;
    Method[] methods = personClass.getDeclaredMethods();
    System.out.println(Arrays.toString(methods));

    运行结果

    1
    2
    3
    4
    5
    [public java.lang.String cn.mghio.blogmghiocode.reflect.Person.toString(), 
    public java.lang.String cn.mghio.blogmghiocode.reflect.Person.getAddress(),
    ...
    protected void cn.mghio.blogmghiocode.reflect.Person.protectedMethod(),
    private void cn.mghio.blogmghiocode.reflect.Person.privateMethod()]

    从以上结果可以看出这个方法只获取当前类中定义的方法,包含 private 方法,不会获取从父类中继承而来的方法。

    通过反射获取类的构造方法

    Class 也提供了两种方式获取类的构造方法。
    第 ① 种 是通过 Class 对象的 getConstructors 方法获取类的构造方法(只能获取当前类的 public 构造方法)。

    1
    2
    3
    Class<Person> personClass = Person.class;
    Constructor[] constructors = personClass.getConstructors();
    System.out.println(Arrays.toString(constructors));

    运行结果

    1
    [public cn.mghio.blogmghiocode.reflect.Person(java.lang.String,java.lang.String,java.lang.Integer,java.lang.String)]

    第 ② 种 是通过 Class 对象的 getDeclaredConstructors 方法获取类的构造方法(只包含类中定义的所有构造方法)。

    1
    2
    3
    Class<Person> personClass = Person.class;
    Constructor[] constructors = personClass.getDeclaredConstructors();
    System.out.println(Arrays.toString(constructors));

    运行结果

    1
    2
    3
    [public cn.mghio.blogmghiocode.reflect.Person(java.lang.String,java.lang.String,java.lang.Integer,java.lang.String), 
    protected cn.mghio.blogmghiocode.reflect.Person(java.lang.String,java.lang.String),
    private cn.mghio.blogmghiocode.reflect.Person()]
    通过反射获取类的类名

    Class 类提供了两种方式获取类的类名。
    第 ① 种 是通过 getName 方法获取类的全限定名(包含包名)。

    1
    2
    3
    Class<Person> personClass = Person.class;
    String fullPersonClassName = personClass.getName();
    System.out.println(fullPersonClassName);

    运行结果

    1
    cn.mghio.blogmghiocode.reflect.Person

    第 ② 种 是通过 Class 对象的 getSimpleName 方法获取类的类名(不包含包名)。

    1
    2
    3
     Class<Person> personClass = Person.class;
    String fullPersonClassName = personClass.getSimpleName();
    System.out.println(fullPersonClassName);

    运行结果

    1
    Person
    通过反射获取类的修饰符

    可以通过 Class 类来获取一个类的修饰符,也就是我们熟知的 publicprotectedprivate 等关键字,通过调用 getModifiers 方法来获取一个类的修饰符。

    1
    2
    3
    Class<Person> personClass = Person.class;
    int modifyInt = personClass.getModifiers();
    System.out.println(modifyInt);

    运行结果

    1
    1

    返回 1 表示类 Person 的修饰符为 public,修饰符在 Modifier 类中都被包装成一个 int 类型的数字,部分修饰符定义如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
    * The {@code int} value representing the {@code public}
    * modifier.
    */
    public static final int PUBLIC = 0x00000001;

    /**
    * The {@code int} value representing the {@code private}
    * modifier.
    */
    public static final int PRIVATE = 0x00000002;

    /**
    * The {@code int} value representing the {@code protected}
    * modifier.
    */
    public static final int PROTECTED = 0x00000004;
    通过反射获取类的包信息

    Class 对象通过 getPackage 方法获取类的包相关信息,可以使用 Class 对象通过如下的方式获取包信息

    1
    2
    3
    Class<Person> personClass = Person.class;
    Package packageClazz = personClass.getPackage();
    System.out.println(packageClazz.getName());

    运行结果

    1
    cn.mghio.blogmghiocode.reflect
    通过反射获取类的父类

    可以通过 Class 类来获取一个类的父类,通过调用 getModifiers 方法来获取一个类的父类。

    1
    2
    3
    Class<Person> personClass = Person.class;
    Class superclass = personClass.getSuperclass();
    System.out.println(superclass.getName());

    运行结果

    1
    java.lang.Object

    以上运行结果表示 Person 类的父类是 Object 类,可以看到 superclass 对象其实就是一个 Class 类的实例,所以也可以继续在这个对象上进行反射操作。

    通过反射获取类的实现接口

    可以通过 Class 类来获取一个类的父类,通过调用 getInterfaces 方法来获取一个类实现的接口。

    1
    2
    3
    Class<Person> personClass = Person.class;
    Class<?>[] interfaces = personClass.getInterfaces();
    System.out.println(Arrays.toString(interfaces));

    运行结果

    1
    [interface cn.mghio.blogmghiocode.reflect.IPerson]

    Java 中一个类可以实现多个接口,因此 getInterfaces 方法返回一个 Class 数组,在 Java 中接口也同样有对应的 Class 对象。这个方法需要注意的是,getInterfaces 方法仅仅只返回当前类所实现的接口。当前类的父类如果实现了接口,这些接口是不会在返回的 Class 集合中的,尽管实际上当前类其实已经实现了父类接口。

    通过反射获取泛型信息

    当我们在声明一个类或者接口的时候可以指定它可以参数化,常用的 List 接口就是一个参数化接口的例子。比如想要检查 List 接口的参数化类型,我们是没有办法能知道它具体的参数化类型是什么。这个类型就可以是一个应用中所有的类型。但是,当你检查一个使用了被参数化的类型的变量或者方法,你可以获得这个被参数化类型的具体参数。
    第 ① 种 泛型方法返回类型 当你获得了 Method 对象,那么就可以获取到这个方法的泛型返回类型信息。如果方法是在一个被参数化类型之中(例如: T foo()),那么将无法获得它的具体类型,但是如果方法返回的是一个泛型类(例如:List foo()),那么就可以获得这个泛型类的具体参数化类型。下面这个例子中的类定义了一个返回类型是泛型的方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * @author mghio
    * @date: 2019-12-29
    * @version: 1.0
    * @description: 通过反射获取泛型信息
    * @since JDK 1.8
    */
    public class ReflectGenericDemo {

    protected List<Integer> stringList = Arrays.asList(2, 55, 3, 90, 81);

    public List<Integer> getStringList(){
    return this.stringList;
    }

    }

    我们可以获取上面这个类 ReflectGenericDemo 的方法 getStringList 的泛型返回类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

    /**
    * @author mghio
    * @date: 2019-12-29
    * @version: 1.0
    * @description: 通过反射获取泛型信息
    * @since JDK 1.8
    */
    public class ReflectGenericDemoTests {

    @Test
    public void testMethodReturnGenericType() throws NoSuchMethodException {
    Class<ReflectGenericDemo> reflectClass = ReflectGenericDemo.class;
    Method method = reflectClass.getMethod("getStringList", (Class<?>) null);
    Type returnType = method.getGenericReturnType();
    if (returnType instanceof ParameterizedType) {
    ParameterizedType type = (ParameterizedType) returnType;
    Type[] typeArguments = type.getActualTypeArguments();
    for (Type typeArgument : typeArguments) {
    Class typeArgumentClass = (Class) typeArgument;
    System.out.println("typeArgumentClass = " + typeArgumentClass);
    }
    }
    }

    }

    运行结果

    1
    typeArgumentClass = class java.lang.Integer

    typeArguments 数组只有一个值,这个数组中唯一的值是 IntegerClass 类的实例,同时 Class 类也实现了 Type 接口。

    第 ② 种 泛型方法返回类型 泛型方法参数类型,我们也可以通过反射来获取方法参数的泛型类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    /**
    * @author mghio
    * @date: 2019-12-29
    * @version: 1.0
    * @description: 通过反射获取泛型信息
    * @since JDK 1.8
    */
    public class ReflectGenericDemo {

    protected List<Integer> stringList = Arrays.asList(2, 55, 3, 90, 81);

    public void setStringList(List<Integer> stringList) {
    this.stringList = stringList;
    }
    }

    可以通过以下方式获取方法参数的泛型类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28

    /**
    * @author mghio
    * @date: 2019-12-29
    * @version: 1.0
    * @description: 通过反射获取泛型信息
    * @since JDK 1.8
    */
    public class ReflectGenericDemoTests {

    @Test
    public void testMethodParameterGenericType() throws NoSuchMethodException {
    Class<ReflectGenericDemo> reflectClass = ReflectGenericDemo.class;
    Method method = reflectClass.getMethod("setStringList", List.class);
    Type[] genericParameterTypes = method.getGenericParameterTypes();
    for (Type genericParameterType : genericParameterTypes) {
    if (genericParameterType instanceof ParameterizedType) {
    ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
    Type[] parameterArgTypes = parameterizedType.getActualTypeArguments();
    for (Type parameterArgType : parameterArgTypes) {
    Class parameterArgClass = (Class) parameterArgType;
    System.out.println("parameterArgClass = " + parameterArgClass);
    }
    }
    }
    }

    }

    运行结果

    1
    parameterArgClass = class java.lang.Integer

    第 ③ 种 泛型变量类型 可以通过反射来访问类中定义变量的泛型类型,不管这个变量是一个类的静态成员变量或是实例成员变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * @author mghio
    * @date: 2019-12-29
    * @version: 1.0
    * @description: 通过反射获取泛型信息
    * @since JDK 1.8
    */
    public class ReflectGenericDemo {

    private List<Integer> stringList = Arrays.asList(2, 55, 3, 90, 81);

    }

    我们可以通过以下代码来获取类 ReflectGenericDemo 的私有变量 stringList 的泛型变量类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

    /**
    * @author mghio
    * @date: 2019-12-29
    * @version: 1.0
    * @description: 通过反射获取泛型信息
    * @since JDK 1.8
    */
    public class ReflectGenericDemoTests {

    @Test
    public void testFieldGenericType() throws NoSuchFieldException {
    Class<ReflectGenericDemo> reflectClass = ReflectGenericDemo.class;
    Field field = reflectClass.getDeclaredField("stringList");
    Type type = field.getGenericType();
    if (type instanceof ParameterizedType) {
    ParameterizedType fieldGenericType = (ParameterizedType) type;
    Type[] fieldGenericTypes = fieldGenericType.getActualTypeArguments();
    for (Type genericType : fieldGenericTypes) {
    Class fieldGenericTypeClass = (Class) genericType;
    System.out.println(fieldGenericTypeClass);
    }
    }
    }

    }

    运行结果

    1
    class java.lang.Integer

    数组 fieldGenericTypes 只有一个元素,它代表类 IntegerClass 类的实例。我们可以得出通过反射获取泛型信息的套路都是先获取 Class 类对象,然后通过该对象获取相应的类,如果是要获取变量的泛型信息就先获取到 Field 类,如果是要获取方法的泛型信息就先获取到 Method 类,最后再通过是否是 ParameterizedType 的实例来判断是否是泛型类型。

    总结

    我们介绍了 Java 泛型的基本使用,反射可能在我们日常的工作中不怎么接触到,但是,在很多框架中都有运用,比如,SpringIOC/DI 也是反射;还有 JDBCclassForName 也是反射。所有深入了解 Java 反射机制很有必要。

    方法描述
    Constructor getConstructor(Class[] params)根据构造方法的参数,返回一个 public 类型的构造方法
    Constructor getConstructors()返回所有 public 类型的构造方法数组
    Constructor getDeclaredConstructor(Class[] params)根据构造方法的参数,返回一个具体的构造方法(所有的类型)
    Constructor getDeclaredConstructors()返回该类中所有的构造方法数组(所有的类型)
    Method getMethod(String name, Class[] params)根据方法名和参数,返回一个 public 类型的方法
    Method[] getMethods()返回所有 public 类型的方法数组
    Method getDeclaredMethod(String name, Class[] params)根据方法名和参数,返回一个具体的方法(所有的类型)
    Method[] getDeclaredMethods()返回该类中的所有的方法数组(所有的类型)
    Field getField(String name)根据变量名,返回一个 public 类型的成员变量
    Field[] getFields()返回 public 类型的成员变量的数组
    Field getDeclaredField(String name)根据变量名,返回一个成员变量(所有的类型)
    Field[] getDelcaredField()返回所有成员变量组成的数组(所有的类型)
    ]]> - - - - <h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>在 <code>Java</code> 中有两种方式可以让我们在运行时识别对象和类的信息。一种是 <code>RTTI</code>(运行时类型识别:Run-Time Type Identification),它假定了我们在编译时已经知道了所有的类型;另一种是我们本文要说的<code>反射机制</code>,它允许我们在运行时获取和使用类的信息。无论是 <code>RTTI</code> 还是<code>反射</code>,其本质都是一样的,都是去动态的获取类的信息。它们唯一不同的是,<code>RTTI</code> 在编译时期知道要解析的类型,而<code>反射</code>是在运行时才知道要解析的类型。</p> -<h4 id="反射概述"><a href="#反射概述" class="headerlink" title="反射概述"></a>反射概述</h4><p>反射就是把 <code>Java</code> 类中的各个部分(属性、方法、构造方法等)映射成一个个对象。<code>Class</code> 类与 <code>java.lang.reflect</code> 类库一起对反射的概念提供了支持,类库中包含了 <code>Field</code>、<code>Method</code> 及 <code>Constructor</code> 类,每个类都实现了 <code>Member</code> 接口。这些类型的对象都是由 <code>JVM</code> 运行时创建的,用来表示未知类里对应的成员。这样我们就可以使用 <code>Constructor</code> 创建新的对象,用 <code>get</code> 和 <code>set</code> 方法读取和修改类中与 <code>Field</code> 对象关联的字段,用 <code>invoke</code> 方法调用类中与 <code>Method</code> 对象关联的方法等。<br><code>Java</code> 反射机制是在运行状态中的,对于任意一个类我们可以通过反射获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。重要的是,要认识到反射机制并没有什么特别之处,当我们通过反射和一个未知类型的对象打交道时,<code>JVM</code> 只是简单的对这个对象做检查,看它属于哪个类,在用它做其它事情之前必须先加载那个类 <code>Class</code> 对象。所以那个类的字节码文件对象对于 <code>JVM</code> 来说必须是可获取的,要么在本地机器上,要么通过网络获取。</p> - - - - - - - - - diff --git a/baidusitemap.xml b/baidusitemap.xml index f361a3c2..cbbb0190 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -1,6 +1,9 @@ + https://www.mghio.cn/post/24cb2421.html + 2020-11-29 + https://www.mghio.cn/post/558ca0bd.html 2020-10-08 diff --git a/categories/JDK/Java/index.html b/categories/JDK/Java/index.html index 6c1c5f73..97df5c4d 100644 --- a/categories/JDK/Java/index.html +++ b/categories/JDK/Java/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index dd4ed64e..8876ada0 100644 --- "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/JDK/index.html b/categories/JDK/index.html index 01edd1f4..dbc9c738 100644 --- a/categories/JDK/index.html +++ b/categories/JDK/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/Bloom-filter/index.html b/categories/Java/Bloom-filter/index.html index a70835be..afa97d42 100644 --- a/categories/Java/Bloom-filter/index.html +++ b/categories/Java/Bloom-filter/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/GC/index.html b/categories/Java/GC/index.html index ba411f3f..8dc03393 100644 --- a/categories/Java/GC/index.html +++ b/categories/Java/GC/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/Guava/String/index.html b/categories/Java/Guava/String/index.html index fe3e2f0b..d31d83a7 100644 --- a/categories/Java/Guava/String/index.html +++ b/categories/Java/Guava/String/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/Guava/index.html b/categories/Java/Guava/index.html index 95cec47c..b7256181 100644 --- a/categories/Java/Guava/index.html +++ b/categories/Java/Guava/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/IDEA/index.html b/categories/Java/IDEA/index.html index 304ceeb5..17ec6680 100644 --- a/categories/Java/IDEA/index.html +++ b/categories/Java/IDEA/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" index fc72a422..91661e7e 100644 --- "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" +++ "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/IO\346\250\241\345\236\213/index.html" "b/categories/Java/IO\346\250\241\345\236\213/index.html" index f052515a..8dd997b8 100644 --- "a/categories/Java/IO\346\250\241\345\236\213/index.html" +++ "b/categories/Java/IO\346\250\241\345\236\213/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/JVM/index.html b/categories/Java/JVM/index.html index 2a4ed421..859ce690 100644 --- a/categories/Java/JVM/index.html +++ b/categories/Java/JVM/index.html @@ -413,7 +413,7 @@

    - 32 + 33 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git a/categories/Java/List/index.html b/categories/Java/List/index.html index 37458cd1..de5a8673 100644 --- a/categories/Java/List/index.html +++ b/categories/Java/List/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/Spring/index.html b/categories/Java/Spring/index.html new file mode 100644 index 00000000..f84f1a9a --- /dev/null +++ b/categories/Java/Spring/index.html @@ -0,0 +1,1254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: Spring | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/Java/index.html b/categories/Java/index.html index 957efaba..32fdc1a7 100644 --- a/categories/Java/index.html +++ b/categories/Java/index.html @@ -309,6 +309,32 @@

    Java分类 + + + + + +
    @@ -541,32 +567,6 @@

    - - - - - - @@ -625,7 +625,7 @@

    - 32 + 33 日志 @@ -636,7 +636,7 @@

    @@ -647,7 +647,7 @@

    diff --git a/categories/Java/page/2/index.html b/categories/Java/page/2/index.html index 58bf8cfb..dc6c1f52 100644 --- a/categories/Java/page/2/index.html +++ b/categories/Java/page/2/index.html @@ -309,6 +309,32 @@

    Java分类 + + + + + +
    @@ -541,32 +567,6 @@

    - - - - - - @@ -625,7 +625,7 @@

    - 32 + 33 日志 @@ -636,7 +636,7 @@

    @@ -647,7 +647,7 @@

    diff --git a/categories/Java/page/3/index.html b/categories/Java/page/3/index.html index 89b63421..3a3fd0bc 100644 --- a/categories/Java/page/3/index.html +++ b/categories/Java/page/3/index.html @@ -309,6 +309,32 @@

    Java分类 + + + + + +
    @@ -521,7 +547,7 @@

    - 32 + 33 日志 @@ -532,7 +558,7 @@

    @@ -543,7 +569,7 @@

    diff --git a/categories/Java/unit-test/index.html b/categories/Java/unit-test/index.html index 606f59ba..e0bb99c7 100644 --- a/categories/Java/unit-test/index.html +++ b/categories/Java/unit-test/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Java/unit-test/mockito/index.html b/categories/Java/unit-test/mockito/index.html index d1e8e0cb..c2b7fc9a 100644 --- a/categories/Java/unit-test/mockito/index.html +++ b/categories/Java/unit-test/mockito/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\345\216\237\347\220\206/index.html" "b/categories/Java/\345\216\237\347\220\206/index.html" index 8f0e0e34..23a016c2 100644 --- "a/categories/Java/\345\216\237\347\220\206/index.html" +++ "b/categories/Java/\345\216\237\347\220\206/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\345\217\215\345\260\204/index.html" "b/categories/Java/\345\217\215\345\260\204/index.html" index baf67cfa..15f3cc38 100644 --- "a/categories/Java/\345\217\215\345\260\204/index.html" +++ "b/categories/Java/\345\217\215\345\260\204/index.html" @@ -413,7 +413,7 @@

    - 32 + 33 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" index b9eb6346..35aaf5b7 100644 --- "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" @@ -413,7 +413,7 @@

    - 32 + 33 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git "a/categories/Java/\345\271\266\345\217\221/index.html" "b/categories/Java/\345\271\266\345\217\221/index.html" index b0a603ab..ba65307a 100644 --- "a/categories/Java/\345\271\266\345\217\221/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/index.html" @@ -439,7 +439,7 @@

    - 32 + 33 日志 @@ -450,7 +450,7 @@

    @@ -461,7 +461,7 @@

    diff --git "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" index 1f343af1..6fe96d2b 100644 --- "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\345\274\202\346\255\245/index.html" "b/categories/Java/\345\274\202\346\255\245/index.html" index b0a4c145..fb64fba6 100644 --- "a/categories/Java/\345\274\202\346\255\245/index.html" +++ "b/categories/Java/\345\274\202\346\255\245/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" index d750b8db..08bfa164 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 5459f3a6..a25277a3 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" index 3f482c7d..4b75f36b 100644 --- "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" +++ "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" @@ -413,7 +413,7 @@

    - 32 + 33 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git "a/categories/Java/\347\274\223\345\255\230/index.html" "b/categories/Java/\347\274\223\345\255\230/index.html" index b405556f..6fd6b560 100644 --- "a/categories/Java/\347\274\223\345\255\230/index.html" +++ "b/categories/Java/\347\274\223\345\255\230/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Java/\351\207\215\346\236\204/index.html" "b/categories/Java/\351\207\215\346\236\204/index.html" index bbbe1f31..128b7271 100644 --- "a/categories/Java/\351\207\215\346\236\204/index.html" +++ "b/categories/Java/\351\207\215\346\236\204/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/Linux\347\254\224\350\256\260/index.html" "b/categories/Linux\347\254\224\350\256\260/index.html" index 1f3fe42a..455cb031 100644 --- "a/categories/Linux\347\254\224\350\256\260/index.html" +++ "b/categories/Linux\347\254\224\350\256\260/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/RabbitMQ/Java/index.html b/categories/RabbitMQ/Java/index.html index 33c59e75..18a21bbb 100644 --- a/categories/RabbitMQ/Java/index.html +++ b/categories/RabbitMQ/Java/index.html @@ -413,7 +413,7 @@

    - 32 + 33 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git a/categories/RabbitMQ/index.html b/categories/RabbitMQ/index.html index 4b97d22e..d707419b 100644 --- a/categories/RabbitMQ/index.html +++ b/categories/RabbitMQ/index.html @@ -413,7 +413,7 @@

    - 32 + 33 日志 @@ -424,7 +424,7 @@

    @@ -435,7 +435,7 @@

    diff --git a/categories/Spring/Java/index.html b/categories/Spring/Java/index.html index 44824e0f..e4d9d566 100644 --- a/categories/Spring/Java/index.html +++ b/categories/Spring/Java/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/Spring/index.html b/categories/Spring/index.html index 4831cff6..8937eec7 100644 --- a/categories/Spring/index.html +++ b/categories/Spring/index.html @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/categories/index.html b/categories/index.html index 090e8329..48a12d74 100644 --- a/categories/index.html +++ b/categories/index.html @@ -317,10 +317,10 @@

    @@ -378,7 +378,7 @@

    - 32 + 33 日志 @@ -389,7 +389,7 @@

    @@ -400,7 +400,7 @@

    diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" index 16e27bb6..37501f90 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 7980cd95..8d5e9165 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -387,7 +387,7 @@

    - 32 + 33 日志 @@ -398,7 +398,7 @@

    @@ -409,7 +409,7 @@

    diff --git a/css/main.css b/css/main.css index a3a0896e..ea650fed 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #e57fec; + background: #cb44bb; } .links-of-blogroll { font-size: 13px; diff --git a/index.html b/index.html index 10065b01..6319c3ad 100644 --- a/index.html +++ b/index.html @@ -310,7 +310,7 @@

    Java 搬运工 & 终身学习
    - +

    @@ -456,10 +456,10 @@

    -

    前言

    使用 Java 作为第一开发语言的朋友们,相信大家或多或少的都使用过 Spring 这个开发框架,可以说 Spring 框架真是我们 Java 程序员的春天,在 SpringBean 是其中最重要的概念之一,是学习其它高级知识的基础,Bean 本质上其实就是一个被 Spring 框架管理的对象,今天我们来看看 BeanSpring 中是如何被造出来的。

    +

    前言

    之前在 上篇 提到过会实现一个简易版的 IoCAOP,今天它终于来了。。。相信对于使用 Java 开发语言的朋友们都使用过或者听说过 Spring 这个开发框架,绝大部分的企业级开发中都离不开它,通过 官网 可以了解到其生态非常庞大,针对不同方面的开发提供了一些解决方案,可以说 Spring 框架的诞生是对 Java 开发人员的一大福利,自 2004 年发布以来,Spring 为了解决一些企业开发中的痛点先后引入了很多的特性和功能,其中最重要的就是我们经常听到的 IoCAOP 特性,由于涉及到的知识和细节比较多,会分为几篇文章来介绍,今天这篇(也是第一篇)我们来看看如何实现基于 XML 配置方式的 Setter 注入

    - + 阅读全文 »
    @@ -512,7 +512,7 @@

    前言 - +

    @@ -658,17 +658,10 @@

    -

    一、前言

    不同存储技术的访问时间差异很大,从 计算机层次结构 可知,通常情况下,从高层往底层走,存储设备变得更慢、更便宜同时体积也会更大,CPU 和内存之间的速度存在着巨大的差异,此时就会想到计算机科学界中一句著名的话:计算机科学的任何一个问题,都可以通过增加一个中间层来解决。

    -

    二、引入缓存层

    为了解决速度不匹配问题,可以通过引入一个缓存中间层来解决问题,但是也会引入一些新的问题。现代计算机系统中,从硬件到操作系统、再到一些应用程序,绝大部分的设计都用到了著名的局部性原理,局部性通常有如下两种不同的形式:

    -
    -

    时间局部性:在一个具有良好的时间局部性的程序当中,被引用过一次的内存位置,在将来一个不久的时间内很可能会被再次引用到。

    -
    -
    -

    空间局部性:在一个具有良好的空间局部性的程序当中,一个内存位置被引用了一次,那么在不久的时间内很可能会引用附近的位置。

    -
    +

    前言

    使用 Java 作为第一开发语言的朋友们,相信大家或多或少的都使用过 Spring 这个开发框架,可以说 Spring 框架真是我们 Java 程序员的春天,在 SpringBean 是其中最重要的概念之一,是学习其它高级知识的基础,Bean 本质上其实就是一个被 Spring 框架管理的对象,今天我们来看看 BeanSpring 中是如何被造出来的。

    - + 阅读全文 »
    @@ -721,7 +714,7 @@

    - +

    -

    +

    @@ -867,12 +860,17 @@

    -

    现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑。

    -

    第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作

    例如我们执行以下代码:

    -
    1
    2
    List<String> strings = Arrays.asList("m", "g");
    strings.add("h");
    +

    一、前言

    不同存储技术的访问时间差异很大,从 计算机层次结构 可知,通常情况下,从高层往底层走,存储设备变得更慢、更便宜同时体积也会更大,CPU 和内存之间的速度存在着巨大的差异,此时就会想到计算机科学界中一句著名的话:计算机科学的任何一个问题,都可以通过增加一个中间层来解决。

    +

    二、引入缓存层

    为了解决速度不匹配问题,可以通过引入一个缓存中间层来解决问题,但是也会引入一些新的问题。现代计算机系统中,从硬件到操作系统、再到一些应用程序,绝大部分的设计都用到了著名的局部性原理,局部性通常有如下两种不同的形式:

    +
    +

    时间局部性:在一个具有良好的时间局部性的程序当中,被引用过一次的内存位置,在将来一个不久的时间内很可能会被再次引用到。

    +
    +
    +

    空间局部性:在一个具有良好的空间局部性的程序当中,一个内存位置被引用了一次,那么在不久的时间内很可能会引用附近的位置。

    +
    - + 阅读全文 »
    @@ -925,7 +923,7 @@

    - +

    @@ -1071,11 +1069,12 @@

    -

    上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

    -

    消息生产者发送的消息不可达时如何处理

    RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

    +

    现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑。

    +

    第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作

    例如我们执行以下代码:

    +
    1
    2
    List<String> strings = Arrays.asList("m", "g");
    strings.add("h");
    - + 阅读全文 »
    @@ -1128,7 +1127,7 @@

    - +

    -

    +

    @@ -1274,11 +1273,11 @@

    -

    什么是消息队列(MQ)

    消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

    -

    什么场景下考虑使用消息队列

    从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

    +

    上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念。

    +

    消息生产者发送的消息不可达时如何处理

    RabbitMQ 提供了消息在传递过程中无法发送到一个队列(比如根据自己的类型和路由键没有找到匹配的队列)时将消息回传给消息发送方的功能,使用 RabbitMQ 的客户端提供 channel.basicPublish 方法的两个参数 mandatoryimmediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器可以将无法发送的消息存储起来处理,不用重新传回给发送方。

    - + 阅读全文 »
    @@ -1331,7 +1330,7 @@

    - +

    -

    +

    @@ -1488,10 +1476,11 @@

    -

    前言

    Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
    Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

    +

    什么是消息队列(MQ)

    消息是在不同应用间传递的数据。这里的消息可以非常简单,比如只包含字符串,也可以非常复杂,包含多个嵌套的对象。消息队列(Message Queue)简单来说就是一种应用程序间的通讯方式,消息发送后立即返回,然后由消息系统保证消息的可靠性传输,消息生产者只需要把消息发到 MQ 中就可以了,不需要关心消息的消费,同样,消息消费者只管从 MQ 中拉取消息而不管是谁生产的消息,通过这样的一个“互相不知道对象存在”模式,将消息的生产者和消息的消费者解耦了。

    +

    什么场景下考虑使用消息队列

    从上面可以知道,消息队列是一种应用间的异步协作机制,那么我们什么时候需要用到 MQ 呢?以常见的订单系统为例,当用户点击「下单」后的业务逻辑可能包括:扣减库存、生成相应订单数据、发短信通知等。在项目和业务发展初期上面这些逻辑可能放在一起执行,随着业务的发展订单量的增加,需要提升系统服务的性能,此时就可以将一些不需要立即生效的操作拆分出来异步执行,比如发送短信通知等。这种场景下就可以使用 MQ ,在下单主流程(比如扣减库存、生成订单数据等)完成之后发送一条消息到 MQ 让主流程快速走完,然后由另外一个线程拉取 MQ 的消息,执行相应的业务逻辑。这里的例子主要是用消息队列来解耦。

    - + 阅读全文 »
    @@ -1544,7 +1533,7 @@

    前言 - +

    @@ -1701,10 +1690,10 @@

    -

    前言

    在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

    +

    前言

    Java 中通过 来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关键字并不需要去关心锁的获取和释放过程,但是在提供方便的同时也意味着其灵活性的下降。例如,有这样的一个场景,先获取锁 A,然后再获取锁 B,当锁 B 获取到之后,释放锁 A 同时获取锁 C,当获取锁 C 后,再释放锁 B 同时获取锁 D,依次类推,像这种比较复杂的场景,使用 synchronized 关键字就比较难实现了。
    Java SE 5 之后,新增加了 Lock 接口和一系列的实现类来提供和 synchronized 关键字一样的功能,它需要我们显示的进行锁的获取和释放,除此之外还提供了可响应中断的锁获取操作以及超时获取锁等同步特性。JDK 中提供的 Lock 接口实现类大部分都是聚合一个同步器 AQS 的子类来实现多线程的访问控制的,下面我们看看这个构建锁和其它同步组件的基础框架——队列同步器 AQS(AbstractQueuedSynchronizer)

    - + 阅读全文 »
    @@ -1757,7 +1746,7 @@

    前言 - +

    @@ -1914,10 +1903,10 @@

    -

    前言

    对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

    +

    前言

    在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

    - + 阅读全文 »
    @@ -1970,7 +1959,7 @@

    前言 - +

    @@ -2116,11 +2116,10 @@

    -

    前言

    在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

    -

    同步与异步

    首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

    +

    前言

    对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

    - + 阅读全文 »
    @@ -2173,7 +2172,7 @@

    - +

    -

    +

    @@ -2319,14 +2318,11 @@

    -

    前言

    在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

    -

    原理

    布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

    -
    -

    A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

    -
    +

    前言

    在网上看到过很多讲有关同步与异步阻塞与非阻塞的文章,但是很多都是抛出一堆相关定义,看了之后还是云里雾里的,对这几个概念还是不能很好的去区分它们。本文通过通俗易懂的语言和相关例子让你深入理解其本质。

    +

    同步与异步

    首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

    - + 阅读全文 »
    @@ -2418,7 +2414,7 @@

    原理 - 32 + 33 日志 @@ -2429,7 +2425,7 @@

    原理 - 33 + 34 分类 @@ -2440,7 +2436,7 @@

    原理 - 29 + 30 标签 diff --git a/page/2/index.html b/page/2/index.html index 48aaf23a..88887867 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -310,7 +310,7 @@

    Java 搬运工 & 终身学习
    - +

    @@ -467,15 +456,14 @@

    -

    前言

    Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

    -

    如何使用

    Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

    -
    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.2-jre</version>
    </dependency>
    - -

    对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

    -
    1
    compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
    +

    前言

    在日常工作中,经常要判断一个元素是否在一个集合中。假设你要向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址,此时你手上有大约 1000 万个恶意 URL 的数据集,你该如何实现该功能。按我之前的思维,要判断一个元素在不在当前的数据集中,首先想到的就是使用 hash table,通过哈希函数运行所有的恶意网址以获取其哈希值,然后创建出一个哈希表(数组)。这个方案有个明显的缺点,就是需要存储原始元素本身,内存占用大,而我们其实主要是关注 当前输入的网址在不在我们的恶意 URL 数据集中,也就是之前的恶意 URL 数据集的具体值是什么并不重要,通过吴军老师的《数学之美》了解到,对于这种场景大数据领域有个用于在海量数据情况下判断某个元素是否已经存在的算法很适合,关键的一点是该算法并不存储元素本身,这个算法就是 — 布隆过滤器(Bloom filter)。

    +

    原理

    布隆过滤器是由巴顿.布隆于一九七零年提出的,在 维基百科 中的描述如下:

    +
    +

    A Bloom filter is a space-efficient probabilistic data structure, conceived by Burton Howard Bloom in 1970, that is used to test whether an element is a member of a set.

    +
    - + 阅读全文 »
    @@ -528,7 +516,7 @@

    - +

    -

    +

    @@ -674,11 +673,15 @@

    -

    前言

    在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

    -

    什么是 CompletableFuture

    CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

    +

    前言

    Java 里字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率,今天要介绍的主角是 Google 开源的一个核心 JavaGuava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,我们将学习使用 Guava 中的 StringsSplitter 字符串操作工具类。

    +

    如何使用

    Google Guava 会同步到 Maven Central 中,所以,如果你是 Maven 项目的话只需要在 pom.xml 文件中引入如下依赖即可:

    +
    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.2-jre</version>
    </dependency>
    + +

    对于 Gradle 项目在 build.gradle 中引入如下依赖即可:

    +
    1
    compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
    - + 阅读全文 »
    @@ -731,7 +734,7 @@

    - +

    -

    +

    @@ -877,11 +880,11 @@

    -

    前言

    在日常生活中,当我们买的水果放久了之后会发出一种难闻的气味(“坏味道”),这个时候我们就应该把它扔掉。同样,代码也有“坏味道”,当然确定什么是和不是代码“坏味道”是主观的,它会随语言、开发人员和开发方法的不同而不同。在工作当中,很多时候都是在维护之前的项目和在此基础上增加一些新功能,为了能让项目代码易于理解和维护,要时刻注意代码中的“坏味道”,当发现代码如果有坏味道了,要及时去重构它使其变成优秀的整洁的代码。本文列举代码中一些常见的“坏味道”和相应的重构方案。

    -

    过长方法 (Long Method)

    这种“坏味道”表现为方法代码行数过长,方法行数越长,就越难以理解和维护它。一个比较有用的方案就是当你觉得需要对方法中的内容加注释的时候,你应该将这个代码段作为一个新方法提取出来,哪怕有时候仅仅是一行代码也可以这么做,而且方法的命名要尽量做到见名知意,如果局部变量和参数干扰到方法的提取,则可以使用引入参数对象来进行提取。一般情况下,方法中条件运算符和循环是可以将代码移至单独方法的一个很好的代码段,对于条件运算符,可以尝试分解条件,如果方法出现循环,可以尝试提取方法。

    +

    前言

    在我们的意识里,同步执行的程序都比较符合人们的思维方式,而异步的东西通常都不好处理。在异步计算的情况下,以回调表示的动作往往会分散在代码中,也可能相互嵌套在内部,如果需要处理其中一个步骤中可能发生的错误时,情况变得更加糟糕。Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,这让我们编写清晰可读的异步代码变得更加容易,该类功能非常强大,包含了超过 50 多个方法。。。

    +

    什么是 CompletableFuture

    CompletableFuture 类的设计灵感来自于 Google GuavaListenableFuture 类,它实现了 FutureCompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

    - + 阅读全文 »
    @@ -934,7 +937,7 @@

    - +

    -

    +

    @@ -2443,7 +2446,7 @@

    - 29 + 30 标签 diff --git a/page/3/index.html b/page/3/index.html index 722f3708..be2018ab 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -305,6 +305,209 @@

    Java 搬运工 & 终身学习 +
    + + + +
    + + + + + + + +
    + + + +

    + +

    + + + +
    + + + + + +
    + + + + + + +

    前言

    Java 中有两种方式可以让我们在运行时识别对象和类的信息。一种是 RTTI(运行时类型识别:Run-Time Type Identification),它假定了我们在编译时已经知道了所有的类型;另一种是我们本文要说的反射机制,它允许我们在运行时获取和使用类的信息。无论是 RTTI 还是反射,其本质都是一样的,都是去动态的获取类的信息。它们唯一不同的是,RTTI 在编译时期知道要解析的类型,而反射是在运行时才知道要解析的类型。

    +

    反射概述

    反射就是把 Java 类中的各个部分(属性、方法、构造方法等)映射成一个个对象。Class 类与 java.lang.reflect 类库一起对反射的概念提供了支持,类库中包含了 FieldMethodConstructor 类,每个类都实现了 Member 接口。这些类型的对象都是由 JVM 运行时创建的,用来表示未知类里对应的成员。这样我们就可以使用 Constructor 创建新的对象,用 getset 方法读取和修改类中与 Field 对象关联的字段,用 invoke 方法调用类中与 Method 对象关联的方法等。
    Java 反射机制是在运行状态中的,对于任意一个类我们可以通过反射获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。重要的是,要认识到反射机制并没有什么特别之处,当我们通过反射和一个未知类型的对象打交道时,JVM 只是简单的对这个对象做检查,看它属于哪个类,在用它做其它事情之前必须先加载那个类 Class 对象。所以那个类的字节码文件对象对于 JVM 来说必须是可获取的,要么在本地机器上,要么通过网络获取。

    + +
    + + 阅读全文 » + +
    + + + +
    + + + + + + + + + + + + +
    + + + + + + + + +
    + +
    +
    + + + +
    + + + + + + + + + + + - - - - - - - - - - - -
    - - - -
    - - - - - - - -
    - - - -

    - -

    - - - -
    - - - - - -
    - - - - - - -

    1.1 split 的坑

    前几天在公司对通过 FTP 方式上传的数据文件按照事先规定的格式进行解析后入库,代码的大概实现思路是这样的:先使用流进行文件读取,对文件的每一行数据解析封装成一个个对象,然后进行入库操作。本以为很简单的一个操作,然后写完代码后自己测试发现对文件的每一行进行字符串分割的时候存在问题,在这里做个简单的记录总结。在 Java 中使用 split 方法对字符串进行分割是经常使用的方法,经常在一些文本处理、字符串分割的逻辑中,需要按照一定的分隔符进行分割拆解。这样的功能,大多数情况下我们都会使用 String 中的 split 方法。关于这个方法,稍不注意很容易踩坑。

    -

    (1)split 的参数是正则表达式
    首先一个常见的问题,就是忘记了 String 的 split 方法的参数不是普通的字符串,而是正则表达式,例如下面的这两种使用方式都达不到我们的预期:

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * @author mghio
    * @date: 2019-10-13
    * @version: 1.0
    * @description: Java 字符串 split 踩坑记
    * @since JDK 1.8
    */
    public class JavaStringSplitTests {

    @Test
    public void testStringSplitRegexArg() {
    System.out.println(Arrays.toString("m.g.h.i.o".split(".")));
    System.out.println(Arrays.toString("m|g|h|i|o".split("|")));
    }

    }
    - -
    - - 阅读全文 » - -
    - - - -
    - - - - - - - - - - - -
    @@ -2453,7 +2463,7 @@

    - 33 + 34 分类 @@ -2464,7 +2474,7 @@

    - 29 + 30 标签 diff --git a/page/4/index.html b/page/4/index.html index b538adcf..65d66967 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -305,6 +305,199 @@

    Java 搬运工 & 终身学习 +
    + + + +
    + + + + + + + +
    + + + +

    + +

    + + + +
    + + + + + +
    + + + + + + +

    1.1 split 的坑

    前几天在公司对通过 FTP 方式上传的数据文件按照事先规定的格式进行解析后入库,代码的大概实现思路是这样的:先使用流进行文件读取,对文件的每一行数据解析封装成一个个对象,然后进行入库操作。本以为很简单的一个操作,然后写完代码后自己测试发现对文件的每一行进行字符串分割的时候存在问题,在这里做个简单的记录总结。在 Java 中使用 split 方法对字符串进行分割是经常使用的方法,经常在一些文本处理、字符串分割的逻辑中,需要按照一定的分隔符进行分割拆解。这样的功能,大多数情况下我们都会使用 String 中的 split 方法。关于这个方法,稍不注意很容易踩坑。

    +

    (1)split 的参数是正则表达式
    首先一个常见的问题,就是忘记了 String 的 split 方法的参数不是普通的字符串,而是正则表达式,例如下面的这两种使用方式都达不到我们的预期:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * @author mghio
    * @date: 2019-10-13
    * @version: 1.0
    * @description: Java 字符串 split 踩坑记
    * @since JDK 1.8
    */
    public class JavaStringSplitTests {

    @Test
    public void testStringSplitRegexArg() {
    System.out.println(Arrays.toString("m.g.h.i.o".split(".")));
    System.out.println(Arrays.toString("m|g|h|i|o".split("|")));
    }

    }
    + +
    + + 阅读全文 » + +
    + + + +
    + + + + + + + + + + + + +
    + + + + + + + + +
    + +
    +
    + + + +
    + + + + + + + + + + +
    @@ -731,7 +924,7 @@

    - 32 + 33 日志 @@ -742,7 +935,7 @@

    @@ -753,7 +946,7 @@

    diff --git a/post/102cd3d9.html b/post/102cd3d9.html index a8bb8bb4..8e0c6df8 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -847,7 +847,7 @@

    总结 - 32 + 33 日志 @@ -858,7 +858,7 @@

    总结 - 33 + 34 分类 @@ -869,7 +869,7 @@

    总结 - 29 + 30 标签 diff --git a/post/11cb7677.html b/post/11cb7677.html index 3ae04fcc..0331441b 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -698,7 +698,7 @@

    总结 - 32 + 33 日志 @@ -709,7 +709,7 @@

    总结 - 33 + 34 分类 @@ -720,7 +720,7 @@

    总结 - 29 + 30 标签 diff --git a/post/192cb539.html b/post/192cb539.html index 7c0ad484..a1221940 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -762,7 +762,7 @@

    - 32 + 33 日志 @@ -773,7 +773,7 @@

    @@ -784,7 +784,7 @@

    diff --git a/post/24042edf.html b/post/24042edf.html index e861fd36..1390499a 100644 --- a/post/24042edf.html +++ b/post/24042edf.html @@ -770,7 +770,7 @@

    总结 - 32 + 33 日志 @@ -781,7 +781,7 @@

    总结 - 33 + 34 分类 @@ -792,7 +792,7 @@

    总结 - 29 + 30 标签 diff --git a/post/24cb2421.html b/post/24cb2421.html new file mode 100644 index 00000000..80df189b --- /dev/null +++ b/post/24cb2421.html @@ -0,0 +1,1598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 如何实现一个简易版的 Spring - 如何实现 Setter 注入 | mghio + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    +
    +
    +
    + + +
    + + + + + + + + +
    + + + +
    + + + + + + + +
    + + + +

    如何实现一个简易版的 Spring - 如何实现 Setter 注入

    + + + +
    + + + + + +
    + + + + + +

    前言

    之前在 上篇 提到过会实现一个简易版的 IoCAOP,今天它终于来了。。。相信对于使用 Java 开发语言的朋友们都使用过或者听说过 Spring 这个开发框架,绝大部分的企业级开发中都离不开它,通过 官网 可以了解到其生态非常庞大,针对不同方面的开发提供了一些解决方案,可以说 Spring 框架的诞生是对 Java 开发人员的一大福利,自 2004 年发布以来,Spring 为了解决一些企业开发中的痛点先后引入了很多的特性和功能,其中最重要的就是我们经常听到的 IoCAOP 特性,由于涉及到的知识和细节比较多,会分为几篇文章来介绍,今天这篇(也是第一篇)我们来看看如何实现基于 XML 配置方式的 Setter 注入

    + +

    预备知识

    既然是通过 XML 配置文件的方式,首先第一件事就是要读取 XML 文件然后转换为我们需要的数据结构,解析 XML 文件有但不限于这些方式(JDOMXOMdom4j),这里使用的是简单易上手的 dom4j,所你得对其基础知识有一些简单了解,其实都是一些很简单的方法基础使用而已,第二个就是你要有一些 Spring 框架的使用经验,这里实现的简易版本质上是对 Spring 的一个精简后的核心部分的简单实现,是的,没错,你只需要有了这些基础预备知识就可以了。

    +

    基础数据结构抽象

    在开始编码实现前先要做一些简单的构思和设计,首先在 Spring 中把一个被其管理的对象称之为 Bean,然后其它的操作都是围绕这个 Bean 来展开设计的,所以为了能在程序中统一并且规范的表示一个 Bean 的定义,于是第一个接口 BeanDefinition 就出来了,本次需要的一些基本信息包含 Bean 的名称、所属类名称、是否单例、作用域等,如下所示:

    +

    spring-injection-beandefinition-1.png

    +

    现在 BeanDefinition 有了,接下来就是要根据这个 BeanDefinition 去创建出对应的 Bean 实例了,很显然这需要一个 Factory 工厂接口去完成这个创建的工作,这个创建 Bean 的接口命名为 BeanFactory,其提供根据不同条件去创建相对应的 Bean 实例功能(比如 beanId),但是创建的前提是需要先注册这个 BeanDefinition,然后根据一定条件再从中去获取 BeanDefinition,根据 单一职责 原则,这个功能应该由一个新的接口去完成,主要是做注册和获取 BeanDefinition 的工作,故将其命名为 BeanDefinitionRegistry,我们需要的 BeanDefinition 要从哪里获取呢?很显然我们是基于 XML 配置的方式,当然是从 XML 配置文件中获取到的,同样根据单一职责原则,也需要一个类去完成这个事情,将其命名为 XMLBeanDefinitionReader,这部分的整体结构如下所示:

    +

    spring-injection-beanfactory-2.png

    +

    接下来面临的一个问题就是,像 XML 这种配置文件资源要如何表示呢,这些配置对于程序来说是一种资源,可以统一抽象为 Resource,然后提供一个返回资源对应流(InputStream)对象接口,这种资源可以从项目中获取、本地文件获取甚至是从远程获取,它们都是一种 Resource,结构如下:

    +

    spring-injection-resource-3.png

    +

    最后就是要一个提供去组合调用上面的那些类去完成 XML 配置文件解析为 BeanDefinition 并注入到容器中了的功能,担任这程序上下文的职责,将其命名为 ApplicationContext,这里同样也可以根据 Resource 的类型分为多种不同的类,比如:FileSystmXmlApplicationContextClassPathXmlApplicationContext 等,这些内部都有一个将配置文件转换为 Resource 的过程,可以使用 模板方法 抽象出一个公共父类抽象类,如下所示:

    +

    spring-injection-applicationcontext.png

    +

    总结以上分析结果,得出初步类图设计如下:

    +

    spring-injection-all-4.png

    +

    最终要实现 Setter 注入这个目标,可以将其分解为以下两个步骤:

    +
      +
    1. XML 配置文件中的 <bean> 标签解析为 BeanDefinition 并注入到容器中
    2. +
    3. 实现 Setter 注入
    4. +
    +

    下面我们分为这两个部分来分别讲述如何实现。

    +

    配置文件解析

    假设有如下内容的配置文件 applicationcontext-config1.xml:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.e3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="orderService" class="cn.mghio.service.version1.OrderService" />

    </beans>
    + +

    最终需要解析出一个 idorderService 类型为 cn.mghio.service.version1.OrderServiceBeanDefinition,翻译成测试类的话也就是需要让如下测试类可以运行通过:

    +
    1
    2
    3
    4
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    /**
    * @author mghio
    */
    public class BeanFactoryTest {

    private Resource resource;
    private DefaultBeanFactory beanFactory;
    private XmlBeanDefinitionReader reader;

    @BeforeEach
    public void beforeEach() {
    resource = new ClassPathResource("applicationcontext-config1.xml");
    beanFactory = new DefaultBeanFactory();
    reader = new XmlBeanDefinitionReader(beanFactory);
    }

    @Test
    public void testGetBeanFromXmlFile() {
    reader.loadBeanDefinition(resource);
    BeanDefinition bd = beanFactory.getBeanDefinition("orderService");

    assertEquals("cn.mghio.service.version1.OrderService", bd.getBeanClassNam());
    OrderService orderService = (OrderService) beanFactory.getBean("orderService");
    assertNotNull(orderService);
    }

    @Test
    public void testGetBeanFromXmlFileWithInvalidBeanId() {
    assertThrows(BeanCreationException.class, () -> beanFactory.getBean("notExistsBeanId"));
    }

    @Test
    public void testGetFromXmlFilWithFileNotExists() {
    resource = new ClassPathResource("notExists.xml");
    assertThrows(BeanDefinitionException.class, () -> reader.loadBeanDefinition(resource));
    }

    }
    + +

    可以看到这里面的关键就是如何去实现 XmlBeanDefinitionReader 类的 loadBeanDefinition 从配置中加载和注入 BeanDefinition,思考分析后不然发现这里主要是两步,第一步是解析 XML 配置转换为 BeanDefinition,这就需要上文提到的 dom4j 提供的能力了,第二步将解析出来的 BeanDefinition 注入到容器中,通过组合使用 BeanDefinitionRegistry 接口提供注册 BeanDefinition 的能力来完成。读取 XML 配置的类 XmlBeanDefinitionReader 的代码实现很快就可以写出来了,该类部分代码如下所示:

    +
    1
    2
    3
    4
    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
    30
    31
    32
    33
    /**
    * @author mghio
    */
    public class XmlBeanDefinitionReader {

    private static final String BEAN_ID_ATTRIBUTE = "id";
    private static final String BEAN_CLASS_ATTRIBUTE = "class";

    private BeanDefinitionRegistry registry;

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
    this.registry = registry;
    }

    @SuppressWarnings("unchecked")
    public void loadBeanDefinition(Resource resource) {
    try (InputStream is = resource.getInputStream()) {
    SAXReader saxReader = new SAXReader();
    Document document = saxReader.read(is);
    Element root = document.getRootElement(); // <beans>
    Iterator<Element> iterator = root.elementIterator();
    while (iterator.hasNext()) {
    Element element = iterator.next();
    String beanId = element.attributeValue(BEAN_ID_ATTRIBUTE);
    String beanClassName = element.attributeValue(BEAN_CLASS_ATTRIBUTE);
    BeanDefinition bd = new GenericBeanDefinition(beanId, beanClassName);
    this.registry.registerBeanDefinition(beanId, bd);
    }
    } catch (DocumentException | IOException e) {
    throw new BeanDefinitionException("IOException parsing XML document:" + configurationFile, e);
    }
    }
    }
    + +

    然后当调用 BeanFactorygetBean 方法时就可以根据 Bean 的全限定名创建一个实例出来了(PS:暂时不考虑实例缓存),方法实现主要代码如下:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public Object getBean(String beanId) {
    BeanDefinition bd = getBeanDefinition(beanId);
    if (null == bd) {
    throw new BeanCreationException("BeanDefinition does not exists, beanId:" + beanId);
    }
    ClassLoader classLoader = this.getClassLoader();
    String beanClassName = bd.getBeanClassNam();
    try {
    Class<?> clazz = classLoader.loadClass(beanClassName);
    return clazz.newInstance();
    } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
    throw new BeanCreationException("Created bean for " + beanClassName + " fail.", e);
    }
    }
    + +

    到这里配置文件解析方面的工作已完成,接下来看看要如何实现 Setter 注入。

    +

    如何实现 Setter 注入

    首先实现基于 XML 配置文件的 Setter 注入本质上也是解析 XML 配置文件,然后再调用对象属性的 setXXX 方法将配置的值设置进去,配置文件 applicationcontext-config2.xml 如下所示:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.e3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="stockDao" class="cn.mghio.dao.version2.StockDao"/>

    <bean id="tradeDao" class="cn.mghio.dao.version2.TradeDao"/>

    <bean id="orderService" class="cn.mghio.service.version2.OrderService">
    <property name="stockDao" ref="stockDao"/>
    <property name="tradeDao" ref="tradeDao"/>
    <property name="num" value="2"/>
    <property name="owner" value="mghio"/>
    <property name="orderTime" value="2020-11-24 18:42:32"/>
    </bean>

    </beans>
    + +

    我们之前使用了 BeanDefinition 去抽象了 <bean> 标签,这里面临的第一个问题就是要如何去表达配置文件中的 <property> 标签,其中 ref 属性表示一个 beanIdvalue 属性表示一个值(值类型为:IntegerStringDate 等)。观察后可以发现,<property> 标签本质上是一个 K-V 格式的数据(name 作为 Keyrefvalue 作为 Value),将这个类命名为 PropertyValue,很明显一个 BeanDefinition 会有多个 PropertyValue,结构如下:

    +

    spring-injection-setter-property-1.png

    +

    这里的 value 有两种不同的类型,一种是表示 Beanid 值,运行时会解析为一个 Bean 的引用,将其命名为 RuntimeBeanReference,还有一种是 String 类型,运行时会解析为不同的类型,将其命名为 TypeStringValue。第二个问题就是要如何将一个类型转换为另一个类型呢?比如将上面配置中的字符串 2 转换为整型的 2、字符串 2020-11-24 18:42:32 转换为日期,这类通用的问题前辈们已经开发好了类库处理了,这里我们使用 commons-beanutils 库提供的 BeanUtils.copyProperty(final Object bean, final String name, final Object value) 方法即可。然后只需在之前 XmlBeanDefinitionReader 类的 loadBeanDefinition 方法解析 XML 配置文件的时解析 <bean> 标签下的 <property> 标签并设置到 BeanDefinitionpropertyValues 属性中;DefaultBeanFactory 中的 getBean 方法分为实例化 Bean 和读取向实例化完成的 Bean 使用 Setter 注入配置文件中配置属性对应的值。XmlBeanDefinitionReaderloadBeanDefinition() 方法代码修改为:

    +
    1
    2
    3
    4
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    public void loadBeanDefinition(Resource resource) {
    try (InputStream is = resource.getInputStream()) {
    SAXReader saxReader = new SAXReader();
    Document document = saxReader.read(is);
    Element root = document.getRootElement(); // <beans>
    Iterator<Element> iterator = root.elementIterator();
    while (iterator.hasNext()) {
    Element element = iterator.next();
    String beanId = element.attributeValue(BEAN_ID_ATTRIBUTE);
    String beanClassName = element.attributeValue(BEAN_CLASS_ATTRIBUTE);
    BeanDefinition bd = new GenericBeanDefinition(beanId, beanClassName);
    parsePropertyElementValue(element, bd); // parse <property>
    this.registry.registerBeanDefinition(beanId, bd);
    }
    } catch (DocumentException | IOException e) {
    throw new BeanDefinitionException("IOException parsing XML document:" + resource, e);
    }
    }

    private void parsePropertyElementValue(Element element, BeanDefinition bd) {
    Iterator<Element> iterator = element.elementIterator(PROPERTY_ATTRIBUTE);
    while (iterator.hasNext()) {
    Element propertyElement = iterator.next();
    String propertyName = propertyElement.attributeValue(NAME_ATTRIBUTE);
    if (!StringUtils.hasText(propertyName)) {
    return;
    }

    Object value = parsePropertyElementValue(propertyElement, propertyName);
    PropertyValue propertyValue = new PropertyValue(propertyName, value);
    bd.getPropertyValues().add(propertyValue);
    }

    }

    private Object parsePropertyElementValue(Element propertyElement, String propertyName) {
    String elementName = (propertyName != null) ?
    "<property> element for property '" + propertyName + "' " : "<constructor-arg> element";

    boolean hasRefAttribute = propertyElement.attribute(REF_ATTRIBUTE) != null;
    boolean hasValueAttribute = propertyElement.attribute(VALUE_ATTRIBUTE) != null;

    if (hasRefAttribute) {
    String refName = propertyElement.attributeValue(REF_ATTRIBUTE);
    RuntimeBeanReference ref = new RuntimeBeanReference(refName);
    return ref;
    } else if (hasValueAttribute) {
    String value = propertyElement.attributeValue(VALUE_ATTRIBUTE);
    TypedStringValue valueHolder = new TypedStringValue(value);
    return valueHolder;
    } else {
    throw new RuntimeException(elementName + " must specify a ref or value");
    }
    }
    + +

    DefaultBeanFactorygetBean 方法也增加 Bean 属性注入操作,部分代码如下:

    +
    1
    2
    3
    4
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    public Object getBean(String beanId) {
    BeanDefinition bd = getBeanDefinition(beanId);
    // 1. instantiate bean
    Object bean = instantiateBean(bd);
    // 2. populate bean
    populateBean(bd, bean);
    return bean;
    }

    private Object instantiateBean(BeanDefinition bd) {
    ClassLoader classLoader = this.getClassLoader();
    String beanClassName = bd.getBeanClassName();
    try {
    Class<?> clazz = classLoader.loadClass(beanClassName);
    return clazz.newInstance();
    } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
    throw new BeanCreationException("Created bean for " + beanClassName + " fail.", e);
    }
    }

    private void populateBean(BeanDefinition bd, Object bean) {
    List<PropertyValue> propertyValues = bd.getPropertyValues();
    if (propertyValues == null || propertyValues.isEmpty()) {
    return;
    }

    BeanDefinitionResolver resolver = new BeanDefinitionResolver(this);
    SimpleTypeConverted converter = new SimpleTypeConverted();
    try {
    for (PropertyValue propertyValue : propertyValues) {
    String propertyName = propertyValue.getName();
    Object originalValue = propertyValue.getValue();
    Object resolvedValue = resolver.resolveValueIfNecessary(originalValue);

    BeanUtils.copyProperty(bean, propertyName, resolvedValue);
    }
    } catch (Exception e) {
    throw new BeanCreationException("Failed to obtain BeanInfo for class [" + bd.getBeanClassName() + "]");
    }
    }
    + +

    至此,简单的 Setter 注入功能已完成。

    +

    总结

    本文简单概述了基于 XML 配置文件方式的 Setter 注入简单实现过程,整体实现 Setter 注入的思路就是先设计一个数据结构去表达 XML 配置文件中的标签数据(比如上面的 PropertyValue),然后再解析配置文件填充数据并利用这个数据结构完成一些功能(比如 Setter 注入等)。感兴趣的朋友可以到这里 mghio-spring 查看完整代码。

    + + +
    + + + + + +
    +
    -------------本文结束感谢您的阅读-------------
    +
    + + + +
    +
    + mghio wechat +
    微信公众号「mghio」
    +
    + +
    + + + +
    +
    +
    请我吃🍗
    + + +
    + +
    + + + +
    + +
    + + + +
    + + + +
    + + + +
    + +
    +
    + + +
    + + + + + + +
    +
    + +
    +
    + + + + + +
    + + + + + + + + + +
    +
    + +
    + +
    + + +
    + + +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/post/34755d6c.html b/post/34755d6c.html index a026ae59..765d1620 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -677,7 +677,7 @@

    总结 - 32 + 33 日志 @@ -688,7 +688,7 @@

    总结 - 33 + 34 分类 @@ -699,7 +699,7 @@

    总结 - 29 + 30 标签 diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index c90abf60..839db949 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -744,7 +744,7 @@

    总结 - 32 + 33 日志 @@ -755,7 +755,7 @@

    总结 - 33 + 34 分类 @@ -766,7 +766,7 @@

    总结 - 29 + 30 标签 diff --git a/post/4615256d.html b/post/4615256d.html index 6efe4677..e91ce87c 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -753,7 +753,7 @@

    - 32 + 33 日志 @@ -764,7 +764,7 @@

    - 33 + 34 分类 @@ -775,7 +775,7 @@

    - 29 + 30 标签 diff --git a/post/4b00e13c.html b/post/4b00e13c.html index 1359e277..8b055656 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -852,7 +852,7 @@

    总结 - 32 + 33 日志 @@ -863,7 +863,7 @@

    总结 - 33 + 34 分类 @@ -874,7 +874,7 @@

    总结 - 29 + 30 标签 diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index 4e547c17..4ce16030 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -685,7 +685,7 @@

    总结 - 32 + 33 日志 @@ -696,7 +696,7 @@

    总结 - 33 + 34 分类 @@ -707,7 +707,7 @@

    总结 - 29 + 30 标签 diff --git a/post/51e5bd99.html b/post/51e5bd99.html index 5edf9fa5..58075f14 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -726,7 +726,7 @@

    - 32 + 33 日志 @@ -737,7 +737,7 @@

    - 33 + 34 分类 @@ -748,7 +748,7 @@

    - 29 + 30 标签 diff --git a/post/558ca0bd.html b/post/558ca0bd.html index f7313418..7b0ac4e1 100644 --- a/post/558ca0bd.html +++ b/post/558ca0bd.html @@ -596,6 +596,10 @@

    3
    + +
    @@ -683,7 +687,7 @@

    3 - 32 + 33 日志 @@ -694,7 +698,7 @@

    3 @@ -705,7 +709,7 @@

    3 diff --git a/post/710bd10b.html b/post/710bd10b.html index 1dbab620..7de9071f 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -732,7 +732,7 @@

    总结 - 32 + 33 日志 @@ -743,7 +743,7 @@

    总结 - 33 + 34 分类 @@ -754,7 +754,7 @@

    总结 - 29 + 30 标签 diff --git a/post/7528c810.html b/post/7528c810.html index 0fac7c0b..e56c53eb 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -715,7 +715,7 @@

    总结 - 32 + 33 日志 @@ -726,7 +726,7 @@

    总结 - 33 + 34 分类 @@ -737,7 +737,7 @@

    总结 - 29 + 30 标签 diff --git a/post/7b9ead86.html b/post/7b9ead86.html index 80a20857..10b3fb5f 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -715,7 +715,7 @@

    总结 - 32 + 33 日志 @@ -726,7 +726,7 @@

    总结 - 33 + 34 分类 @@ -737,7 +737,7 @@

    总结 - 29 + 30 标签 diff --git a/post/7eb2637f.html b/post/7eb2637f.html index 1e2dbc07..ab4942bd 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -754,7 +754,7 @@

    - 32 + 33 日志 @@ -765,7 +765,7 @@

    - 33 + 34 分类 @@ -776,7 +776,7 @@

    - 29 + 30 标签 diff --git a/post/817c7d82.html b/post/817c7d82.html index 0c6f37b6..1f39cb6f 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1323,7 +1323,7 @@

    - 32 + 33 日志 @@ -1334,7 +1334,7 @@
    - 33 + 34 分类 @@ -1345,7 +1345,7 @@
    - 29 + 30 标签 diff --git a/post/8a061473.html b/post/8a061473.html index 210eb51d..f512d7ff 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -791,7 +791,7 @@
    - 32 + 33 日志 @@ -802,7 +802,7 @@
    - 33 + 34 分类 @@ -813,7 +813,7 @@
    - 29 + 30 标签 diff --git a/post/8bd965a0.html b/post/8bd965a0.html index e9fea2ef..bf087304 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -714,7 +714,7 @@

    - 32 + 33 日志 @@ -725,7 +725,7 @@

    @@ -736,7 +736,7 @@

    diff --git a/post/99ea2970.html b/post/99ea2970.html index 6a07ceb2..72fe5dde 100644 --- a/post/99ea2970.html +++ b/post/99ea2970.html @@ -710,7 +710,7 @@

    - 32 + 33 日志 @@ -721,7 +721,7 @@

    @@ -732,7 +732,7 @@

    diff --git a/post/a38c0645.html b/post/a38c0645.html index 2ef88b65..b3307f99 100644 --- a/post/a38c0645.html +++ b/post/a38c0645.html @@ -694,7 +694,7 @@

    总结 - 32 + 33 日志 @@ -705,7 +705,7 @@

    总结 - 33 + 34 分类 @@ -716,7 +716,7 @@

    总结 - 29 + 30 标签 diff --git a/post/ab706eb5.html b/post/ab706eb5.html index 236a48b2..ba0da6fb 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -697,7 +697,7 @@

    总结 - 32 + 33 日志 @@ -708,7 +708,7 @@

    总结 - 33 + 34 分类 @@ -719,7 +719,7 @@

    总结 - 29 + 30 标签 diff --git a/post/b1d4025b.html b/post/b1d4025b.html index ff4586c0..a0f451e9 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -627,7 +627,7 @@

    hello world

    - 32 + 33 日志 @@ -638,7 +638,7 @@

    hello world

    @@ -649,7 +649,7 @@

    hello world

    diff --git a/post/bc557e1a.html b/post/bc557e1a.html index 95bb8c0f..7ebeff31 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -762,7 +762,7 @@
    - 32 + 33 日志 @@ -773,7 +773,7 @@
    - 33 + 34 分类 @@ -784,7 +784,7 @@
    - 29 + 30 标签 diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index 08153497..b055f6cd 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -714,7 +714,7 @@

    - 32 + 33 日志 @@ -725,7 +725,7 @@

    @@ -736,7 +736,7 @@

    diff --git a/post/c34b451f.html b/post/c34b451f.html index 303a6003..9fde2d7f 100644 --- a/post/c34b451f.html +++ b/post/c34b451f.html @@ -753,7 +753,7 @@

    总结 - 32 + 33 日志 @@ -764,7 +764,7 @@

    总结 - 33 + 34 分类 @@ -775,7 +775,7 @@

    总结 - 29 + 30 标签 diff --git a/post/d7d0fc76.html b/post/d7d0fc76.html index 398d9996..74daa191 100644 --- a/post/d7d0fc76.html +++ b/post/d7d0fc76.html @@ -679,7 +679,7 @@

    - 32 + 33 日志 @@ -690,7 +690,7 @@

    - 33 + 34 分类 @@ -701,7 +701,7 @@

    - 29 + 30 标签 diff --git a/post/e09f0428.html b/post/e09f0428.html index a211b512..f9d2ab3f 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -684,7 +684,7 @@

    - 32 + 33 日志 @@ -695,7 +695,7 @@

    - 33 + 34 分类 @@ -706,7 +706,7 @@

    - 29 + 30 标签 diff --git a/post/ee27c07f.html b/post/ee27c07f.html index 5a633e3f..07330fca 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -677,7 +677,7 @@

    - 32 + 33 日志 @@ -688,7 +688,7 @@

    @@ -699,7 +699,7 @@

    diff --git a/post/f440d00b.html b/post/f440d00b.html index d7b4130d..1f9549ea 100644 --- a/post/f440d00b.html +++ b/post/f440d00b.html @@ -713,7 +713,7 @@

    总结 - 32 + 33 日志 @@ -724,7 +724,7 @@

    总结 - 33 + 34 分类 @@ -735,7 +735,7 @@

    总结 - 29 + 30 标签 diff --git a/post/f92758d8.html b/post/f92758d8.html index 3716b188..3b2695fa 100644 --- a/post/f92758d8.html +++ b/post/f92758d8.html @@ -701,7 +701,7 @@

    总结 - 32 + 33 日志 @@ -712,7 +712,7 @@

    总结 - 33 + 34 分类 @@ -723,7 +723,7 @@

    总结 - 29 + 30 标签 diff --git a/post/fa75f5d7.html b/post/fa75f5d7.html index 37b7f43f..e69af2ae 100644 --- a/post/fa75f5d7.html +++ b/post/fa75f5d7.html @@ -717,7 +717,7 @@

    - 32 + 33 日志 @@ -728,7 +728,7 @@

    - 33 + 34 分类 @@ -739,7 +739,7 @@

    - 29 + 30 标签 diff --git a/post/fe76043.html b/post/fe76043.html index a0a6d1ea..e9553626 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -680,7 +680,7 @@

    总结 - 32 + 33 日志 @@ -691,7 +691,7 @@

    总结 - 33 + 34 分类 @@ -702,7 +702,7 @@

    总结 - 29 + 30 标签 diff --git a/search.xml b/search.xml index 34b847df..a3457750 100644 --- a/search.xml +++ b/search.xml @@ -1,5 +1,18 @@ + + <![CDATA[如何实现一个简易版的 Spring - 如何实现 Setter 注入]]> + %2Fpost%2F24cb2421.html + + + Java + Spring + + + Spring + IoC + + <![CDATA[Spring 是如何造出一个 Bean 的]]> %2Fpost%2F558ca0bd.html diff --git a/sitemap.xml b/sitemap.xml index 874fbd26..f8de7afe 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,13 @@ + + https://www.mghio.cn/post/24cb2421.html + + 2020-11-29T07:58:43.606Z + + + https://www.mghio.cn/about/index.html diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index f038547b..5794ca2b 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index 2e71d920..40266a17 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index 16c65747..90bdbf5b 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/GC/index.html b/tags/GC/index.html index e2443953..bccf4a5b 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/Guava/index.html b/tags/Guava/index.html index e7544077..9252a5de 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index 9bc497b3..861b5b6f 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index 136bbdd3..cafe7af1 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/IoC/index.html b/tags/IoC/index.html new file mode 100644 index 00000000..a32b06aa --- /dev/null +++ b/tags/IoC/index.html @@ -0,0 +1,1253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: IoC | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/JDK/index.html b/tags/JDK/index.html index 9cbb6a9a..fb67eb2a 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/JVM/index.html b/tags/JVM/index.html index bde66927..73438182 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -412,7 +412,7 @@

    - 32 + 33 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index 5d202d39..c232a1b9 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index 22c5b248..7e8257da 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/Java/index.html b/tags/Java/index.html index b234f87d..72f95095 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -624,7 +624,7 @@

    - 32 + 33 日志 @@ -635,7 +635,7 @@

    @@ -646,7 +646,7 @@

    diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index 200e11da..82ade5c6 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -624,7 +624,7 @@

    - 32 + 33 日志 @@ -635,7 +635,7 @@

    @@ -646,7 +646,7 @@

    diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index 1b3b45dc..8c56f6e5 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -572,7 +572,7 @@

    - 32 + 33 日志 @@ -583,7 +583,7 @@

    @@ -594,7 +594,7 @@

    diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index 9178b3f2..60892428 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/List/index.html b/tags/List/index.html index 556b0031..d3665b05 100644 --- a/tags/List/index.html +++ b/tags/List/index.html @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/RabbitMQ/index.html b/tags/RabbitMQ/index.html index bfc71138..44249e3a 100644 --- a/tags/RabbitMQ/index.html +++ b/tags/RabbitMQ/index.html @@ -412,7 +412,7 @@

    - 32 + 33 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git a/tags/Spring/index.html b/tags/Spring/index.html index 2c98c3da..b98dd345 100644 --- a/tags/Spring/index.html +++ b/tags/Spring/index.html @@ -309,6 +309,32 @@

    Spring标签 + + + + + +
    @@ -386,7 +412,7 @@

    - 32 + 33 日志 @@ -397,7 +423,7 @@

    @@ -408,7 +434,7 @@

    diff --git a/tags/String/index.html b/tags/String/index.html index 6ecb4abf..1c9cda70 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/index.html b/tags/index.html index ee62de01..9028c4a0 100644 --- a/tags/index.html +++ b/tags/index.html @@ -317,10 +317,10 @@

    @@ -378,7 +378,7 @@

    - 32 + 33 日志 @@ -389,7 +389,7 @@

    @@ -400,7 +400,7 @@

    diff --git a/tags/mockito/index.html b/tags/mockito/index.html index 495aaaa2..31fd56be 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git a/tags/test/index.html b/tags/test/index.html index 2821a198..ba90d068 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 3f39c0e2..fcfe38be 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index 6bdde673..1764d1df 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -412,7 +412,7 @@

    - 32 + 33 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 12be18e4..ef00caaf 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -412,7 +412,7 @@

    - 32 + 33 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index 64c294b2..d67a0eb8 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index 570ce642..1aa96f9f 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -412,7 +412,7 @@

    - 32 + 33 日志 @@ -423,7 +423,7 @@

    @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index 689b56de..6cae15e8 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 5ac17f4c..416c6d20 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 66c00126..e1c40f78 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\347\274\223\345\255\230/index.html" "b/tags/\347\274\223\345\255\230/index.html" index 0206d783..0ef9ed4e 100644 --- "a/tags/\347\274\223\345\255\230/index.html" +++ "b/tags/\347\274\223\345\255\230/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index db81c437..66d3a471 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -386,7 +386,7 @@

    - 32 + 33 日志 @@ -397,7 +397,7 @@

    @@ -408,7 +408,7 @@

    From 658b67b58f6e7676b672604f4ef784b450242eac Mon Sep 17 00:00:00 2001 From: mghio Date: Tue, 8 Dec 2020 00:13:57 +0800 Subject: [PATCH 12/19] Site updated: 2020-12-08 00:13:56 --- atom.xml | 4 ++-- baidusitemap.xml | 6 +++--- css/main.css | 2 +- post/51e5bd99.html | 30 +++++++++++++++--------------- sitemap.xml | 14 +++++++------- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/atom.xml b/atom.xml index 56c473bd..3a28ba5a 100644 --- a/atom.xml +++ b/atom.xml @@ -254,9 +254,9 @@ https://www.mghio.cn/post/51e5bd99.html 2020-05-16T12:52:22.000Z - 2020-05-17T09:42:06.027Z + 2020-12-07T16:12:57.281Z - 前言

    对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

    SDKMan 简介

    直接引用 SDKMan 官网上的介绍如下:

    SDKMAN! is a tool for managing parallel versions of multiple Software Development Kits on most Unix based systems. It provides a convenient Command Line Interface (CLI) and API for installing, switching, removing and listing Candidates.

    简单来说就是其提供了管理多个版本开发工具包的能力,同时也提供了一些命令行接口让我们方便安装、版本切换、版本移除和显示版本列表。关于 SDKMan 还有几个要点如下:

    1. SDKMan 是由开源社区开发的,免费使用,。
    2. SDKMan 是用 bash 编写的,它只需要您的系统上安装了 curlzip / unzip 命令即可。
    3. SDKMan 可以为 JVM 安装大约 29 个软件开发包,比如 JavaGroovyScalaKotlinGradleMavenSparkSpring Boot 等。
    4. SDKMan 可以自动处理帮我们配置 *_HOME(e.g.:JAVA_HOME)PATH 环境变量,因此我们不需要担心切换版本后这些环境变量的设置。

    安装 SDKMan

    SDKMan 可以运行在任何类 Unix 系统上,我们只需要在命令行输入以下命令即可安装:

    1
    curl -s "https://get.sdkman.io" | bash

    install-sdkman.png

    然后执行以下命令,加载文件 sdkman-init.sh 到当前环境,执行完该命令之后我们可以通过 sdk version 来验证是否安装成功,同时还可以通过 sdk help 命令显示有关 sdk 命令用法和帮助(PS: 对于使用 Windows 环境的朋友可以安装 Cygwin 或 Git Bash 运行以上命令)。

    1
    source "$HOME/.sdkman/bin/sdkman-init.sh"

    verify-sdkman-install.png

    使用 SDKMan 安装 JDK

    前面已经介绍过,SDKMan 支持多达大约 29 个软件开发包管理,我们也可以使用 sdk list 命令来查看支持的完整列表,本文主要介绍 Java 相关的内容,可以通过命令 sdk list java 来查看支持安装的 Java 版本。

    sdk-list-java.png

    使用以下命令安装 Java 11

    1
    sdk install java 11.0.7.hs-adpt

    该命令会花费一些时间,因为它会在我们的计算机上下载对应版本的 JDK,执行完成之后 SDKman 会自动给我们配置好 JAVA_HOMEPATH 等环境变量,可以通过 Java -version 命令验证。

    sdk-install-jdk-11

    现在,如果检查 Java 版本和 JAVA_HOME 环境变量,可以看到当前 Java 的版本已更新为 11.0.7

    java-version-verify

    可以使用以下命令来设置默认使用的 JDK 版本。

    1
    sdk default java 11.0.7.hs-adpt

    将 SDKMan 指向已安装 Java 版本

    如果在你安装 SDKMan 之前本地电脑已经安装了 JDK 版本,默认是无法识别到的,那么你需要进行以下配置才能让 SDKMan 识别已安装的版本,首先,第一步你要先找到你的 Java 安装目录,我本地 Mac 的安装目录是 /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk,然后使用命令 ln -s 来为 Java 安装目录建立符号链接。

    point-sdkman-existing-installd-version.png

    多个 JDK 版本切换示例

    SDKMan 提供了命令 sdk use java <version_want_to_use> 在多个版本之间进行切换,使用 sdk use java jdk1.8.0_181.jdk 命令来使用之前本地安装的 Java 8

    sdk-use-jdk8.png

    使用命令 sdk use java 11.0.7.hs-adpt 来设置版本为 Java 11

    sdk-use-java11

    需要注意的是:使用命令 sdk use java <version> 只在当前会话有效,如果你关闭终端并再次打开它,则将使用以前安装的版本,不会改变你本地使用的版本,此时可以使用 sdk default java <version> 来设置永久生效。

    如何卸载指定的 JDK 版本

    如果你想要卸载任何已安装的 JDK 版本,比如: 11.0.7.hs-adpt,可以使用以下命令卸载:

    1
    sdk uninstall java 11.0.7.hs-adpt

    此时,如果你想再次安装之前通过 SDKMan 卸载的版本,此时不会再次重新下载,会提示 Found a previously downloaded java 11.0.7.hs-adpt archive. Not downloading it again...,因为之前删除操作并没有真正的从你计算机上删除源压缩包文件。

    IntelliJ IDEA 使用 SDMan 安装 JDK

    SDKMan 所有安装的 JDK 都放在目录 .sdkman/candidates/java/,你可以在你当前用户的 home 文件夹下面看到该文件夹(注意是隐藏文件夹)。

    show-sdkman-directory.png

    IntelliJ IDEA 中打开任何一个 Java 项目后,您可以按 Command + : 快捷键打开项目结构窗口,在 Project SDK 模块选择新建一个 JDK 后输入你需要的 JDK 版本在 SDKMan 中的路径即可。

    idea-set-jdk-version.png

    因为 .sdkman 是隐藏文件夹不太方便查找,可以使用以下命令创建一个非隐藏文件夹指向它。

    1
    ln -s ~/.sdkman ~/sdkman
    ]]> + 前言

    对于使用 Java 语言开发的朋友可能会遇到这种情况,有时想学习和探索 Java 的最新版本提供的一些新特性,比如 Java 11,但你无法将其安装在自己的计算机上,因为你的团队正在使用比这个旧的版本(我们目前用的 Java 8),你并不想影响目前的项目。或者你目前是在维护和开发多个项目,而这些不同的项目使用的 JDK 版本不一样,比如那些维护的老项目使用的是 JDK 8,而新项目你打算使用比较新的版本 JDK 11,以上这些情况都需要在计算机上安装多个 JDK,并且应该能够在多个版本之间方便快速的切换。今天要介绍的主角 SDKMAN 可以很好的解决上面这种问题,它提供了在同一台计算机上对多个版本的开发工具包管理。需要注意的是:这个工具只适用于类 Unix 的系统(比如:Mac OSX、Linux、Cygwin、Solaris、FreeBSD 等)。

    SDKMan 简介

    直接引用 SDKMan 官网上的介绍如下:

    SDKMAN! is a tool for managing parallel versions of multiple Software Development Kits on most Unix based systems. It provides a convenient Command Line Interface (CLI) and API for installing, switching, removing and listing Candidates.

    简单来说就是其提供了管理多个版本开发工具包的能力,同时也提供了一些命令行接口让我们方便安装、版本切换、版本移除和显示版本列表。关于 SDKMan 还有几个要点如下:

    1. SDKMan 是由开源社区开发的,免费使用,。
    2. SDKMan 是用 bash 编写的,它只需要您的系统上安装了 curlzip / unzip 命令即可。
    3. SDKMan 可以为 JVM 安装大约 29 个软件开发包,比如 JavaGroovyScalaKotlinGradleMavenSparkSpring Boot 等。
    4. SDKMan 可以自动处理帮我们配置 *_HOME(e.g.:JAVA_HOME)PATH 环境变量,因此我们不需要担心切换版本后这些环境变量的设置。

    安装 SDKMan

    SDKMan 可以运行在任何类 Unix 系统上,我们只需要在命令行输入以下命令即可安装:

    1
    curl -s "https://get.sdkman.io" | bash

    install-sdkman.png

    然后执行以下命令,加载文件 sdkman-init.sh 到当前环境,执行完该命令之后我们可以通过 sdk version 来验证是否安装成功,同时还可以通过 sdk help 命令显示有关 sdk 命令用法和帮助(PS: 对于使用 Windows 环境的朋友可以安装 Cygwin 或 Git Bash 运行以上命令)。

    1
    source "$HOME/.sdkman/bin/sdkman-init.sh"

    verify-sdkman-install.png

    使用 SDKMan 安装 JDK

    前面已经介绍过,SDKMan 支持多达大约 29 个软件开发包管理,我们也可以使用 sdk list 命令来查看支持的完整列表,本文主要介绍 Java 相关的内容,可以通过命令 sdk list java 来查看支持安装的 Java 版本。

    sdk-list-java.png

    使用以下命令安装 Java 11

    1
    sdk install java 11.0.7.hs-adpt

    该命令会花费一些时间,因为它会在我们的计算机上下载对应版本的 JDK,执行完成之后 SDKman 会自动给我们配置好 JAVA_HOMEPATH 等环境变量,可以通过 Java -version 命令验证。

    sdk-install-jdk-11.png

    现在,如果检查 Java 版本和 JAVA_HOME 环境变量,可以看到当前 Java 的版本已更新为 11.0.7

    java-version-verify.png

    可以使用以下命令来设置默认使用的 JDK 版本。

    1
    sdk default java 11.0.7.hs-adpt

    将 SDKMan 指向已安装 Java 版本

    如果在你安装 SDKMan 之前本地电脑已经安装了 JDK 版本,默认是无法识别到的,那么你需要进行以下配置才能让 SDKMan 识别已安装的版本,首先,第一步你要先找到你的 Java 安装目录,我本地 Mac 的安装目录是 /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk,然后使用命令 ln -s 来为 Java 安装目录建立符号链接。

    point-sdkman-existing-installed-version.png

    多个 JDK 版本切换示例

    SDKMan 提供了命令 sdk use java <version_want_to_use> 在多个版本之间进行切换,使用 sdk use java jdk1.8.0_181.jdk 命令来使用之前本地安装的 Java 8

    sdk-use-jdk8.png

    使用命令 sdk use java 11.0.7.hs-adpt 来设置版本为 Java 11

    sdk-use-java11.png

    需要注意的是:使用命令 sdk use java <version> 只在当前会话有效,如果你关闭终端并再次打开它,则将使用以前安装的版本,不会改变你本地使用的版本,此时可以使用 sdk default java <version> 来设置永久生效。

    如何卸载指定的 JDK 版本

    如果你想要卸载任何已安装的 JDK 版本,比如: 11.0.7.hs-adpt,可以使用以下命令卸载:

    1
    sdk uninstall java 11.0.7.hs-adpt

    此时,如果你想再次安装之前通过 SDKMan 卸载的版本,此时不会再次重新下载,会提示 Found a previously downloaded java 11.0.7.hs-adpt archive. Not downloading it again...,因为之前删除操作并没有真正的从你计算机上删除源压缩包文件。

    IntelliJ IDEA 使用 SDMan 安装 JDK

    SDKMan 所有安装的 JDK 都放在目录 .sdkman/candidates/java/,你可以在你当前用户的 home 文件夹下面看到该文件夹(注意是隐藏文件夹)。

    show-sdkman-directory.png

    IntelliJ IDEA 中打开任何一个 Java 项目后,您可以按 Command + : 快捷键打开项目结构窗口,在 Project SDK 模块选择新建一个 JDK 后输入你需要的 JDK 版本在 SDKMan 中的路径即可。

    idea-set-jdk-version.png

    因为 .sdkman 是隐藏文件夹不太方便查找,可以使用以下命令创建一个非隐藏文件夹指向它。

    1
    ln -s ~/.sdkman ~/sdkman
    ]]> diff --git a/baidusitemap.xml b/baidusitemap.xml index cbbb0190..edb75ed6 100644 --- a/baidusitemap.xml +++ b/baidusitemap.xml @@ -1,6 +1,9 @@ + https://www.mghio.cn/post/51e5bd99.html + 2020-12-07 + https://www.mghio.cn/post/24cb2421.html 2020-11-29 @@ -24,9 +27,6 @@ https://www.mghio.cn/post/24042edf.html 2020-06-03 - - https://www.mghio.cn/post/51e5bd99.html - 2020-05-17 https://www.mghio.cn/post/34755d6c.html 2020-04-26 diff --git a/css/main.css b/css/main.css index ea650fed..8d92b982 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #cb44bb; + background: #cb9cff; } .links-of-blogroll { font-size: 13px; diff --git a/post/51e5bd99.html b/post/51e5bd99.html index 58075f14..051caf70 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -105,14 +105,14 @@ - - - - - - - - + + + + + + + + @@ -507,18 +507,18 @@

    1
    sdk install java 11.0.7.hs-adpt

    该命令会花费一些时间,因为它会在我们的计算机上下载对应版本的 JDK,执行完成之后 SDKman 会自动给我们配置好 JAVA_HOMEPATH 等环境变量,可以通过 Java -version 命令验证。

    -

    sdk-install-jdk-11

    +

    sdk-install-jdk-11.png

    现在,如果检查 Java 版本和 JAVA_HOME 环境变量,可以看到当前 Java 的版本已更新为 11.0.7

    -

    java-version-verify

    +

    java-version-verify.png

    可以使用以下命令来设置默认使用的 JDK 版本。

    1
    sdk default java 11.0.7.hs-adpt

    将 SDKMan 指向已安装 Java 版本

    如果在你安装 SDKMan 之前本地电脑已经安装了 JDK 版本,默认是无法识别到的,那么你需要进行以下配置才能让 SDKMan 识别已安装的版本,首先,第一步你要先找到你的 Java 安装目录,我本地 Mac 的安装目录是 /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk,然后使用命令 ln -s 来为 Java 安装目录建立符号链接。

    -

    point-sdkman-existing-installd-version.png

    +

    point-sdkman-existing-installed-version.png

    多个 JDK 版本切换示例

    SDKMan 提供了命令 sdk use java <version_want_to_use> 在多个版本之间进行切换,使用 sdk use java jdk1.8.0_181.jdk 命令来使用之前本地安装的 Java 8

    -

    sdk-use-jdk8.png

    +

    sdk-use-jdk8.png

    使用命令 sdk use java 11.0.7.hs-adpt 来设置版本为 Java 11

    -

    sdk-use-java11

    +

    sdk-use-java11.png

    需要注意的是:使用命令 sdk use java <version> 只在当前会话有效,如果你关闭终端并再次打开它,则将使用以前安装的版本,不会改变你本地使用的版本,此时可以使用 sdk default java <version> 来设置永久生效。

    @@ -527,9 +527,9 @@

    IntelliJ IDEA 使用 SDMan 安装 JDK

    SDKMan 所有安装的 JDK 都放在目录 .sdkman/candidates/java/,你可以在你当前用户的 home 文件夹下面看到该文件夹(注意是隐藏文件夹)。

    -

    show-sdkman-directory.png

    +

    show-sdkman-directory.png

    IntelliJ IDEA 中打开任何一个 Java 项目后,您可以按 Command + : 快捷键打开项目结构窗口,在 Project SDK 模块选择新建一个 JDK 后输入你需要的 JDK 版本在 SDKMan 中的路径即可。

    -

    idea-set-jdk-version.png

    +

    idea-set-jdk-version.png

    因为 .sdkman 是隐藏文件夹不太方便查找,可以使用以下命令创建一个非隐藏文件夹指向它。

    1
    ln -s ~/.sdkman ~/sdkman
    diff --git a/sitemap.xml b/sitemap.xml index f8de7afe..b95c4e02 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,13 @@ + + https://www.mghio.cn/post/51e5bd99.html + + 2020-12-07T16:12:57.281Z + + + https://www.mghio.cn/post/24cb2421.html @@ -64,13 +71,6 @@ - - https://www.mghio.cn/post/51e5bd99.html - - 2020-05-17T09:42:06.027Z - - - https://www.mghio.cn/post/34755d6c.html From b1f135bc3b6ba930b48cc58946b4a974bb66b49e Mon Sep 17 00:00:00 2001 From: mghio Date: Sat, 16 Jan 2021 21:05:42 +0800 Subject: [PATCH 13/19] Site updated: 2021-01-16 21:05:41 --- about/index.html | 2 +- archives/2019/10/index.html | 2 +- archives/2019/11/index.html | 2 +- archives/2019/12/index.html | 2 +- archives/2019/index.html | 2 +- archives/2019/page/2/index.html | 2 +- archives/2020/01/index.html | 2 +- archives/2020/02/index.html | 2 +- archives/2020/03/index.html | 2 +- archives/2020/04/index.html | 2 +- archives/2020/05/index.html | 2 +- archives/2020/06/index.html | 2 +- archives/2020/07/index.html | 2 +- archives/2020/08/index.html | 2 +- archives/2020/09/index.html | 2 +- archives/2020/10/index.html | 2 +- archives/2020/11/index.html | 2 +- archives/2020/index.html | 2 +- archives/2020/page/2/index.html | 2 +- archives/index.html | 2 +- archives/page/2/index.html | 2 +- archives/page/3/index.html | 2 +- archives/page/4/index.html | 2 +- atom.xml | 8 ++++---- baidusitemap.xml | 6 +++--- categories/JDK/Java/index.html | 2 +- .../index.html" | 2 +- categories/JDK/index.html | 2 +- categories/Java/Bloom-filter/index.html | 2 +- categories/Java/GC/index.html | 2 +- categories/Java/Guava/String/index.html | 2 +- categories/Java/Guava/index.html | 2 +- categories/Java/IDEA/index.html | 2 +- .../Java/IDEA/\345\267\245\345\205\267/index.html" | 2 +- "categories/Java/IO\346\250\241\345\236\213/index.html" | 2 +- categories/Java/JVM/index.html | 2 +- categories/Java/List/index.html | 2 +- categories/Java/Spring/index.html | 2 +- categories/Java/index.html | 2 +- categories/Java/page/2/index.html | 2 +- categories/Java/page/3/index.html | 2 +- categories/Java/unit-test/index.html | 2 +- categories/Java/unit-test/mockito/index.html | 2 +- "categories/Java/\345\216\237\347\220\206/index.html" | 2 +- "categories/Java/\345\217\215\345\260\204/index.html" | 2 +- .../Java/\345\244\232\347\272\277\347\250\213/index.html" | 2 +- "categories/Java/\345\271\266\345\217\221/index.html" | 2 +- .../\350\277\233\351\230\266/index.html" | 2 +- "categories/Java/\345\274\202\346\255\245/index.html" | 2 +- .../Eureka/index.html" | 2 +- .../index.html" | 2 +- .../Java/\347\272\277\347\250\213\346\261\240/index.html" | 2 +- "categories/Java/\347\274\223\345\255\230/index.html" | 2 +- "categories/Java/\351\207\215\346\236\204/index.html" | 2 +- "categories/Linux\347\254\224\350\256\260/index.html" | 2 +- categories/RabbitMQ/Java/index.html | 2 +- categories/RabbitMQ/index.html | 2 +- categories/Spring/Java/index.html | 2 +- categories/Spring/index.html | 2 +- categories/index.html | 2 +- .../CAP\345\256\232\347\220\206/index.html" | 2 +- .../index.html" | 2 +- css/main.css | 2 +- index.html | 2 +- page/2/index.html | 2 +- page/3/index.html | 2 +- page/4/index.html | 2 +- post/102cd3d9.html | 2 +- post/11cb7677.html | 2 +- post/192cb539.html | 2 +- post/24042edf.html | 2 +- post/24cb2421.html | 6 +++--- post/34755d6c.html | 2 +- post/3ae0ff4e.html | 2 +- post/4615256d.html | 2 +- post/4b00e13c.html | 2 +- post/4ea48fa7.html | 2 +- post/51e5bd99.html | 4 ++-- post/558ca0bd.html | 2 +- post/710bd10b.html | 2 +- post/7528c810.html | 2 +- post/7b9ead86.html | 2 +- post/7eb2637f.html | 2 +- post/817c7d82.html | 2 +- post/8a061473.html | 2 +- post/8bd965a0.html | 2 +- post/99ea2970.html | 2 +- post/a38c0645.html | 2 +- post/ab706eb5.html | 2 +- post/b1d4025b.html | 2 +- post/bc557e1a.html | 2 +- post/bfcdfeaf.html | 2 +- post/c34b451f.html | 2 +- post/d7d0fc76.html | 2 +- post/e09f0428.html | 2 +- post/ee27c07f.html | 2 +- post/f440d00b.html | 2 +- post/f92758d8.html | 2 +- post/fa75f5d7.html | 2 +- post/fe76043.html | 2 +- search.xml | 2 +- sitemap.xml | 8 ++++---- tags/Bloom-filter/index.html | 2 +- "tags/CAP\345\256\232\347\220\206/index.html" | 2 +- tags/Eureka/index.html | 2 +- tags/GC/index.html | 2 +- tags/Guava/index.html | 2 +- tags/IDEA/index.html | 2 +- "tags/IO\346\250\241\345\236\213/index.html" | 2 +- tags/IoC/index.html | 2 +- tags/JDK/index.html | 2 +- tags/JVM/index.html | 2 +- "tags/Java-\345\216\237\347\220\206/index.html" | 2 +- "tags/Java-\345\271\266\345\217\221/index.html" | 2 +- tags/Java/index.html | 2 +- tags/Java/page/2/index.html | 2 +- tags/Java/page/3/index.html | 2 +- "tags/Linux\347\254\224\350\256\260/index.html" | 2 +- tags/List/index.html | 2 +- tags/RabbitMQ/index.html | 2 +- tags/Spring/index.html | 2 +- tags/String/index.html | 2 +- tags/index.html | 2 +- tags/mockito/index.html | 2 +- tags/test/index.html | 2 +- .../index.html" | 2 +- "tags/\345\217\215\345\260\204/index.html" | 2 +- "tags/\345\244\232\347\272\277\347\250\213/index.html" | 2 +- "tags/\345\267\245\345\205\267/index.html" | 2 +- "tags/\345\271\266\345\217\221/index.html" | 2 +- "tags/\345\274\202\346\255\245/index.html" | 2 +- .../index.html" | 2 +- .../index.html" | 2 +- "tags/\347\274\223\345\255\230/index.html" | 2 +- "tags/\351\207\215\346\236\204/index.html" | 2 +- 135 files changed, 146 insertions(+), 146 deletions(-) diff --git a/about/index.html b/about/index.html index 4101a7e9..25957e91 100644 --- a/about/index.html +++ b/about/index.html @@ -675,7 +675,7 @@

    - - - - - - - - - - - -
    - - - -
    - - - - - - - -
    - - - -

    - -

    - - - -
    - - - - - -
    - - - - - - -

    1.1 什么是 ThreadLocal

    ThreadLocal 简单理解 Thread 即线程,Local 即本地,结合起来理解就是 每个线程都是本地独有的。在早期的计算机中不包含操作系统,从头到尾只执行一个程序,并且这个程序能访问计算中的所有资源,这对于计算机资源来说是一种浪费。要想充分发挥多处理器的强大计算能力,最简单的方式就是使用多线程。与串行程序相比,在并发程序中存在更多容易出错的地方。当访问共享数据时,通常需要使用同步来控制并发程序的访问。一种避免使用同步的方式就是让这部分共享数据变成不共享的,试想一下,如果只是在单个线程内对数据进行访问,那么就可以不用同步了,这种技术称为线程封闭(Thread Confinement),它是实现线程安全最简单的方式之一。
    当某个对象封闭在一个单个线程中时,这种用法会自动实现了线程安全,因为只有一个线程访问数据,从根本上避免了共享数据的线程安全问题,即使被封闭的对象本身不是线程安全的。要保证线程安全,并不是一定就需要同步,两者没有因果关系,同步只是保证共享数据征用时正确性的手段,如果一个方法本来就不涉及共享数据,那它就不需要任何同步措施去保证正确性。而维持线程封闭的一种规范用法就是使用 ThreadLoal,这个类能使当前线程中的某个值与保存的值关联起来。ThreadLocal 提供了 get()set(T value) 等方法,set 方法为每个使用了该变量的线程都存有一份独立的副本,因此当我们调用 get 方法时总是返回由当前线程在调用 set 方法的时候设置的最新值。

    -

    1.2 ThreadLocal 的用法

    接下来通过一个示例代码说明 ThreadLocal 的使用方式,该示例使用了三个不同的线程 Main ThreadThread-1Thread-2 分别对同一个 ThreadLocal 对象中存储副本。

    -
    1
    2
    3
    4
    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
    30
    31
    /**
    * @author mghio
    * @date: 2019-10-20
    * @version: 1.0
    * @description: Java 并发之 ThreadLocal
    * @since JDK 1.8
    */
    public class ThreadLocalDemoTests {
    private ThreadLocal<String> boolThreadLocal = ThreadLocal.withInitial(() -> "");

    @Test
    public void testUseCase() {
    boolThreadLocal.set("main-thread-set");
    System.out.printf("Main Thread: %s\n", boolThreadLocal.get());

    new Thread("Thread-1") {
    @Override
    public void run() {
    boolThreadLocal.set("thread-1-set");
    System.out.printf("Thread-1: %s\n", boolThreadLocal.get());
    }
    }.start();

    new Thread("Thread-2") {
    @Override
    public void run() {
    System.out.printf("Thread-2: %s\n", boolThreadLocal.get());
    }
    }.start();
    }
    }
    - -
    - - 阅读全文 » - -
    - - - -
    - - - - - - - - - - - -
    @@ -2474,7 +2476,7 @@

    - 30 + 31 标签 diff --git a/page/4/index.html b/page/4/index.html index dfce59f2..7d2f54d2 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -305,6 +305,210 @@

    Java 搬运工 & 终身学习 +
    + + + +
    + + + + + + + +
    + + + +

    + +

    + + + +
    + + + + + +
    + + + + + + +

    1.1 什么是 ThreadLocal

    ThreadLocal 简单理解 Thread 即线程,Local 即本地,结合起来理解就是 每个线程都是本地独有的。在早期的计算机中不包含操作系统,从头到尾只执行一个程序,并且这个程序能访问计算中的所有资源,这对于计算机资源来说是一种浪费。要想充分发挥多处理器的强大计算能力,最简单的方式就是使用多线程。与串行程序相比,在并发程序中存在更多容易出错的地方。当访问共享数据时,通常需要使用同步来控制并发程序的访问。一种避免使用同步的方式就是让这部分共享数据变成不共享的,试想一下,如果只是在单个线程内对数据进行访问,那么就可以不用同步了,这种技术称为线程封闭(Thread Confinement),它是实现线程安全最简单的方式之一。
    当某个对象封闭在一个单个线程中时,这种用法会自动实现了线程安全,因为只有一个线程访问数据,从根本上避免了共享数据的线程安全问题,即使被封闭的对象本身不是线程安全的。要保证线程安全,并不是一定就需要同步,两者没有因果关系,同步只是保证共享数据征用时正确性的手段,如果一个方法本来就不涉及共享数据,那它就不需要任何同步措施去保证正确性。而维持线程封闭的一种规范用法就是使用 ThreadLoal,这个类能使当前线程中的某个值与保存的值关联起来。ThreadLocal 提供了 get()set(T value) 等方法,set 方法为每个使用了该变量的线程都存有一份独立的副本,因此当我们调用 get 方法时总是返回由当前线程在调用 set 方法的时候设置的最新值。

    +

    1.2 ThreadLocal 的用法

    接下来通过一个示例代码说明 ThreadLocal 的使用方式,该示例使用了三个不同的线程 Main ThreadThread-1Thread-2 分别对同一个 ThreadLocal 对象中存储副本。

    +
    1
    2
    3
    4
    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
    30
    31
    /**
    * @author mghio
    * @date: 2019-10-20
    * @version: 1.0
    * @description: Java 并发之 ThreadLocal
    * @since JDK 1.8
    */
    public class ThreadLocalDemoTests {
    private ThreadLocal<String> boolThreadLocal = ThreadLocal.withInitial(() -> "");

    @Test
    public void testUseCase() {
    boolThreadLocal.set("main-thread-set");
    System.out.printf("Main Thread: %s\n", boolThreadLocal.get());

    new Thread("Thread-1") {
    @Override
    public void run() {
    boolThreadLocal.set("thread-1-set");
    System.out.printf("Thread-1: %s\n", boolThreadLocal.get());
    }
    }.start();

    new Thread("Thread-2") {
    @Override
    public void run() {
    System.out.printf("Thread-2: %s\n", boolThreadLocal.get());
    }
    }.start();
    }
    }
    + +
    + + 阅读全文 » + +
    + + + +
    + + + + + + + + + + + + +
    + + + + + + + + +
    + +
    +
    + + + +
    + + + + + + + + + + +
    @@ -924,7 +1128,7 @@

    - 33 + 34 日志 @@ -946,7 +1150,7 @@

    diff --git a/post/102cd3d9.html b/post/102cd3d9.html index 3bdc5f81..a9c0842e 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -847,7 +847,7 @@

    总结 - 33 + 34 日志 @@ -869,7 +869,7 @@

    总结 - 30 + 31 标签 diff --git a/post/11cb7677.html b/post/11cb7677.html index e2c41a16..a932fa47 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -698,7 +698,7 @@

    总结 - 33 + 34 日志 @@ -720,7 +720,7 @@

    总结 - 30 + 31 标签 diff --git a/post/192cb539.html b/post/192cb539.html index db8757b9..afd06466 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -762,7 +762,7 @@

    - 33 + 34 日志 @@ -784,7 +784,7 @@

    diff --git a/post/24042edf.html b/post/24042edf.html index a44d4650..935089ce 100644 --- a/post/24042edf.html +++ b/post/24042edf.html @@ -770,7 +770,7 @@

    总结 - 33 + 34 日志 @@ -792,7 +792,7 @@

    总结 - 30 + 31 标签 diff --git a/post/24cb2421.html b/post/24cb2421.html index 53ad2cf9..6a9141e2 100644 --- a/post/24cb2421.html +++ b/post/24cb2421.html @@ -612,6 +612,10 @@

    总结 + + @@ -699,7 +703,7 @@

    总结 - 33 + 34 日志 @@ -721,7 +725,7 @@

    总结 - 30 + 31 标签 diff --git a/post/315ff4dc.html b/post/315ff4dc.html new file mode 100644 index 00000000..38502e35 --- /dev/null +++ b/post/315ff4dc.html @@ -0,0 +1,1581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 如何实现一个简易版的 Spring - 如何实现 Constructor 注入 | mghio + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    +
    +
    +
    + + +
    + + + + + + + + +
    + + + +
    + + + + + + + +
    + + + +

    如何实现一个简易版的 Spring - 如何实现 Constructor 注入

    + + + +
    + + + + + +
    + + + + + +

    前言

    本文是「如何实现一个简易版的 Spring」系列的第二篇,在 第一篇 介绍了如何实现一个基于 XML 的简单 Setter 注入,这篇来看看要如何去实现一个简单的 Constructor 注入功能,实现步骤和 Setter 注入是一样的“套路”,先设计一个数据结构去解析表达 XML 配置文件里的信息,然后再使用这些解析好的数据结构做一些事情,比如这里的 Constructor 注入。话不多说,下面我们直接进入正题。

    + +

    数据结构设计

    使用 Constructor 注入方式的 XML 的一种配置如下所示:

    +
    1
    2
    3
    4
    5
    <bean id="orderService" class="cn.mghio.service.version3.OrderService">
    <constructor-arg ref="stockService"/>
    <constructor-arg ref="tradeService"/>
    <constructor-arg type="java.lang.String" value="mghio"/>
    </bean>
    + +

    以上 OrderService 类如下:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * @author mghio
    * @since 2021-01-16
    */
    public class OrderService {

    private StockDao stockDao;
    private TradeDao tradeDao;
    private String owner;

    public OrderService(StockDao stockDao, TradeDao tradeDao, String owner) {
    this.stockDao = stockDao;
    this.tradeDao = tradeDao;
    this.owner = owner;
    }
    }
    + +

    XML 的配置结构上看和 Setter 注入类似,都是 Key-Value 类的格式,可以将每个 constructor-arg 节点抽象为 ValueHolder,包含实际解析后的值类型 value、类型 type 以及参数名称 name,如下所示:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * @author mghio
    * @since 2021-01-16
    */
    public class ValueHolder {
    private Object value;
    private String type;
    private String name;

    // omit setter and getter
    }
    + +

    同样一个 Bean 可以包含多个 ValueHolder,为了封装实现以及方便提供一些判断方法(比如是否配置有构造器注入等),将进一步封装为 ConstructorArgument,并提供一些 CRUD 接口,而 ValueHolder 作为内部类,如下所示:

    +
    1
    2
    3
    4
    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
    30
    31
    32
    33
    34
    35
    36
    37
    /**
    * @author mghio
    * @since 2021-01-16
    */
    public class ConstructorArgument {

    private final List<ValueHolder> argumentsValues = new LinkedList<>();

    public void addArgumentValue(Object value) {
    this.argumentsValues.add(new ValueHolder(value));
    }

    public List<ValueHolder> getArgumentsValues() {
    return this.argumentsValues;
    }

    public int getArgumentCount() {
    return this.argumentsValues.size();
    }

    public boolean isEmpty() {
    return this.argumentsValues.isEmpty();
    }

    public void clear() {
    this.argumentsValues.clear();
    }

    // some other methods...

    public static class ValueHolder {

    private Object value;
    private String type;
    private String name;
    }
    }
    + +

    然后在 BeanDefinition 接口中增加获取 ConstructorArgument 方法和判断是否配置 ConstructorArgument 方法。结构如下图所示:

    +

    spring-constructor-injection.png

    +

    解析 XML 配置文件

    有了 上篇文章 的基础,解析 XML 也比较简单,这里我们解析的是 constructor-arg 节点,组装数据添加到 BeanDefinitionConstructorArgument 属性中,修改 XmlBeanDefinitionReader 类的 loadBeanDefinition(Resource resource) 方法如下:

    +
    1
    2
    3
    4
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    /**
    * @author mghio
    * @since 2021-01-16
    */
    public class XmlBeanDefinitionReader {

    private static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";
    private static final String NAME_ATTRIBUTE = "name";
    private static final String TYPE_ATTRIBUTE = "type";

    // other fields and methods ...

    public void loadBeanDefinition(Resource resource) {
    try (InputStream is = resource.getInputStream()) {
    SAXReader saxReader = new SAXReader();
    Document document = saxReader.read(is);
    Element root = document.getRootElement(); // <beans>
    Iterator<Element> iterator = root.elementIterator();
    while (iterator.hasNext()) {
    Element element = iterator.next();
    String beanId = element.attributeValue(BEAN_ID_ATTRIBUTE);
    String beanClassName = element.attributeValue(BEAN_CLASS_ATTRIBUTE);
    BeanDefinition bd = new GenericBeanDefinition(beanId, beanClassName);
    if (null != element.attributeValue(BEAN_SCOPE_ATTRIBUTE)) {
    bd.setScope(element.attributeValue(BEAN_SCOPE_ATTRIBUTE));
    }
    // parse <constructor-arg> node
    parseConstructorArgElements(element, bd);
    parsePropertyElementValues(element, bd);
    this.registry.registerBeanDefinition(beanId, bd);
    }
    } catch (DocumentException | IOException e) {
    throw new BeanDefinitionException("IOException parsing XML document:" + resource, e);
    }
    }

    private void parseConstructorArgElements(Element rootEle, BeanDefinition bd) {
    Iterator<Element> iterator = rootEle.elementIterator(CONSTRUCTOR_ARG_ELEMENT);
    while (iterator.hasNext()) {
    Element element = iterator.next();
    parseConstructorArgElement(element, bd);
    }
    }

    private void parseConstructorArgElement(Element element, BeanDefinition bd) {
    String typeAttr = element.attributeValue(TYPE_ATTRIBUTE);
    String nameAttr = element.attributeValue(NAME_ATTRIBUTE);
    Object value = parsePropertyElementValue(element, null);
    ConstructorArgument.ValueHolder valueHolder = new ConstructorArgument.ValueHolder(value);
    if (StringUtils.hasLength(typeAttr)) {
    valueHolder.setType(typeAttr);
    }
    if (StringUtils.hasLength(nameAttr)) {
    valueHolder.setName(nameAttr);
    }
    bd.getConstructorArgument().addArgumentValue(valueHolder);
    }

    // other fields and methods ...

    }
    + +

    解析 XML 的过程整体上分为两步,第一步在遍历每个 <bean> 节点时判断 <constructor-arg> 节点是否存在,存在则解析 <constructor-arg> 节点;第二步将解析拼装好的 ValueHolder 添加到 BeanDefinition 中,这样我们就把 XML 配置的 Constructor 注入解析到 BeanDefinition 中了,下面看看如何在创建 Bean 的过程中如何使用该数据结构进行构造器注入。

    +

    如何选择 Constructor

    很明显,使用构造器注入需要放在实例化 Bean的阶段,通过判断当前待实例化的 Bean 是否有配置构造器注入,有则使用构造器实例化。判断 XML 是否有配置构造器注入可以直接使用 BeanDefinition 提供的 hasConstructorArguments() 方法即可,实际上最终是通过判断 ConstructorArgument.ValueHolder 集合是否有值来判断的。这里还有个问题 当存在多个构造器时如何选择,比如 OrderService 类有如下三个构造函数:

    +
    1
    2
    3
    4
    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
    /**
    * @author mghio
    * @since 2021-01-16
    */
    public class OrderService {

    private StockDao stockDao;

    private TradeDao tradeDao;

    private String owner;

    public OrderService(StockDao stockDao, TradeDao tradeDao) {
    this.stockDao = stockDao;
    this.tradeDao = tradeDao;
    this.owner = "nobody";
    }

    public OrderService(StockDao stockDao, String owner) {
    this.stockDao = stockDao;
    this.owner = owner;
    }

    public OrderService(StockDao stockDao, TradeDao tradeDao, String owner) {
    this.stockDao = stockDao;
    this.tradeDao = tradeDao;
    this.owner = owner;
    }
    }
    + +

    XML 构造器注入的配置如下:

    +
    1
    2
    3
    4
    5
    <bean id="orderService" class="cn.mghio.service.version3.OrderService">
    <constructor-arg ref="stockService"/>
    <constructor-arg ref="tradeService"/>
    <constructor-arg type="java.lang.String" value="mghio"/>
    </bean>
    + +

    这时该如何选择最适合的构造器进行注入呢?这里使用的匹配方法是 1. 先判断构造函数参数个数,如果不匹配直接跳过,进行下一次循环;2. 当构造器参数个数匹配时再判断参数类型,如果和当前参数类型一致或者是当前参数类型的父类型则使用该构造器进行实例化。这个使用的判断方法比较简单直接,实际上 Spring 的判断方式考虑到的情况比较全面同时代码实现也更加复杂,感兴趣的朋友可以查看 org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(...) 方法。这里需要注意的是,在解析 XML 配置的构造器注入参数时要进行类型转换为目标类型,将该类命名为 ConstructorResolver,实现代码比较多这里就不贴出来了,可以到 GitHub 查看完整代码。然后只需要在实例化 Bean 的时候判断是否存在构造器注入配置,存在则使用构造器注入即可,修改 DefaultBeanFactory 的实例化方法如下:

    +
    1
    2
    3
    4
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    /**
    * @author mghio
    * @since 2021-01-16
    */
    public class DefaultBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory,
    BeanDefinitionRegistry {

    // other fields and methods ...

    private Object doCreateBean(BeanDefinition bd) {
    // 1. instantiate bean
    Object bean = instantiateBean(bd);
    // 2. populate bean
    populateBean(bd, bean);
    return bean;
    }

    private Object instantiateBean(BeanDefinition bd) {
    // 判断当前 Bean 的 `XML` 配置是否配置为构造器注入方式
    if (bd.hasConstructorArguments()) {
    ConstructorResolver constructorResolver = new ConstructorResolver(this);
    return constructorResolver.autowireConstructor(bd);
    } else {
    ClassLoader classLoader = this.getClassLoader();
    String beanClassName = bd.getBeanClassName();
    try {
    Class<?> beanClass = null;
    Class<?> cacheBeanClass = bd.getBeanClass();
    if (cacheBeanClass == null) {
    beanClass = classLoader.loadClass(beanClassName);
    bd.setBeanClass(beanClass);
    } else {
    beanClass = cacheBeanClass;
    }
    return beanClass.getDeclaredConstructor().newInstance();
    } catch (Exception e) {
    throw new BeanCreationException("Created bean for " + beanClassName + " fail.", e);
    }
    }
    }

    // other fields and methods ...

    }
    + +

    到这里就已经实现了一个简易版的基于 XML 配置的 Constructor 注入了。

    +

    总结

    本文简要介绍了 Spring 基于 XML 配置的 Constructor 注入,其实有了第一篇的 Setter 注入的基础,实现 Constructor 注入相对来说难度要小很多,这里的实现相对来说比较简单,但是其思想和大体流程是类似的,想要深入了解 Spring 实现的具体细节可以查看源码。完整代码已上传至 GitHub,感兴趣的朋友可以到这里 mghio-spring 查看完整代码,下篇预告:「如何实现一个简易版的 Spring - 实现字段注解方式注入」

    + + +
    + + + + + +
    +
    -------------本文结束感谢您的阅读-------------
    +
    + + + +
    +
    + mghio wechat +
    微信公众号「mghio」
    +
    + +
    + + + +
    +
    +
    请我吃🍗
    + + +
    + +
    + + + +
    + +
    + + + +
    + + + +
    + + + +
    + +
    +
    + + +
    + + + + + + +
    +
    + +
    +
    + + + + + +
    + + + + + + + + + +
    +
    + +
    + +
    + + +
    + + +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/post/34755d6c.html b/post/34755d6c.html index 29409c66..aaa570db 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -677,7 +677,7 @@

    总结 - 33 + 34 日志 @@ -699,7 +699,7 @@

    总结 - 30 + 31 标签 diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index 45166980..728e66e2 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -744,7 +744,7 @@

    总结 - 33 + 34 日志 @@ -766,7 +766,7 @@

    总结 - 30 + 31 标签 diff --git a/post/4615256d.html b/post/4615256d.html index 5594dc14..d774ccc5 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -753,7 +753,7 @@

    - 33 + 34 日志 @@ -775,7 +775,7 @@

    - 30 + 31 标签 diff --git a/post/4b00e13c.html b/post/4b00e13c.html index 692239be..229b435f 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -852,7 +852,7 @@

    总结 - 33 + 34 日志 @@ -874,7 +874,7 @@

    总结 - 30 + 31 标签 diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index e578bdbe..70187830 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -685,7 +685,7 @@

    总结 - 33 + 34 日志 @@ -707,7 +707,7 @@

    总结 - 30 + 31 标签 diff --git a/post/51e5bd99.html b/post/51e5bd99.html index cc7ebf73..17b3accc 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -726,7 +726,7 @@

    - 33 + 34 日志 @@ -748,7 +748,7 @@

    - 30 + 31 标签 diff --git a/post/558ca0bd.html b/post/558ca0bd.html index c3407724..95710a6f 100644 --- a/post/558ca0bd.html +++ b/post/558ca0bd.html @@ -687,7 +687,7 @@

    3 - 33 + 34 日志 @@ -709,7 +709,7 @@

    3 diff --git a/post/710bd10b.html b/post/710bd10b.html index 310ec12c..bc7fad32 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -732,7 +732,7 @@

    总结 - 33 + 34 日志 @@ -754,7 +754,7 @@

    总结 - 30 + 31 标签 diff --git a/post/7528c810.html b/post/7528c810.html index 6fd0e6e2..d2fffb33 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -715,7 +715,7 @@

    总结 - 33 + 34 日志 @@ -737,7 +737,7 @@

    总结 - 30 + 31 标签 diff --git a/post/7b9ead86.html b/post/7b9ead86.html index fa9eba72..bf06c4f1 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -715,7 +715,7 @@

    总结 - 33 + 34 日志 @@ -737,7 +737,7 @@

    总结 - 30 + 31 标签 diff --git a/post/7eb2637f.html b/post/7eb2637f.html index 2f087408..c20ffa70 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -754,7 +754,7 @@

    - 33 + 34 日志 @@ -776,7 +776,7 @@

    - 30 + 31 标签 diff --git a/post/817c7d82.html b/post/817c7d82.html index 34a4e02b..6914f726 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1323,7 +1323,7 @@

    - 33 + 34 日志 @@ -1345,7 +1345,7 @@
    - 30 + 31 标签 diff --git a/post/8a061473.html b/post/8a061473.html index 6b08617b..d1e9ac31 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -791,7 +791,7 @@
    - 33 + 34 日志 @@ -813,7 +813,7 @@
    - 30 + 31 标签 diff --git a/post/8bd965a0.html b/post/8bd965a0.html index f750a167..c580d98c 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -714,7 +714,7 @@

    - 33 + 34 日志 @@ -736,7 +736,7 @@

    diff --git a/post/99ea2970.html b/post/99ea2970.html index c1144ac0..f5404aaa 100644 --- a/post/99ea2970.html +++ b/post/99ea2970.html @@ -710,7 +710,7 @@

    - 33 + 34 日志 @@ -732,7 +732,7 @@

    diff --git a/post/a38c0645.html b/post/a38c0645.html index 5639d912..97da2358 100644 --- a/post/a38c0645.html +++ b/post/a38c0645.html @@ -694,7 +694,7 @@

    总结 - 33 + 34 日志 @@ -716,7 +716,7 @@

    总结 - 30 + 31 标签 diff --git a/post/ab706eb5.html b/post/ab706eb5.html index 74a5b4d3..da650851 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -697,7 +697,7 @@

    总结 - 33 + 34 日志 @@ -719,7 +719,7 @@

    总结 - 30 + 31 标签 diff --git a/post/b1d4025b.html b/post/b1d4025b.html index 6cbce5b9..2991e0b8 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -627,7 +627,7 @@

    hello world

    - 33 + 34 日志 @@ -649,7 +649,7 @@

    hello world

    diff --git a/post/bc557e1a.html b/post/bc557e1a.html index d97b5b19..717d63ac 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -762,7 +762,7 @@
    - 33 + 34 日志 @@ -784,7 +784,7 @@
    - 30 + 31 标签 diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index 33ba0a08..f47b4cce 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -714,7 +714,7 @@

    - 33 + 34 日志 @@ -736,7 +736,7 @@

    diff --git a/post/c34b451f.html b/post/c34b451f.html index 3fba3b7b..f60a46ff 100644 --- a/post/c34b451f.html +++ b/post/c34b451f.html @@ -753,7 +753,7 @@

    总结 - 33 + 34 日志 @@ -775,7 +775,7 @@

    总结 - 30 + 31 标签 diff --git a/post/d7d0fc76.html b/post/d7d0fc76.html index 60a65a21..f6c5d9aa 100644 --- a/post/d7d0fc76.html +++ b/post/d7d0fc76.html @@ -679,7 +679,7 @@

    - 33 + 34 日志 @@ -701,7 +701,7 @@

    - 30 + 31 标签 diff --git a/post/e09f0428.html b/post/e09f0428.html index 94285c31..aa1c01de 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -684,7 +684,7 @@

    - 33 + 34 日志 @@ -706,7 +706,7 @@

    - 30 + 31 标签 diff --git a/post/ee27c07f.html b/post/ee27c07f.html index e146e17d..034b4701 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -677,7 +677,7 @@

    - 33 + 34 日志 @@ -699,7 +699,7 @@

    diff --git a/post/f440d00b.html b/post/f440d00b.html index 408ddb89..e528790a 100644 --- a/post/f440d00b.html +++ b/post/f440d00b.html @@ -713,7 +713,7 @@

    总结 - 33 + 34 日志 @@ -735,7 +735,7 @@

    总结 - 30 + 31 标签 diff --git a/post/f92758d8.html b/post/f92758d8.html index 5afe9830..02f5a346 100644 --- a/post/f92758d8.html +++ b/post/f92758d8.html @@ -701,7 +701,7 @@

    总结 - 33 + 34 日志 @@ -723,7 +723,7 @@

    总结 - 30 + 31 标签 diff --git a/post/fa75f5d7.html b/post/fa75f5d7.html index 3e2dd541..1085210b 100644 --- a/post/fa75f5d7.html +++ b/post/fa75f5d7.html @@ -717,7 +717,7 @@

    - 33 + 34 日志 @@ -739,7 +739,7 @@

    - 30 + 31 标签 diff --git a/post/fe76043.html b/post/fe76043.html index 7529b948..33724fdd 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -680,7 +680,7 @@

    总结 - 33 + 34 日志 @@ -702,7 +702,7 @@

    总结 - 30 + 31 标签 diff --git a/search.xml b/search.xml index d8707bfe..b12ac229 100644 --- a/search.xml +++ b/search.xml @@ -1,5 +1,19 @@ + + <![CDATA[如何实现一个简易版的 Spring - 如何实现 Constructor 注入]]> + %2Fpost%2F315ff4dc.html + + + Java + Spring + + + Java + Spring + Constructor 注入 + + <![CDATA[如何实现一个简易版的 Spring - 如何实现 Setter 注入]]> %2Fpost%2F24cb2421.html diff --git a/sitemap.xml b/sitemap.xml index d591c003..692954b0 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,13 @@ + + https://www.mghio.cn/post/315ff4dc.html + + 2021-01-17T06:46:20.341Z + + + https://www.mghio.cn/post/24cb2421.html diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index a4a25914..cd39c38c 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index fc00ad1d..6f600e79 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/Constructor-\346\263\250\345\205\245/index.html" "b/tags/Constructor-\346\263\250\345\205\245/index.html" new file mode 100644 index 00000000..f58e963c --- /dev/null +++ "b/tags/Constructor-\346\263\250\345\205\245/index.html" @@ -0,0 +1,1253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: Constructor 注入 | mghio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index 9d6f6da0..53e1d427 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/GC/index.html b/tags/GC/index.html index a1978dbe..f6631bb7 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/Guava/index.html b/tags/Guava/index.html index 026aff44..83318c74 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index 9cc7ae69..cc72ea0e 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index 1fd20f3f..d9b80868 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/IoC/index.html b/tags/IoC/index.html index 67f7a5e8..581db4e6 100644 --- a/tags/IoC/index.html +++ b/tags/IoC/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/JDK/index.html b/tags/JDK/index.html index 71c70f77..e8a33199 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/JVM/index.html b/tags/JVM/index.html index 5812574a..59f190af 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -412,7 +412,7 @@

    - 33 + 34 日志 @@ -434,7 +434,7 @@

    diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index 15b28a8b..c2d8bfea 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index fc26197c..a7d3e6af 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/Java/index.html b/tags/Java/index.html index 6c6cb942..03bf2095 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -309,6 +309,32 @@

    Java标签 + + + + + +
    @@ -541,32 +567,6 @@

    - - - - - - @@ -624,7 +624,7 @@

    - 33 + 34 日志 @@ -646,7 +646,7 @@

    diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index 449f8dbe..55b32dec 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -309,6 +309,32 @@

    Java标签 + + + + + +
    @@ -541,32 +567,6 @@

    - - - - - - @@ -624,7 +624,7 @@

    - 33 + 34 日志 @@ -646,7 +646,7 @@

    diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index 9a048911..d8b30394 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -309,6 +309,32 @@

    Java标签 + + + + + +
    @@ -572,7 +598,7 @@

    - 33 + 34 日志 @@ -594,7 +620,7 @@

    diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index 7a933f6e..431162c6 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/List/index.html b/tags/List/index.html index 40ff710a..4822e1be 100644 --- a/tags/List/index.html +++ b/tags/List/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/RabbitMQ/index.html b/tags/RabbitMQ/index.html index 4baa24a6..8a0ede8a 100644 --- a/tags/RabbitMQ/index.html +++ b/tags/RabbitMQ/index.html @@ -412,7 +412,7 @@

    - 33 + 34 日志 @@ -434,7 +434,7 @@

    diff --git a/tags/Spring/index.html b/tags/Spring/index.html index 672647ce..b41079c6 100644 --- a/tags/Spring/index.html +++ b/tags/Spring/index.html @@ -309,6 +309,32 @@

    Spring标签 + + + + + +
    @@ -412,7 +438,7 @@

    - 33 + 34 日志 @@ -434,7 +460,7 @@

    diff --git a/tags/String/index.html b/tags/String/index.html index 764fecf4..025d1639 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/index.html b/tags/index.html index a63c203d..c35a052b 100644 --- a/tags/index.html +++ b/tags/index.html @@ -317,10 +317,10 @@

    @@ -378,7 +378,7 @@

    - 33 + 34 日志 @@ -400,7 +400,7 @@

    diff --git a/tags/mockito/index.html b/tags/mockito/index.html index bfe78053..0e5ae67a 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git a/tags/test/index.html b/tags/test/index.html index 5b983132..7f48f353 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index ff45e4d1..926c7fbf 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index 0c1e50d1..a4d23f72 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -412,7 +412,7 @@

    - 33 + 34 日志 @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 7bedacef..1fd7be69 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -412,7 +412,7 @@

    - 33 + 34 日志 @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index fcf577b4..c363f666 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index 692dc935..ab69ab1b 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -412,7 +412,7 @@

    - 33 + 34 日志 @@ -434,7 +434,7 @@

    diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index 34cb0295..eadfaf24 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 47fb05be..a20aea0a 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 594dd62b..4f4395a3 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/\347\274\223\345\255\230/index.html" "b/tags/\347\274\223\345\255\230/index.html" index 0454b3ef..3ced39f8 100644 --- "a/tags/\347\274\223\345\255\230/index.html" +++ "b/tags/\347\274\223\345\255\230/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index a52579d4..ea400a1b 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -386,7 +386,7 @@

    - 33 + 34 日志 @@ -408,7 +408,7 @@

    From ee16030a0d41dda9ce8b12c2c890f6ba99c15775 Mon Sep 17 00:00:00 2001 From: mghio Date: Sat, 23 Jan 2021 11:14:31 +0800 Subject: [PATCH 15/19] Site updated: 2021-01-23 11:14:30 --- about/index.html | 9 +++++++-- archives/2019/10/index.html | 9 +++++++-- archives/2019/11/index.html | 9 +++++++-- archives/2019/12/index.html | 9 +++++++-- archives/2019/index.html | 9 +++++++-- archives/2019/page/2/index.html | 9 +++++++-- archives/2020/01/index.html | 9 +++++++-- archives/2020/02/index.html | 9 +++++++-- archives/2020/03/index.html | 9 +++++++-- archives/2020/04/index.html | 9 +++++++-- archives/2020/05/index.html | 9 +++++++-- archives/2020/06/index.html | 9 +++++++-- archives/2020/07/index.html | 9 +++++++-- archives/2020/08/index.html | 9 +++++++-- archives/2020/09/index.html | 9 +++++++-- archives/2020/10/index.html | 9 +++++++-- archives/2020/11/index.html | 9 +++++++-- archives/2020/index.html | 9 +++++++-- archives/2020/page/2/index.html | 9 +++++++-- archives/2021/01/index.html | 9 +++++++-- archives/2021/index.html | 9 +++++++-- archives/index.html | 9 +++++++-- archives/page/2/index.html | 9 +++++++-- archives/page/3/index.html | 9 +++++++-- archives/page/4/index.html | 9 +++++++-- categories/JDK/Java/index.html | 9 +++++++-- .../index.html" | 9 +++++++-- categories/JDK/index.html | 9 +++++++-- categories/Java/Bloom-filter/index.html | 9 +++++++-- categories/Java/GC/index.html | 9 +++++++-- categories/Java/Guava/String/index.html | 9 +++++++-- categories/Java/Guava/index.html | 9 +++++++-- categories/Java/IDEA/index.html | 9 +++++++-- .../IDEA/\345\267\245\345\205\267/index.html" | 9 +++++++-- .../Java/IO\346\250\241\345\236\213/index.html" | 9 +++++++-- categories/Java/JVM/index.html | 9 +++++++-- categories/Java/List/index.html | 9 +++++++-- categories/Java/Spring/index.html | 9 +++++++-- categories/Java/index.html | 9 +++++++-- categories/Java/page/2/index.html | 9 +++++++-- categories/Java/page/3/index.html | 9 +++++++-- categories/Java/unit-test/index.html | 9 +++++++-- categories/Java/unit-test/mockito/index.html | 9 +++++++-- .../Java/\345\216\237\347\220\206/index.html" | 9 +++++++-- .../Java/\345\217\215\345\260\204/index.html" | 9 +++++++-- .../index.html" | 9 +++++++-- .../Java/\345\271\266\345\217\221/index.html" | 9 +++++++-- .../\350\277\233\351\230\266/index.html" | 9 +++++++-- .../Java/\345\274\202\346\255\245/index.html" | 9 +++++++-- .../Eureka/index.html" | 9 +++++++-- .../index.html" | 9 +++++++-- .../index.html" | 9 +++++++-- .../Java/\347\274\223\345\255\230/index.html" | 9 +++++++-- .../Java/\351\207\215\346\236\204/index.html" | 9 +++++++-- .../Linux\347\254\224\350\256\260/index.html" | 9 +++++++-- categories/RabbitMQ/Java/index.html | 9 +++++++-- categories/RabbitMQ/index.html | 9 +++++++-- categories/Spring/Java/index.html | 9 +++++++-- categories/Spring/index.html | 9 +++++++-- categories/index.html | 9 +++++++-- .../CAP\345\256\232\347\220\206/index.html" | 9 +++++++-- .../index.html" | 9 +++++++-- css/main.css | 2 +- images/beian_icon.png | Bin 0 -> 19256 bytes index.html | 9 +++++++-- page/2/index.html | 9 +++++++-- page/3/index.html | 9 +++++++-- page/4/index.html | 9 +++++++-- post/102cd3d9.html | 9 +++++++-- post/11cb7677.html | 9 +++++++-- post/192cb539.html | 9 +++++++-- post/24042edf.html | 9 +++++++-- post/24cb2421.html | 9 +++++++-- post/315ff4dc.html | 9 +++++++-- post/34755d6c.html | 9 +++++++-- post/3ae0ff4e.html | 9 +++++++-- post/4615256d.html | 9 +++++++-- post/4b00e13c.html | 9 +++++++-- post/4ea48fa7.html | 9 +++++++-- post/51e5bd99.html | 9 +++++++-- post/558ca0bd.html | 9 +++++++-- post/710bd10b.html | 9 +++++++-- post/7528c810.html | 9 +++++++-- post/7b9ead86.html | 9 +++++++-- post/7eb2637f.html | 9 +++++++-- post/817c7d82.html | 9 +++++++-- post/8a061473.html | 9 +++++++-- post/8bd965a0.html | 9 +++++++-- post/99ea2970.html | 9 +++++++-- post/a38c0645.html | 9 +++++++-- post/ab706eb5.html | 9 +++++++-- post/b1d4025b.html | 9 +++++++-- post/bc557e1a.html | 9 +++++++-- post/bfcdfeaf.html | 9 +++++++-- post/c34b451f.html | 9 +++++++-- post/d7d0fc76.html | 9 +++++++-- post/e09f0428.html | 9 +++++++-- post/ee27c07f.html | 9 +++++++-- post/f440d00b.html | 9 +++++++-- post/f92758d8.html | 9 +++++++-- post/fa75f5d7.html | 9 +++++++-- post/fe76043.html | 9 +++++++-- tags/Bloom-filter/index.html | 9 +++++++-- "tags/CAP\345\256\232\347\220\206/index.html" | 9 +++++++-- .../index.html" | 9 +++++++-- tags/Eureka/index.html | 9 +++++++-- tags/GC/index.html | 9 +++++++-- tags/Guava/index.html | 9 +++++++-- tags/IDEA/index.html | 9 +++++++-- "tags/IO\346\250\241\345\236\213/index.html" | 9 +++++++-- tags/IoC/index.html | 9 +++++++-- tags/JDK/index.html | 9 +++++++-- tags/JVM/index.html | 9 +++++++-- "tags/Java-\345\216\237\347\220\206/index.html" | 9 +++++++-- "tags/Java-\345\271\266\345\217\221/index.html" | 9 +++++++-- tags/Java/index.html | 9 +++++++-- tags/Java/page/2/index.html | 9 +++++++-- tags/Java/page/3/index.html | 9 +++++++-- "tags/Linux\347\254\224\350\256\260/index.html" | 9 +++++++-- tags/List/index.html | 9 +++++++-- tags/RabbitMQ/index.html | 9 +++++++-- tags/Spring/index.html | 9 +++++++-- tags/String/index.html | 9 +++++++-- tags/index.html | 9 +++++++-- tags/mockito/index.html | 9 +++++++-- tags/test/index.html | 9 +++++++-- .../index.html" | 9 +++++++-- "tags/\345\217\215\345\260\204/index.html" | 9 +++++++-- .../index.html" | 9 +++++++-- "tags/\345\267\245\345\205\267/index.html" | 9 +++++++-- "tags/\345\271\266\345\217\221/index.html" | 9 +++++++-- "tags/\345\274\202\346\255\245/index.html" | 9 +++++++-- .../index.html" | 9 +++++++-- .../index.html" | 9 +++++++-- "tags/\347\274\223\345\255\230/index.html" | 9 +++++++-- "tags/\351\207\215\346\236\204/index.html" | 9 +++++++-- 136 files changed, 939 insertions(+), 269 deletions(-) create mode 100644 images/beian_icon.png diff --git a/about/index.html b/about/index.html index 73a06e87..802cca75 100644 --- a/about/index.html +++ b/about/index.html @@ -680,7 +680,13 @@

    mghio - + + @@ -693,7 +699,6 @@

    diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html index 8961738a..bb87f10b 100644 --- a/archives/2019/10/index.html +++ b/archives/2019/10/index.html @@ -801,7 +801,13 @@

    mghio - + + @@ -814,7 +820,6 @@

    -
    diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html index ef046b74..64ce8ac2 100644 --- a/archives/2019/11/index.html +++ b/archives/2019/11/index.html @@ -766,7 +766,13 @@

    mghio - + +

    @@ -779,7 +785,6 @@

    -
    diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html index 9af254c3..f6fcba42 100644 --- a/archives/2019/12/index.html +++ b/archives/2019/12/index.html @@ -766,7 +766,13 @@

    mghio - + +

    @@ -779,7 +785,6 @@

    -
    diff --git a/archives/2019/index.html b/archives/2019/index.html index a93b3796..74894a1f 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -980,7 +980,13 @@

    mghio - + +

    @@ -993,7 +999,6 @@

    -
    diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html index 34ca164c..f29a4703 100644 --- a/archives/2019/page/2/index.html +++ b/archives/2019/page/2/index.html @@ -735,7 +735,13 @@

    mghio - + +

    @@ -748,7 +754,6 @@

    -
    diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html index 6797714e..67994955 100644 --- a/archives/2020/01/index.html +++ b/archives/2020/01/index.html @@ -696,7 +696,13 @@

    mghio - + +

    @@ -709,7 +715,6 @@

    -
    diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html index 2bd58929..779186bc 100644 --- a/archives/2020/02/index.html +++ b/archives/2020/02/index.html @@ -661,7 +661,13 @@

    mghio - + +

    @@ -674,7 +680,6 @@

    -
    diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index 4f2560d1..694dfd7d 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -766,7 +766,13 @@

    mghio - + +

    @@ -779,7 +785,6 @@

    -
    diff --git a/archives/2020/04/index.html b/archives/2020/04/index.html index 10fede6f..22a7c0b8 100644 --- a/archives/2020/04/index.html +++ b/archives/2020/04/index.html @@ -766,7 +766,13 @@

    mghio - + +

    @@ -779,7 +785,6 @@

    -
    diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index 63ccb5c8..ff53deb4 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -696,7 +696,13 @@

    mghio - + +

    @@ -709,7 +715,6 @@

    -
    diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html index 0bcb5b7b..a0368416 100644 --- a/archives/2020/06/index.html +++ b/archives/2020/06/index.html @@ -661,7 +661,13 @@

    mghio - + +

    @@ -674,7 +680,6 @@

    -
    diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html index 8c24bd67..914af405 100644 --- a/archives/2020/07/index.html +++ b/archives/2020/07/index.html @@ -661,7 +661,13 @@

    mghio - + +

    @@ -674,7 +680,6 @@

    -
    diff --git a/archives/2020/08/index.html b/archives/2020/08/index.html index eff03064..ca96e101 100644 --- a/archives/2020/08/index.html +++ b/archives/2020/08/index.html @@ -696,7 +696,13 @@

    mghio - + +

    @@ -709,7 +715,6 @@

    -
    diff --git a/archives/2020/09/index.html b/archives/2020/09/index.html index 64de0bcd..8c45d839 100644 --- a/archives/2020/09/index.html +++ b/archives/2020/09/index.html @@ -661,7 +661,13 @@

    mghio - + +

    @@ -674,7 +680,6 @@

    -
    diff --git a/archives/2020/10/index.html b/archives/2020/10/index.html index 63e06ee9..2484fd5c 100644 --- a/archives/2020/10/index.html +++ b/archives/2020/10/index.html @@ -661,7 +661,13 @@

    mghio - + +

    @@ -674,7 +680,6 @@

    -
    diff --git a/archives/2020/11/index.html b/archives/2020/11/index.html index 7423e2ff..9c8ef31f 100644 --- a/archives/2020/11/index.html +++ b/archives/2020/11/index.html @@ -661,7 +661,13 @@

    mghio - + +

    @@ -674,7 +680,6 @@

    -
    diff --git a/archives/2020/index.html b/archives/2020/index.html index cf08cc38..0b7bc440 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -980,7 +980,13 @@

    mghio - + +

    @@ -993,7 +999,6 @@

    -
    diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html index 11f8d675..51a37ac1 100644 --- a/archives/2020/page/2/index.html +++ b/archives/2020/page/2/index.html @@ -980,7 +980,13 @@

    mghio - + +

    @@ -993,7 +999,6 @@

    -
    diff --git a/archives/2021/01/index.html b/archives/2021/01/index.html index dab3f669..7f04ece0 100644 --- a/archives/2021/01/index.html +++ b/archives/2021/01/index.html @@ -661,7 +661,13 @@

    mghio - + +

    @@ -674,7 +680,6 @@

    -
    diff --git a/archives/2021/index.html b/archives/2021/index.html index e83e1bec..e162c14e 100644 --- a/archives/2021/index.html +++ b/archives/2021/index.html @@ -661,7 +661,13 @@

    mghio - + +

    @@ -674,7 +680,6 @@

    -
    diff --git a/archives/index.html b/archives/index.html index 1077009f..058d2ad3 100644 --- a/archives/index.html +++ b/archives/index.html @@ -985,7 +985,13 @@

    mghio - + +

    @@ -998,7 +1004,6 @@

    -
    diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 0412533b..45fc59d5 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -980,7 +980,13 @@

    mghio - + +

    @@ -993,7 +999,6 @@

    -
    diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 5b0092b8..81eb16d5 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -985,7 +985,13 @@

    mghio - + +

    @@ -998,7 +1004,6 @@

    -
    diff --git a/archives/page/4/index.html b/archives/page/4/index.html index ca1f5393..db70549a 100644 --- a/archives/page/4/index.html +++ b/archives/page/4/index.html @@ -770,7 +770,13 @@

    mghio - + +

    @@ -783,7 +789,6 @@

    -
    diff --git a/categories/JDK/Java/index.html b/categories/JDK/Java/index.html index 073f6bb5..9289bcf0 100644 --- a/categories/JDK/Java/index.html +++ b/categories/JDK/Java/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 9453f58d..6b0e9ff1 100644 --- "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/JDK/index.html b/categories/JDK/index.html index ae2007da..7e3452d1 100644 --- a/categories/JDK/index.html +++ b/categories/JDK/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/Java/Bloom-filter/index.html b/categories/Java/Bloom-filter/index.html index 1715cb29..1a87e4ef 100644 --- a/categories/Java/Bloom-filter/index.html +++ b/categories/Java/Bloom-filter/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/Java/GC/index.html b/categories/Java/GC/index.html index a74064cd..5d89855c 100644 --- a/categories/Java/GC/index.html +++ b/categories/Java/GC/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/Java/Guava/String/index.html b/categories/Java/Guava/String/index.html index 7524e22b..60a3e5cf 100644 --- a/categories/Java/Guava/String/index.html +++ b/categories/Java/Guava/String/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/Java/Guava/index.html b/categories/Java/Guava/index.html index 7a070eb8..7c1a4f5e 100644 --- a/categories/Java/Guava/index.html +++ b/categories/Java/Guava/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/Java/IDEA/index.html b/categories/Java/IDEA/index.html index d32fa136..4abf4713 100644 --- a/categories/Java/IDEA/index.html +++ b/categories/Java/IDEA/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" index 2bee6e8b..4adc4568 100644 --- "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" +++ "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/Java/IO\346\250\241\345\236\213/index.html" "b/categories/Java/IO\346\250\241\345\236\213/index.html" index 46073b6e..d8f40603 100644 --- "a/categories/Java/IO\346\250\241\345\236\213/index.html" +++ "b/categories/Java/IO\346\250\241\345\236\213/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/Java/JVM/index.html b/categories/Java/JVM/index.html index 8153c59e..102a526e 100644 --- a/categories/Java/JVM/index.html +++ b/categories/Java/JVM/index.html @@ -669,7 +669,13 @@

    mghio - + +

    @@ -682,7 +688,6 @@

    -
    diff --git a/categories/Java/List/index.html b/categories/Java/List/index.html index 9c9da7f7..a5da57f9 100644 --- a/categories/Java/List/index.html +++ b/categories/Java/List/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/Java/Spring/index.html b/categories/Java/Spring/index.html index 8d0fe60d..ffefa1bc 100644 --- a/categories/Java/Spring/index.html +++ b/categories/Java/Spring/index.html @@ -669,7 +669,13 @@

    mghio - + +

    @@ -682,7 +688,6 @@

    -
    diff --git a/categories/Java/index.html b/categories/Java/index.html index c8e07443..96e8589a 100644 --- a/categories/Java/index.html +++ b/categories/Java/index.html @@ -881,7 +881,13 @@

    mghio - + +

    @@ -894,7 +900,6 @@

    -
    diff --git a/categories/Java/page/2/index.html b/categories/Java/page/2/index.html index 3adf19b1..8bade47c 100644 --- a/categories/Java/page/2/index.html +++ b/categories/Java/page/2/index.html @@ -881,7 +881,13 @@

    mghio - + +

    @@ -894,7 +900,6 @@

    -
    diff --git a/categories/Java/page/3/index.html b/categories/Java/page/3/index.html index 684ed523..477f84b9 100644 --- a/categories/Java/page/3/index.html +++ b/categories/Java/page/3/index.html @@ -829,7 +829,13 @@

    mghio - + +

    @@ -842,7 +848,6 @@

    -
    diff --git a/categories/Java/unit-test/index.html b/categories/Java/unit-test/index.html index f5545876..220fcd80 100644 --- a/categories/Java/unit-test/index.html +++ b/categories/Java/unit-test/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/Java/unit-test/mockito/index.html b/categories/Java/unit-test/mockito/index.html index d41fa6de..a4cdcb7f 100644 --- a/categories/Java/unit-test/mockito/index.html +++ b/categories/Java/unit-test/mockito/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/Java/\345\216\237\347\220\206/index.html" "b/categories/Java/\345\216\237\347\220\206/index.html" index 096cc86c..52457705 100644 --- "a/categories/Java/\345\216\237\347\220\206/index.html" +++ "b/categories/Java/\345\216\237\347\220\206/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/Java/\345\217\215\345\260\204/index.html" "b/categories/Java/\345\217\215\345\260\204/index.html" index c9560e06..700e0e07 100644 --- "a/categories/Java/\345\217\215\345\260\204/index.html" +++ "b/categories/Java/\345\217\215\345\260\204/index.html" @@ -669,7 +669,13 @@

    mghio - + +

    @@ -682,7 +688,6 @@

    -
    diff --git "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" index f0710416..04d68075 100644 --- "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" @@ -669,7 +669,13 @@

    mghio - + +

    @@ -682,7 +688,6 @@

    -
    diff --git "a/categories/Java/\345\271\266\345\217\221/index.html" "b/categories/Java/\345\271\266\345\217\221/index.html" index d5edf2f5..bafaef1e 100644 --- "a/categories/Java/\345\271\266\345\217\221/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/index.html" @@ -695,7 +695,13 @@

    mghio - + +

    @@ -708,7 +714,6 @@

    -
    diff --git "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" index 41abda34..7883ffd0 100644 --- "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/Java/\345\274\202\346\255\245/index.html" "b/categories/Java/\345\274\202\346\255\245/index.html" index 9a949eff..9a1c643e 100644 --- "a/categories/Java/\345\274\202\346\255\245/index.html" +++ "b/categories/Java/\345\274\202\346\255\245/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" index ffc0e462..a62f7d2e 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 56b5d3bb..3025c5d6 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" index a012ce8e..7032559e 100644 --- "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" +++ "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" @@ -669,7 +669,13 @@

    mghio - + +

    @@ -682,7 +688,6 @@

    -
    diff --git "a/categories/Java/\347\274\223\345\255\230/index.html" "b/categories/Java/\347\274\223\345\255\230/index.html" index 55cf73e4..2ca0d851 100644 --- "a/categories/Java/\347\274\223\345\255\230/index.html" +++ "b/categories/Java/\347\274\223\345\255\230/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/Java/\351\207\215\346\236\204/index.html" "b/categories/Java/\351\207\215\346\236\204/index.html" index 458ce5e7..169dbba4 100644 --- "a/categories/Java/\351\207\215\346\236\204/index.html" +++ "b/categories/Java/\351\207\215\346\236\204/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/Linux\347\254\224\350\256\260/index.html" "b/categories/Linux\347\254\224\350\256\260/index.html" index c5df8239..d7da6f84 100644 --- "a/categories/Linux\347\254\224\350\256\260/index.html" +++ "b/categories/Linux\347\254\224\350\256\260/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/RabbitMQ/Java/index.html b/categories/RabbitMQ/Java/index.html index 39044740..2a5d6977 100644 --- a/categories/RabbitMQ/Java/index.html +++ b/categories/RabbitMQ/Java/index.html @@ -669,7 +669,13 @@

    mghio - + +

    @@ -682,7 +688,6 @@

    -
    diff --git a/categories/RabbitMQ/index.html b/categories/RabbitMQ/index.html index a15c16bd..4ecc8603 100644 --- a/categories/RabbitMQ/index.html +++ b/categories/RabbitMQ/index.html @@ -669,7 +669,13 @@

    mghio - + +

    @@ -682,7 +688,6 @@

    -
    diff --git a/categories/Spring/Java/index.html b/categories/Spring/Java/index.html index 68e89aaf..859742b2 100644 --- a/categories/Spring/Java/index.html +++ b/categories/Spring/Java/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/Spring/index.html b/categories/Spring/index.html index 4f24b4a9..e826943e 100644 --- a/categories/Spring/index.html +++ b/categories/Spring/index.html @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/categories/index.html b/categories/index.html index 1a01a41f..a63ab16c 100644 --- a/categories/index.html +++ b/categories/index.html @@ -634,7 +634,13 @@

    mghio - + +
    @@ -647,7 +653,6 @@

    -
    diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" index 32bb88c7..2da3d961 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index fe119ec7..09ea3148 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -643,7 +643,13 @@

    mghio - + +

    @@ -656,7 +662,6 @@

    -
    diff --git a/css/main.css b/css/main.css index da4c7c67..edb3a43d 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #ee05b6; + background: #f7ff69; } .links-of-blogroll { font-size: 13px; diff --git a/images/beian_icon.png b/images/beian_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9f763946dd6606addeab24e40e2369124d53a048 GIT binary patch literal 19256 zcmeI4c{G&a_rPDYSRz?cRHh**jbW@aG4@bIvPT-TFwB@~W-OyD?Wzv>B_s{Rld(O-|_qor#_kBLkeeV0rob%2J%k9R3{F3|t z00^3z7+NvUVlyw^Ma=h*6RQQ8CqA-?0~G)SL}y-HKwQEK0N^*r8yHwxx|3)msym4c zGBq#&ktrk`o`3}azm~+EzV=b$%aQHl*rm4m&BNDY2nPVL41>2y*dbLo5_Jg5x422i0+8_A>U(Yr%K>1Rhwc|hyQVY6b(I8g z1LQ_US&_n%Gm*+2%rNj(k;LhZUs~+T33kyRV#pNJ8xk4foK3A(D&AUo>^XyWe)cdW-8O z41Fk1{o*-H0wdRsw0|i)&Ak8+-d;D<;?mXC#6zy+y5?QtnYjySu?5`QC!AGU`H~&^ zANx<7qH9j+u1QLYs+S*2-* zruU+}e6p=VyQ>%ID|?N1%Y3Ok5;PsUq5ie%b*D|@Cr9j0t?AQ$&3A^Qd&KsRs{a#~U#0uXjnh0(_WAgW{{ zOjm&mcodWV1^^1*t#G;&En!x{3jl`62R2^QTfF417^74u;qL0fQVDLe2muY_~&Dr*XMcZfJ0=p#!k+Os0*-ipGbd<*od zctufb5yzLghBkw1c_m^)7l2VFs*%Czpq}GmJHX{tlyvS)eUAud6PfoAiWoe^N%wPj zYZVA~a_VHEv2yf*oEYwr>QP=4nCXeSudHpMmzXcYDWFGciuE0 z;AAK|xL#QZcltTX>GUz9JtyoXyX@6$!_?5L?KOPFrAm`fL%g!wr-DWMd3PTc zzDGD19&T)JW^Zt5UB67ONCB@M-=V|G_tt}>E?MNR^B0*Y^K(U954YdKkQ-dPW^K~C z-Rp%!U7}26g&st9Zs%XSE*xemVCreoY63~$nT~7_#wVD`^@S53yzJ!731)y|BJ#qQ zhFe5VKDghRCx$3L{@RQ$Rn{s!T4bvlR;O#hh4V1|*yPJQ9%Uvy<-L3yao*9CnCxQ- z-FYliRMk6f-J|&B2G!}1w8qDAcsKmGJG6&Z!1v^FYgxL-Wtp~xA;8QU{~ zXSy$2+fZ$E8tIn>tgqNCy|UXj;NljW8D%Oa&fIlZ&P2bN&%#M5ALu@_ zod(p)I0h~Pm-u$?BQBwe>m9@J=LuVD*VYQw?t}0^bRgH8JhE_Efms?Y{w>8Vt^<^T z>-Na3aV+bN*+?%gJyV+UiI*m1Z7S1a7{S+o##1xe*N&_SC^JmyB9>1xu?~ermfGH8$9OrM$JzG ziDQsfxiVB=V%t2mP_B4bYkFCFd1vv4N70^fxPtoJC$yTHs!eT-X2yg5P~Ef+cDc`4AUm3zD<3^COd+qlwJIi zctm{ltxH+)S!F))#CEaQVqqH^HjM4`YEkZ=>gVr|>t8eg|A_jy?j!MI-RhcEBCDG= z(>Cv?(7bDW2;{=P^jE6)Gs`mX_t?2fxusAON7W=QZVRs#iSdb%*h$Pdnc;Qbzxqs< zVP9gsY5gU6FcdO_@h3yakjhAh0Z2)YC* zuD^s&&_S9KMJkneFExQyX>;2YS1a$XfoY|VDWuZswc-w^oNf#%~dTMU* z9`7(F9M6}=uZ)$L2oT$_5q4RzcSr6{+FsiDrY1(G!=zhL=tx-R>D!xIJ#JBa+!!7N zD+0PdK0i4Ba{d9oW1oyhVnk@7vU~$4I?I~Nv`@UDa(5HrR1!Mltk2TW*BN2lu$NZ%5=!lEm~%Y3!y`@``^ER2d%LsEBK&&%Jc75O&N z_RL4k7n=hNKD!^a*y3HG!e?QnK#y1%d0S@G+}5z^C8O^7-scc_bV77Onw22_Y_7sH zr9AmO3!H*Nlwc?QE%BjL)Uk)-oiY>D(N=N75wrTVT&rwLq2*@KOA3CwR_yZ2Hz_i4 ze5%rp`_elhBXDr}{-W?}migCiH0S#{jC6oYjP5L#Iki*5S5ev7ssQ7MA8rV!cCXGk zJ8k*e-pb~^2fgimsMVo{3l|I&4%(@n$&7wb?Unt(@itlQbWgAA?)vtN`}e)Ee3w#tzwQ2`_Sm4j zG2T8Cxn%5Tu#m1<#jNy&-w+9MO42czC( zU^0>tx9ey>jcuckn@z=fI`42UaxMl|rcD#DPPAi-C!MtyC{m_%3&mN_X)MuZbDLS907Y$YPOXYdVy;zmM zu3+qw&&L4?U;aU}HfR4ZzpGQlEz`Y=KQHYK%KdU3TT1Nsw5N1W-F=6pLqdGVlD>U;qW75Es8<;|8KQL$18u+3`>0pC+oxYoZmYAOY91Dt zI8|4YP0t*q3|+~*il~&SlrF5LYmZ!<%BpP*7|I_iXs;}ij+LL%{bD&<{~2AG@z`P< z*}ebE6mxTEz1`pjS0fX=uZLpo1xso~A0PBu7@uy&S`fs;J`+K6{7_bhKU&{}{bU?(?P#`}d z!HbIU(+1D_MKC|lG(*9l*)B9sZLr=vHoN;C3dUdi{7{V^cbnoh<- zt*}&*HwBF~^1*u1Wd3v!{6iQ}uqYadVof3ukl(Uw?%Nad%hOC& zf#mJ*UKo-ub%Pd^)nsnI=e%JJQ8X-)X{iQLR)#1mSt~P>Q5B)4q@bk9%*uIAzV&4B zVb08b42p*O7cal`W%WbC;BoYS@-o-+S0Co)2vaXA4dsQ#ni?XRV^_rEF$hg1S2PN) zsRmKS!CfKhSXB%JjzhyCSWTQN9Hy>;!Kq?r2l=b{Z>|kVXz!UkV7mUc@G&Gb)BVr1 zLSQi%6joCS4bjxlP-3#gszEeW;V6hJ8izrtE5S5zu%ChEIr}Y;1%iF`NvrP;O4hbCU`0{o9Oeh zjG1e*m1ie*@2{;t6a@Ti1tFs-RP4;c)CT`pnLkU;&x$f*GrPbMDD+J2L852U7mLw? z{?a;kSwAhmo8f<-&VNJj&Hp^}zsK-($9l0#|8K5ld;Q%Bm4u`Dq9|BBH)e+X%gX%b z^;a`i_gc`IT1~+JA4~)l<@3LrhJRaC|1YLtE{oCbC@(iG1_}L#83 z8tTC{RA8DaYO2aGRipnY(f(5KTrn6N8mEq9U-15v!`}k_ddXVQe;e>TE(Rn5iDFK| zV38{Gt>>EO=4GB0^H)a8Z$C03saD4NAX6g)b!E7^Is~T3ES_^0F|Xe|KNvIuN1_l> zG$fvga>GK&UT#{@xyE@tXKwxoW))^u1k`NxV|xFsjkUl1Of@BV&-T}VDKQVI^33~p z)A?#vQwR2@^VO`TbCxz#7UgY3n&xb|J!NmfEy~x4Eo)3$bgNp?Sdy#{SJs%b= z2Nw$v_96!tdp;~$4lWiT>_rYP_Iy~h99%3w*oz!o?D?>0Ik;GWuopSF*z;l0a&WN# zVJ~uUvFF30<=|og!d~RyV$X*~%fZD0guTeY#hwp~mV=802z!x(i#;C}Ee9715cVPm z7kfS|S`IE2AnZjBF7|v_v>aS4K-h~MTyCiIq73_^$(i;6nf~@s)Y*0RV3$0O;KV0Elw{AVG?BDc=GB3zwN1>RJ1> z7(VSI?HXHMIWm6x6Z7y%(DW(HS1^}p5oGWjV(XDlJ~W8&nkHT^9)UBq`# zdJ?Et6SOUO36LopDa_rTeMmN(=RhhpcPWg?a=hbK+C5LOET6D^Pw_6AL5}-L?BNKmM~&;h3|ExBu?QU^7N~q4;5#z? z**vMi?RNK|ma}hnz;Q z6*mp1{a+JplzQQp2Jf7ZiHT}iPi>`>?--2|cqaT;KR7Mo%ulv>DVvimRn%iS(TA@X zB&m#)%e|aZl9x@lT|##kXFzRFzN#FO=Do1ulKKYE&Zt1g5>0^sp)I}$@2!w<` z%r$U{SsZDYwLx@X$5O(oHM{b-Yn}Xujtx-gno*CFMUBMxF~|1d!Pf?RLAW=3mIUD$SCA(?T@?8@3G$HIFr zCwUNo++W{my$G6IbsMUG$9Qc`CdOA>-puI&Wmqfg*1cx;!x(RoD=DdRUA)2k!YaiG zMN+=HWap&cYpLanKl}R?X&u+ucVMtrmV!7+O*yI-o|dp-*cZNNL)7}>+q&x=$_fqc zRWabVxDO_X3f^stE>Ar4Wa^_`tKZ1PvQWqPlvgSqc0DlcOT^jq6I>X-!EVInMRKw6 z3!LJwp^461HaCijqH5mMO-3(Qd|&-a9{pyoTxhFPWZrP;MW}q)Mq22H`fNDkx%+V6 z;_SVnPt^!6#&sT-F5X&}Kenpy?fNiVi?4&%RN5=9e6ox~O&b^(jv^M=9K5`hdUtJ6 zwm_4QLFT;=tucEe9Ym)2T#FX<90=Havu0c;{ID=UbNm`W=$Sh3jQg3X9WucZfs&D?-Eu+@Lke}9aJ|NSbNy((&o`0*Er=e{`d^2D6Y($o+8 z&(#h|f-dFpG8V0nJc&y!PcCXpx4E2hbzlqh?Z{bTTh2OH&p7!^vFlJznHIYppWYp5 zdlp#~Va9cJjmV;nsN@bsN05F?BjV8mBiVJ_k%#xC>C4JRef3#;Wo1*H{;@`g=hl<% z8i>A|heqs103%Lk@{07bBdr~)XsW#%skOpUf1X6x@c_#dhPKRf^c literal 0 HcmV?d00001 diff --git a/index.html b/index.html index c4f16626..d260b971 100644 --- a/index.html +++ b/index.html @@ -2669,7 +2669,13 @@

    前言 mghio - + +

    @@ -2682,7 +2688,6 @@

    前言 diff --git a/page/2/index.html b/page/2/index.html index 30c90416..4d6337d6 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -2677,7 +2677,13 @@

    前言 mghio - + + @@ -2690,7 +2696,6 @@

    前言 diff --git a/page/3/index.html b/page/3/index.html index a0e67172..2ed61eb6 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -2710,7 +2710,13 @@

    mghio - + + @@ -2723,7 +2729,6 @@

    diff --git a/page/4/index.html b/page/4/index.html index 7d2f54d2..e1cab829 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -1384,7 +1384,13 @@

    mghio - + + @@ -1397,7 +1403,6 @@

    -
    diff --git a/post/102cd3d9.html b/post/102cd3d9.html index a9c0842e..aa7c2297 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -1119,7 +1119,13 @@

    总结 mghio - + +

    @@ -1132,7 +1138,6 @@

    总结 diff --git a/post/11cb7677.html b/post/11cb7677.html index a932fa47..bf3a3dfa 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -970,7 +970,13 @@

    总结 mghio - + + @@ -983,7 +989,6 @@

    总结 diff --git a/post/192cb539.html b/post/192cb539.html index afd06466..82d0fa36 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -1034,7 +1034,13 @@

    mghio - + + @@ -1047,7 +1053,6 @@

    - @@ -1055,7 +1061,6 @@

    总结 diff --git a/post/24cb2421.html b/post/24cb2421.html index 6a9141e2..0ed33907 100644 --- a/post/24cb2421.html +++ b/post/24cb2421.html @@ -975,7 +975,13 @@

    总结 mghio - + + @@ -988,7 +994,6 @@

    总结 diff --git a/post/315ff4dc.html b/post/315ff4dc.html index 38502e35..d28cefa4 100644 --- a/post/315ff4dc.html +++ b/post/315ff4dc.html @@ -954,7 +954,13 @@

    总结 mghio - + + @@ -967,7 +973,6 @@

    总结 diff --git a/post/34755d6c.html b/post/34755d6c.html index aaa570db..e7261a6f 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -949,7 +949,13 @@

    总结 mghio - + + @@ -962,7 +968,6 @@

    总结 diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index 728e66e2..336f29ea 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -1016,7 +1016,13 @@

    总结 mghio - + + @@ -1029,7 +1035,6 @@

    总结 diff --git a/post/4615256d.html b/post/4615256d.html index d774ccc5..3eea11d2 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -1025,7 +1025,13 @@

    mghio - + + @@ -1038,7 +1044,6 @@

    diff --git a/post/4b00e13c.html b/post/4b00e13c.html index 229b435f..687749ed 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -1124,7 +1124,13 @@

    总结 mghio - + + @@ -1137,7 +1143,6 @@

    总结 diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index 70187830..dbaed950 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -957,7 +957,13 @@

    总结 mghio - + + @@ -970,7 +976,6 @@

    总结 diff --git a/post/51e5bd99.html b/post/51e5bd99.html index 17b3accc..4ad47a6e 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -998,7 +998,13 @@

    mghio - + + @@ -1011,7 +1017,6 @@

    diff --git a/post/558ca0bd.html b/post/558ca0bd.html index 95710a6f..82aaf8ea 100644 --- a/post/558ca0bd.html +++ b/post/558ca0bd.html @@ -959,7 +959,13 @@

    3 mghio - + + @@ -972,7 +978,6 @@

    3 -
    diff --git a/post/710bd10b.html b/post/710bd10b.html index bc7fad32..719f8033 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -1004,7 +1004,13 @@

    总结 mghio - + +

    @@ -1017,7 +1023,6 @@

    总结 diff --git a/post/7528c810.html b/post/7528c810.html index d2fffb33..cbc30491 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -987,7 +987,13 @@

    总结 mghio - + + @@ -1000,7 +1006,6 @@

    总结 diff --git a/post/7b9ead86.html b/post/7b9ead86.html index bf06c4f1..b0c63c3e 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -987,7 +987,13 @@

    总结 mghio - + + @@ -1000,7 +1006,6 @@

    总结 diff --git a/post/7eb2637f.html b/post/7eb2637f.html index c20ffa70..285e126f 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -1026,7 +1026,13 @@

    mghio - + + @@ -1039,7 +1045,6 @@

    diff --git a/post/817c7d82.html b/post/817c7d82.html index 6914f726..81af1513 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1595,7 +1595,13 @@
    mghio - + + @@ -1608,7 +1614,6 @@
    diff --git a/post/8a061473.html b/post/8a061473.html index d1e9ac31..2174e520 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -1063,7 +1063,13 @@
    mghio - + + @@ -1076,7 +1082,6 @@
    diff --git a/post/8bd965a0.html b/post/8bd965a0.html index c580d98c..34b12d25 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -986,7 +986,13 @@

    mghio - + + @@ -999,7 +1005,6 @@

    - @@ -995,7 +1001,6 @@

    - @@ -979,7 +985,6 @@

    总结 diff --git a/post/ab706eb5.html b/post/ab706eb5.html index da650851..736b4b1b 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -969,7 +969,13 @@

    总结 mghio - + + @@ -982,7 +988,6 @@

    总结 diff --git a/post/b1d4025b.html b/post/b1d4025b.html index 2991e0b8..8e328a65 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -883,7 +883,13 @@

    hello world

    mghio - + + @@ -896,7 +902,6 @@

    hello world

    -
    diff --git a/post/bc557e1a.html b/post/bc557e1a.html index 717d63ac..d6c1ad2f 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -1034,7 +1034,13 @@
    mghio - + +
    @@ -1047,7 +1053,6 @@
    diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index f47b4cce..494f2c98 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -986,7 +986,13 @@

    mghio - + + @@ -999,7 +1005,6 @@

    - @@ -1038,7 +1044,6 @@

    总结 diff --git a/post/d7d0fc76.html b/post/d7d0fc76.html index f6c5d9aa..6d3a27e7 100644 --- a/post/d7d0fc76.html +++ b/post/d7d0fc76.html @@ -951,7 +951,13 @@

    mghio - + + @@ -964,7 +970,6 @@

    diff --git a/post/e09f0428.html b/post/e09f0428.html index aa1c01de..96261fcb 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -956,7 +956,13 @@

    mghio - + + @@ -969,7 +975,6 @@

    diff --git a/post/ee27c07f.html b/post/ee27c07f.html index 034b4701..18bd93a8 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -949,7 +949,13 @@

    mghio - + + @@ -962,7 +968,6 @@

    - @@ -998,7 +1004,6 @@

    总结 diff --git a/post/f92758d8.html b/post/f92758d8.html index 02f5a346..2438aded 100644 --- a/post/f92758d8.html +++ b/post/f92758d8.html @@ -973,7 +973,13 @@

    总结 mghio - + + @@ -986,7 +992,6 @@

    总结 diff --git a/post/fa75f5d7.html b/post/fa75f5d7.html index 1085210b..b09530f1 100644 --- a/post/fa75f5d7.html +++ b/post/fa75f5d7.html @@ -989,7 +989,13 @@

    mghio - + + @@ -1002,7 +1008,6 @@

    diff --git a/post/fe76043.html b/post/fe76043.html index 33724fdd..b8a79417 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -952,7 +952,13 @@

    总结 mghio - + + @@ -965,7 +971,6 @@

    总结 diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index cd39c38c..fe9f223b 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -642,7 +642,13 @@

    mghio - + + @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index 6f600e79..8904dd5e 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/Constructor-\346\263\250\345\205\245/index.html" "b/tags/Constructor-\346\263\250\345\205\245/index.html" index f58e963c..09896de9 100644 --- "a/tags/Constructor-\346\263\250\345\205\245/index.html" +++ "b/tags/Constructor-\346\263\250\345\205\245/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index 53e1d427..4da77089 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/GC/index.html b/tags/GC/index.html index f6631bb7..478a40a8 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/Guava/index.html b/tags/Guava/index.html index 83318c74..93d4c071 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index cc72ea0e..a5ebcd59 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index d9b80868..3c573b89 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/IoC/index.html b/tags/IoC/index.html index 581db4e6..f2414ff2 100644 --- a/tags/IoC/index.html +++ b/tags/IoC/index.html @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/JDK/index.html b/tags/JDK/index.html index e8a33199..c6cb285f 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/JVM/index.html b/tags/JVM/index.html index 59f190af..255bdd43 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -668,7 +668,13 @@

    mghio - + +

    @@ -681,7 +687,6 @@

    -
    diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index c2d8bfea..f73195b5 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index a7d3e6af..c677164e 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/Java/index.html b/tags/Java/index.html index 03bf2095..454c0d4f 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -880,7 +880,13 @@

    mghio - + +

    @@ -893,7 +899,6 @@

    -
    diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index 55b32dec..11548ccf 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -880,7 +880,13 @@

    mghio - + +

    @@ -893,7 +899,6 @@

    -
    diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index d8b30394..833fa459 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -854,7 +854,13 @@

    mghio - + +

    @@ -867,7 +873,6 @@

    -
    diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index 431162c6..14d2885b 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/List/index.html b/tags/List/index.html index 4822e1be..bcbcb6d3 100644 --- a/tags/List/index.html +++ b/tags/List/index.html @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/RabbitMQ/index.html b/tags/RabbitMQ/index.html index 8a0ede8a..48d83f60 100644 --- a/tags/RabbitMQ/index.html +++ b/tags/RabbitMQ/index.html @@ -668,7 +668,13 @@

    mghio - + +

    @@ -681,7 +687,6 @@

    -
    diff --git a/tags/Spring/index.html b/tags/Spring/index.html index b41079c6..ae0ddee8 100644 --- a/tags/Spring/index.html +++ b/tags/Spring/index.html @@ -694,7 +694,13 @@

    mghio - + +

    @@ -707,7 +713,6 @@

    -
    diff --git a/tags/String/index.html b/tags/String/index.html index 025d1639..037c769b 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/index.html b/tags/index.html index c35a052b..71740201 100644 --- a/tags/index.html +++ b/tags/index.html @@ -634,7 +634,13 @@

    mghio - + +
    @@ -647,7 +653,6 @@

    -
    diff --git a/tags/mockito/index.html b/tags/mockito/index.html index 0e5ae67a..712bf758 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git a/tags/test/index.html b/tags/test/index.html index 7f48f353..3412e160 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 926c7fbf..7b8411a1 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index a4d23f72..bbf2373a 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -668,7 +668,13 @@

    mghio - + +

    @@ -681,7 +687,6 @@

    -
    diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 1fd7be69..969e285f 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -668,7 +668,13 @@

    mghio - + +

    @@ -681,7 +687,6 @@

    -
    diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index c363f666..0dab8383 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index ab69ab1b..fe6bb789 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -668,7 +668,13 @@

    mghio - + +

    @@ -681,7 +687,6 @@

    -
    diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index eadfaf24..4b9736f2 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index a20aea0a..36512bdc 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 4f4395a3..118590f0 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/\347\274\223\345\255\230/index.html" "b/tags/\347\274\223\345\255\230/index.html" index 3ced39f8..82a4bba3 100644 --- "a/tags/\347\274\223\345\255\230/index.html" +++ "b/tags/\347\274\223\345\255\230/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index ea400a1b..bbd34da4 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -642,7 +642,13 @@

    mghio - + +

    @@ -655,7 +661,6 @@

    -
    From 0b048e7345c7283b93c121c3f1477ca26b8e1378 Mon Sep 17 00:00:00 2001 From: mghio Date: Sat, 23 Jan 2021 23:22:40 +0800 Subject: [PATCH 16/19] Site updated: 2021-01-23 23:22:40 --- CNAME | 2 +- css/main.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CNAME b/CNAME index 17ec11f1..81894942 100644 --- a/CNAME +++ b/CNAME @@ -1 +1 @@ -www.mghio.cn \ No newline at end of file +blog.mghio.cn \ No newline at end of file diff --git a/css/main.css b/css/main.css index edb3a43d..d9434e07 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #f7ff69; + background: #0479ff; } .links-of-blogroll { font-size: 13px; From 5fc56b3e8f317eca6e51c0183d32f710f500a68b Mon Sep 17 00:00:00 2001 From: mghio Date: Sat, 23 Jan 2021 23:30:00 +0800 Subject: [PATCH 17/19] Site updated: 2021-01-23 23:29:59 --- CNAME | 2 +- css/main.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CNAME b/CNAME index 81894942..17ec11f1 100644 --- a/CNAME +++ b/CNAME @@ -1 +1 @@ -blog.mghio.cn \ No newline at end of file +www.mghio.cn \ No newline at end of file diff --git a/css/main.css b/css/main.css index d9434e07..97cc9cd4 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #0479ff; + background: #62eeff; } .links-of-blogroll { font-size: 13px; From e4f7161cdd4b9ed07658e9ac6141c57a645edf7c Mon Sep 17 00:00:00 2001 From: mghio Date: Sun, 24 Jan 2021 14:40:44 +0800 Subject: [PATCH 18/19] Site updated: 2021-01-24 14:40:43 --- about/index.html | 4 + archives/2019/10/index.html | 4 + archives/2019/11/index.html | 4 + archives/2019/12/index.html | 4 + archives/2019/index.html | 4 + archives/2019/page/2/index.html | 4 + archives/2020/01/index.html | 4 + archives/2020/02/index.html | 4 + archives/2020/03/index.html | 4 + archives/2020/04/index.html | 4 + archives/2020/05/index.html | 4 + archives/2020/06/index.html | 4 + archives/2020/07/index.html | 4 + archives/2020/08/index.html | 4 + archives/2020/09/index.html | 4 + archives/2020/10/index.html | 4 + archives/2020/11/index.html | 4 + archives/2020/index.html | 4 + archives/2020/page/2/index.html | 4 + archives/2021/01/index.html | 4 + archives/2021/index.html | 4 + archives/index.html | 4 + archives/page/2/index.html | 4 + archives/page/3/index.html | 4 + archives/page/4/index.html | 4 + categories/JDK/Java/index.html | 4 + .../index.html" | 4 + categories/JDK/index.html | 4 + categories/Java/Bloom-filter/index.html | 4 + categories/Java/GC/index.html | 4 + categories/Java/Guava/String/index.html | 4 + categories/Java/Guava/index.html | 4 + categories/Java/IDEA/index.html | 4 + .../IDEA/\345\267\245\345\205\267/index.html" | 4 + .../IO\346\250\241\345\236\213/index.html" | 4 + categories/Java/JVM/index.html | 4 + categories/Java/List/index.html | 4 + categories/Java/Spring/index.html | 4 + categories/Java/index.html | 4 + categories/Java/page/2/index.html | 4 + categories/Java/page/3/index.html | 4 + categories/Java/unit-test/index.html | 4 + categories/Java/unit-test/mockito/index.html | 4 + .../Java/\345\216\237\347\220\206/index.html" | 4 + .../Java/\345\217\215\345\260\204/index.html" | 4 + .../index.html" | 4 + .../Java/\345\271\266\345\217\221/index.html" | 4 + .../\350\277\233\351\230\266/index.html" | 4 + .../Java/\345\274\202\346\255\245/index.html" | 4 + .../Eureka/index.html" | 4 + .../index.html" | 4 + .../index.html" | 4 + .../Java/\347\274\223\345\255\230/index.html" | 4 + .../Java/\351\207\215\346\236\204/index.html" | 4 + .../Linux\347\254\224\350\256\260/index.html" | 4 + categories/RabbitMQ/Java/index.html | 4 + categories/RabbitMQ/index.html | 4 + categories/Spring/Java/index.html | 4 + categories/Spring/index.html | 4 + categories/index.html | 4 + .../CAP\345\256\232\347\220\206/index.html" | 4 + .../index.html" | 4 + css/main.css | 2 +- index.html | 4 + lib/darkmode-js/CHANGELOG.html | 24 ++ lib/darkmode-js/LICENSE | 22 ++ lib/darkmode-js/README.html | 110 +++++++ lib/darkmode-js/lib/darkmode-js.js | 300 ++++++++++++++++++ lib/darkmode-js/lib/darkmode-js.min.js | 1 + lib/darkmode-js/package-lock.json | 1 + lib/darkmode-js/package.json | 1 + lib/darkmode-js/src/darkmode.js | 228 +++++++++++++ lib/darkmode-js/src/index.js | 10 + lib/darkmode-js/test/index.html | 38 +++ lib/darkmode-js/test/index.spec.js | 72 +++++ lib/darkmode-js/test/mocha.opts | 1 + lib/darkmode-js/webpack.config.js | 54 ++++ page/2/index.html | 4 + page/3/index.html | 4 + page/4/index.html | 4 + post/102cd3d9.html | 4 + post/11cb7677.html | 4 + post/192cb539.html | 4 + post/24042edf.html | 4 + post/24cb2421.html | 4 + post/315ff4dc.html | 4 + post/34755d6c.html | 4 + post/3ae0ff4e.html | 4 + post/4615256d.html | 4 + post/4b00e13c.html | 4 + post/4ea48fa7.html | 4 + post/51e5bd99.html | 4 + post/558ca0bd.html | 4 + post/710bd10b.html | 4 + post/7528c810.html | 4 + post/7b9ead86.html | 4 + post/7eb2637f.html | 4 + post/817c7d82.html | 4 + post/8a061473.html | 4 + post/8bd965a0.html | 4 + post/99ea2970.html | 4 + post/a38c0645.html | 4 + post/ab706eb5.html | 4 + post/b1d4025b.html | 4 + post/bc557e1a.html | 4 + post/bfcdfeaf.html | 4 + post/c34b451f.html | 4 + post/d7d0fc76.html | 4 + post/e09f0428.html | 4 + post/ee27c07f.html | 4 + post/f440d00b.html | 4 + post/f92758d8.html | 4 + post/fa75f5d7.html | 4 + post/fe76043.html | 4 + tags/Bloom-filter/index.html | 4 + "tags/CAP\345\256\232\347\220\206/index.html" | 4 + .../index.html" | 4 + tags/Eureka/index.html | 4 + tags/GC/index.html | 4 + tags/Guava/index.html | 4 + tags/IDEA/index.html | 4 + "tags/IO\346\250\241\345\236\213/index.html" | 4 + tags/IoC/index.html | 4 + tags/JDK/index.html | 4 + tags/JVM/index.html | 4 + .../Java-\345\216\237\347\220\206/index.html" | 4 + .../Java-\345\271\266\345\217\221/index.html" | 4 + tags/Java/index.html | 4 + tags/Java/page/2/index.html | 4 + tags/Java/page/3/index.html | 4 + .../Linux\347\254\224\350\256\260/index.html" | 4 + tags/List/index.html | 4 + tags/RabbitMQ/index.html | 4 + tags/Spring/index.html | 4 + tags/String/index.html | 4 + tags/index.html | 4 + tags/mockito/index.html | 4 + tags/test/index.html | 4 + .../index.html" | 4 + "tags/\345\217\215\345\260\204/index.html" | 4 + .../index.html" | 4 + "tags/\345\267\245\345\205\267/index.html" | 4 + "tags/\345\271\266\345\217\221/index.html" | 4 + "tags/\345\274\202\346\255\245/index.html" | 4 + .../index.html" | 4 + .../index.html" | 4 + "tags/\347\274\223\345\255\230/index.html" | 4 + "tags/\351\207\215\346\236\204/index.html" | 4 + 148 files changed, 1399 insertions(+), 1 deletion(-) create mode 100644 lib/darkmode-js/CHANGELOG.html create mode 100644 lib/darkmode-js/LICENSE create mode 100644 lib/darkmode-js/README.html create mode 100644 lib/darkmode-js/lib/darkmode-js.js create mode 100644 lib/darkmode-js/lib/darkmode-js.min.js create mode 100644 lib/darkmode-js/package-lock.json create mode 100644 lib/darkmode-js/package.json create mode 100644 lib/darkmode-js/src/darkmode.js create mode 100644 lib/darkmode-js/src/index.js create mode 100644 lib/darkmode-js/test/index.html create mode 100644 lib/darkmode-js/test/index.spec.js create mode 100644 lib/darkmode-js/test/mocha.opts create mode 100644 lib/darkmode-js/webpack.config.js diff --git a/about/index.html b/about/index.html index 802cca75..cb3a7115 100644 --- a/about/index.html +++ b/about/index.html @@ -635,6 +635,10 @@

    程序员阿淼 + +

    diff --git a/archives/2019/10/index.html b/archives/2019/10/index.html index bb87f10b..7a184d92 100644 --- a/archives/2019/10/index.html +++ b/archives/2019/10/index.html @@ -772,6 +772,10 @@

    程序员阿淼 + + diff --git a/archives/2019/11/index.html b/archives/2019/11/index.html index 64ce8ac2..a22b0ac7 100644 --- a/archives/2019/11/index.html +++ b/archives/2019/11/index.html @@ -737,6 +737,10 @@

    程序员阿淼 + + diff --git a/archives/2019/12/index.html b/archives/2019/12/index.html index f6fcba42..0c75273d 100644 --- a/archives/2019/12/index.html +++ b/archives/2019/12/index.html @@ -737,6 +737,10 @@

    程序员阿淼 + + diff --git a/archives/2019/index.html b/archives/2019/index.html index 74894a1f..31068545 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -951,6 +951,10 @@

    程序员阿淼 + + diff --git a/archives/2019/page/2/index.html b/archives/2019/page/2/index.html index f29a4703..50c40719 100644 --- a/archives/2019/page/2/index.html +++ b/archives/2019/page/2/index.html @@ -706,6 +706,10 @@

    程序员阿淼 + + diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html index 67994955..56b3d3fc 100644 --- a/archives/2020/01/index.html +++ b/archives/2020/01/index.html @@ -667,6 +667,10 @@

    程序员阿淼 + + diff --git a/archives/2020/02/index.html b/archives/2020/02/index.html index 779186bc..ad31875e 100644 --- a/archives/2020/02/index.html +++ b/archives/2020/02/index.html @@ -632,6 +632,10 @@

    程序员阿淼 + + diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index 694dfd7d..e0e1f3bb 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -737,6 +737,10 @@

    程序员阿淼 + + diff --git a/archives/2020/04/index.html b/archives/2020/04/index.html index 22a7c0b8..e9964b35 100644 --- a/archives/2020/04/index.html +++ b/archives/2020/04/index.html @@ -737,6 +737,10 @@

    程序员阿淼 + + diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index ff53deb4..aab2bd8d 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -667,6 +667,10 @@

    程序员阿淼 + + diff --git a/archives/2020/06/index.html b/archives/2020/06/index.html index a0368416..9189c1f8 100644 --- a/archives/2020/06/index.html +++ b/archives/2020/06/index.html @@ -632,6 +632,10 @@

    程序员阿淼 + + diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html index 914af405..44084d86 100644 --- a/archives/2020/07/index.html +++ b/archives/2020/07/index.html @@ -632,6 +632,10 @@

    程序员阿淼 + + diff --git a/archives/2020/08/index.html b/archives/2020/08/index.html index ca96e101..c9064de5 100644 --- a/archives/2020/08/index.html +++ b/archives/2020/08/index.html @@ -667,6 +667,10 @@

    程序员阿淼 + + diff --git a/archives/2020/09/index.html b/archives/2020/09/index.html index 8c45d839..ebc60690 100644 --- a/archives/2020/09/index.html +++ b/archives/2020/09/index.html @@ -632,6 +632,10 @@

    程序员阿淼 + + diff --git a/archives/2020/10/index.html b/archives/2020/10/index.html index 2484fd5c..bfc5bd26 100644 --- a/archives/2020/10/index.html +++ b/archives/2020/10/index.html @@ -632,6 +632,10 @@

    程序员阿淼 + + diff --git a/archives/2020/11/index.html b/archives/2020/11/index.html index 9c8ef31f..51d299e1 100644 --- a/archives/2020/11/index.html +++ b/archives/2020/11/index.html @@ -632,6 +632,10 @@

    程序员阿淼 + + diff --git a/archives/2020/index.html b/archives/2020/index.html index 0b7bc440..bd2172fb 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -951,6 +951,10 @@

    程序员阿淼 + + diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html index 51a37ac1..eb02dae1 100644 --- a/archives/2020/page/2/index.html +++ b/archives/2020/page/2/index.html @@ -951,6 +951,10 @@

    程序员阿淼 + + diff --git a/archives/2021/01/index.html b/archives/2021/01/index.html index 7f04ece0..c1657bd9 100644 --- a/archives/2021/01/index.html +++ b/archives/2021/01/index.html @@ -632,6 +632,10 @@

    程序员阿淼 + + diff --git a/archives/2021/index.html b/archives/2021/index.html index e162c14e..29e7114f 100644 --- a/archives/2021/index.html +++ b/archives/2021/index.html @@ -632,6 +632,10 @@

    程序员阿淼 + + diff --git a/archives/index.html b/archives/index.html index 058d2ad3..0de5ed27 100644 --- a/archives/index.html +++ b/archives/index.html @@ -956,6 +956,10 @@

    程序员阿淼 + + diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 45fc59d5..78f48149 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -951,6 +951,10 @@

    程序员阿淼 + + diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 81eb16d5..33a0f635 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -956,6 +956,10 @@

    程序员阿淼 + + diff --git a/archives/page/4/index.html b/archives/page/4/index.html index db70549a..e85bf794 100644 --- a/archives/page/4/index.html +++ b/archives/page/4/index.html @@ -741,6 +741,10 @@

    程序员阿淼 + + diff --git a/categories/JDK/Java/index.html b/categories/JDK/Java/index.html index 9289bcf0..857ad9b0 100644 --- a/categories/JDK/Java/index.html +++ b/categories/JDK/Java/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 6b0e9ff1..bb98be4c 100644 --- "a/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/categories/JDK/Java/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/JDK/index.html b/categories/JDK/index.html index 7e3452d1..0a25c402 100644 --- a/categories/JDK/index.html +++ b/categories/JDK/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/Java/Bloom-filter/index.html b/categories/Java/Bloom-filter/index.html index 1a87e4ef..24a2bd56 100644 --- a/categories/Java/Bloom-filter/index.html +++ b/categories/Java/Bloom-filter/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/Java/GC/index.html b/categories/Java/GC/index.html index 5d89855c..675a4a99 100644 --- a/categories/Java/GC/index.html +++ b/categories/Java/GC/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/Java/Guava/String/index.html b/categories/Java/Guava/String/index.html index 60a3e5cf..eac4ab16 100644 --- a/categories/Java/Guava/String/index.html +++ b/categories/Java/Guava/String/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/Java/Guava/index.html b/categories/Java/Guava/index.html index 7c1a4f5e..c532b8fb 100644 --- a/categories/Java/Guava/index.html +++ b/categories/Java/Guava/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/Java/IDEA/index.html b/categories/Java/IDEA/index.html index 4abf4713..747e733a 100644 --- a/categories/Java/IDEA/index.html +++ b/categories/Java/IDEA/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" index 4adc4568..557c0933 100644 --- "a/categories/Java/IDEA/\345\267\245\345\205\267/index.html" +++ "b/categories/Java/IDEA/\345\267\245\345\205\267/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/IO\346\250\241\345\236\213/index.html" "b/categories/Java/IO\346\250\241\345\236\213/index.html" index d8f40603..5a02acf7 100644 --- "a/categories/Java/IO\346\250\241\345\236\213/index.html" +++ "b/categories/Java/IO\346\250\241\345\236\213/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/Java/JVM/index.html b/categories/Java/JVM/index.html index 102a526e..8e6861f5 100644 --- a/categories/Java/JVM/index.html +++ b/categories/Java/JVM/index.html @@ -640,6 +640,10 @@

    程序员阿淼 + + diff --git a/categories/Java/List/index.html b/categories/Java/List/index.html index a5da57f9..d15192d5 100644 --- a/categories/Java/List/index.html +++ b/categories/Java/List/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/Java/Spring/index.html b/categories/Java/Spring/index.html index ffefa1bc..47860d41 100644 --- a/categories/Java/Spring/index.html +++ b/categories/Java/Spring/index.html @@ -640,6 +640,10 @@

    程序员阿淼 + + diff --git a/categories/Java/index.html b/categories/Java/index.html index 96e8589a..bc9570fb 100644 --- a/categories/Java/index.html +++ b/categories/Java/index.html @@ -852,6 +852,10 @@

    程序员阿淼 + + diff --git a/categories/Java/page/2/index.html b/categories/Java/page/2/index.html index 8bade47c..535521e4 100644 --- a/categories/Java/page/2/index.html +++ b/categories/Java/page/2/index.html @@ -852,6 +852,10 @@

    程序员阿淼 + + diff --git a/categories/Java/page/3/index.html b/categories/Java/page/3/index.html index 477f84b9..a8a23117 100644 --- a/categories/Java/page/3/index.html +++ b/categories/Java/page/3/index.html @@ -800,6 +800,10 @@

    程序员阿淼 + + diff --git a/categories/Java/unit-test/index.html b/categories/Java/unit-test/index.html index 220fcd80..a3d40f22 100644 --- a/categories/Java/unit-test/index.html +++ b/categories/Java/unit-test/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/Java/unit-test/mockito/index.html b/categories/Java/unit-test/mockito/index.html index a4cdcb7f..cb315ee0 100644 --- a/categories/Java/unit-test/mockito/index.html +++ b/categories/Java/unit-test/mockito/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\345\216\237\347\220\206/index.html" "b/categories/Java/\345\216\237\347\220\206/index.html" index 52457705..4f197bd7 100644 --- "a/categories/Java/\345\216\237\347\220\206/index.html" +++ "b/categories/Java/\345\216\237\347\220\206/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\345\217\215\345\260\204/index.html" "b/categories/Java/\345\217\215\345\260\204/index.html" index 700e0e07..8d88eff3 100644 --- "a/categories/Java/\345\217\215\345\260\204/index.html" +++ "b/categories/Java/\345\217\215\345\260\204/index.html" @@ -640,6 +640,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" index 04d68075..9048602b 100644 --- "a/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/categories/Java/\345\244\232\347\272\277\347\250\213/index.html" @@ -640,6 +640,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\345\271\266\345\217\221/index.html" "b/categories/Java/\345\271\266\345\217\221/index.html" index bafaef1e..0e583c2e 100644 --- "a/categories/Java/\345\271\266\345\217\221/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/index.html" @@ -666,6 +666,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" index 7883ffd0..8d896834 100644 --- "a/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" +++ "b/categories/Java/\345\271\266\345\217\221/\350\277\233\351\230\266/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\345\274\202\346\255\245/index.html" "b/categories/Java/\345\274\202\346\255\245/index.html" index 9a1c643e..9ad22a80 100644 --- "a/categories/Java/\345\274\202\346\255\245/index.html" +++ "b/categories/Java/\345\274\202\346\255\245/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" index a62f7d2e..84d33ad5 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/Eureka/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 3025c5d6..3c968a59 100644 --- "a/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/categories/Java/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" index 7032559e..1c788f6f 100644 --- "a/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" +++ "b/categories/Java/\347\272\277\347\250\213\346\261\240/index.html" @@ -640,6 +640,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\347\274\223\345\255\230/index.html" "b/categories/Java/\347\274\223\345\255\230/index.html" index 2ca0d851..924a5ab3 100644 --- "a/categories/Java/\347\274\223\345\255\230/index.html" +++ "b/categories/Java/\347\274\223\345\255\230/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/Java/\351\207\215\346\236\204/index.html" "b/categories/Java/\351\207\215\346\236\204/index.html" index 169dbba4..dcd2770d 100644 --- "a/categories/Java/\351\207\215\346\236\204/index.html" +++ "b/categories/Java/\351\207\215\346\236\204/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/Linux\347\254\224\350\256\260/index.html" "b/categories/Linux\347\254\224\350\256\260/index.html" index d7da6f84..73d035fa 100644 --- "a/categories/Linux\347\254\224\350\256\260/index.html" +++ "b/categories/Linux\347\254\224\350\256\260/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/RabbitMQ/Java/index.html b/categories/RabbitMQ/Java/index.html index 2a5d6977..b202ef3e 100644 --- a/categories/RabbitMQ/Java/index.html +++ b/categories/RabbitMQ/Java/index.html @@ -640,6 +640,10 @@

    程序员阿淼 + + diff --git a/categories/RabbitMQ/index.html b/categories/RabbitMQ/index.html index 4ecc8603..c6b8a295 100644 --- a/categories/RabbitMQ/index.html +++ b/categories/RabbitMQ/index.html @@ -640,6 +640,10 @@

    程序员阿淼 + + diff --git a/categories/Spring/Java/index.html b/categories/Spring/Java/index.html index 859742b2..c8232781 100644 --- a/categories/Spring/Java/index.html +++ b/categories/Spring/Java/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/Spring/index.html b/categories/Spring/index.html index e826943e..3a44dcfb 100644 --- a/categories/Spring/index.html +++ b/categories/Spring/index.html @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/categories/index.html b/categories/index.html index a63ab16c..208499fa 100644 --- a/categories/index.html +++ b/categories/index.html @@ -605,6 +605,10 @@

    程序员阿淼 + + diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" index 2da3d961..2c5fd213 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/CAP\345\256\232\347\220\206/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 09ea3148..327e6c6d 100644 --- "a/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/categories/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -614,6 +614,10 @@

    程序员阿淼 + + diff --git a/css/main.css b/css/main.css index 97cc9cd4..861550c7 100644 --- a/css/main.css +++ b/css/main.css @@ -2000,7 +2000,7 @@ pre .javascript .function { width: 4px; height: 4px; border-radius: 50%; - background: #62eeff; + background: #7fff5c; } .links-of-blogroll { font-size: 13px; diff --git a/index.html b/index.html index d260b971..d60c21bb 100644 --- a/index.html +++ b/index.html @@ -2640,6 +2640,10 @@

    前言程序员阿淼 + + diff --git a/lib/darkmode-js/CHANGELOG.html b/lib/darkmode-js/CHANGELOG.html new file mode 100644 index 00000000..95aad1fc --- /dev/null +++ b/lib/darkmode-js/CHANGELOG.html @@ -0,0 +1,24 @@ +

    Changelog

    1.5.7

      +
    • Adding role for better accessiblity of the widget
    • +
    +

    1.5.6

      +
    • Aria labels added for accessibility to the widget
    • +
    +

    1.5.5

      +
    • Fixing bug of visible button even when using programatically without widget
    • +
    +

    1.5.4

      +
    • Fixing the bug of overlay breaking when too many clicks are done at the same time by disabling/enabling the button
    • +
    +

    1.5.3

      +
    • Putting back the default values of button’s color
    • +
    +

    1.5.2

      +
    • Putting back saveInCookies to true in the default settings
    • +
    +

    1.5.1

      +
    • Code refactored for better readability
    • +
    +

    1.5.0

      +
    • Support server rendered frameworks such as Next.js and Gatsby
    • +
    diff --git a/lib/darkmode-js/LICENSE b/lib/darkmode-js/LICENSE new file mode 100644 index 00000000..661587fc --- /dev/null +++ b/lib/darkmode-js/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2019 Sandoche ADITTANE + +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. + diff --git a/lib/darkmode-js/README.html b/lib/darkmode-js/README.html new file mode 100644 index 00000000..913ed620 --- /dev/null +++ b/lib/darkmode-js/README.html @@ -0,0 +1,110 @@ +

    Darkmode.js

    npm version
    npm downloads
    License
    Medium Badge
    Twitter: sandochee

    +

    🌓 Add a Dark Mode / Night Mode to your website in a few seconds

    +

    This library uses the CSS mix-blend-mode to bring Dark Mode to any of your websites.
    Just copy-paste the snippet and you will get a widget to turn on and off the Dark Mode. You can also use it without the widget programmatically. The plugin is lightweight, built-in Vanilla.
    It also uses local storage by default, so your last setting will be remembered!

    +

    I have been inspired by this article: https://dev.wgao19.cc/2019-05-04__sun-moon-blending-mode/

    +

    Features

      +
    • Widget appears automatically
    • +
    • Saving users choice
    • +
    • Automatically shows Darkmode if the OS preferred theme is dark (if the browsers support prefers-color-scheme)
    • +
    • Can be used programmatically without widget
    • +
    +

    ✨ Demo

    Check out the demo in these websites:

    + +

    Wordpress plugins

    If you are using Wordpress you may want to have a look at these plugins based on Darkmode.js:

    + +

    Nuxt.js module

    If you are using Nuxt.js there is a module for Darkmode.js:

    + +

    📖 How to use

    Darkmode.js is very easy to use, just copy-paste the following code or use the npm package.

    +

    🚀 Easy way (using the JSDelivr CDN)

    Just add this code to your HTML page:

    +
    <script src="https://cdn.jsdelivr.net/npm/darkmode-js@1.5.7/lib/darkmode-js.min.js"></script>
    +<script>
    +  function addDarkmodeWidget() {
    +    new Darkmode().showWidget();
    +  }
    +  window.addEventListener('load', addDarkmodeWidget);
    +</script>
    +

    📦 Using NPM

    npm install darkmode-js
    +

    Then add the following JavaScript code:

    +
    import Darkmode from 'darkmode-js';
    +
    +new Darkmode().showWidget();
    +

    ⚙️ Options

    Here are the option availables:

    +
    const options = {
    +  bottom: '64px', // default: '32px'
    +  right: 'unset', // default: '32px'
    +  left: '32px', // default: 'unset'
    +  time: '0.5s', // default: '0.3s'
    +  mixColor: '#fff', // default: '#fff'
    +  backgroundColor: '#fff',  // default: '#fff'
    +  buttonColorDark: '#100f2c',  // default: '#100f2c'
    +  buttonColorLight: '#fff', // default: '#fff'
    +  saveInCookies: false, // default: true,
    +  label: '🌓', // default: ''
    +  autoMatchOsTheme: true // default: true
    +}
    +
    +const darkmode = new Darkmode(options);
    +darkmode.showWidget();
    +

    ▶️ Methods

    If you don’t want to show the widget and enable/disable Darkmode programatically you can use the method toggle(). You can also check if the Dark Mode is activated with the method isActivated(). See them in action in the following example:

    +
    const darkmode =  new Darkmode();
    +darkmode.toggle();
    +console.log(darkmode.isActivated()) // will return true
    +

    Override style

      +
    • A CSS class darkmode--activated is added to the body tag when the darkmode is activated. You can take advantage of it to override the style and have a custom style
    • +
    • Use the class darkmode-ignore where you don’t want to apply darkmode
    • +
    • You can also add this style: isolation: isolate; in your CSS, this will also ignore the darkmode.
    • +
    • It is also possible to revert the Dark Mode with this style mix-blend-mode: difference;
    • +
    +

    Examples

    .darkmode--activated p, .darkmode--activated li {
    +  color: #000;
    +}
    +
    +.button {
    +  isolation: isolate;
    +}
    +
    +.darkmode--activated .logo {
    +  mix-blend-mode: difference;
    +}
    +
    <span class="darkmode-ignore">😬<span>
    +

    Debug

    If it does not work you may have to add the following code, but this will invalidate the classes to override.

    +
    .darkmode-layer, .darkmode-toggle {
    +  z-index: 500;
    +}
    +

    Browser compatibility

    This library uses the CSS mix-blend-mode: difference; to provide the Dark Mode.
    It may not be compatible with all the browsers. Therefore the widget has been hidden in Internet Explorer and Edge.
    This library also uses prefers-color-scheme: dark to automatically enable the Dark Mode if the OS prefered theme is dark.

    +

    Check the compatibility here:

    + +

    Development

      +
    • yarn build or npm run build - produces a production version of your library under the lib folder
    • +
    • yarn dev or npm run dev - produces development version of your library and runs a watcher
    • +
    • yarn test or npm run test - it runs the tests :)
    • +
    • yarn test:watch or npm run test:watch - same as above but in a watch mode
    • +
    +

    ⭐️ Show your support

    Please ⭐️ this repository if this project helped you!

    +

    patreon.png

    +

    🍺 Buy me a beer

    If you like this project, feel free to donate:

    +
      +
    • PayPal: https://www.paypal.me/kanbanote
    • +
    • Bitcoin: 19JiNZ1LkMaz57tewqJaTg2hQWH4RgW4Yp
    • +
    • Ethereum: 0xded81fa4624e05339924355fe3504ba9587d5419
    • +
    • Monero: 43jqzMquW2q989UKSrB2YbeffhmJhbYb2Yxu289bv7pLRh4xVgMKj5yTd52iL6x1dvCYs9ERg5biHYxMjGkpSTs6S2jMyJn
    • +
    • Motive: MOTIV-25T5-SD65-V7LJ-BBWRD (Get Motive Now: https://motive.network)
    • +
    +

    📄 License

    MIT License

    +

    Copyright (c) Sandoche Adittane

    + diff --git a/lib/darkmode-js/lib/darkmode-js.js b/lib/darkmode-js/lib/darkmode-js.js new file mode 100644 index 00000000..a4739ebd --- /dev/null +++ b/lib/darkmode-js/lib/darkmode-js.js @@ -0,0 +1,300 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define("darkmode-js", [], factory); + else if(typeof exports === 'object') + exports["darkmode-js"] = factory(); + else + root["darkmode-js"] = factory(); +})(typeof self !== 'undefined' ? self : this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "./src/darkmode.js": +/*!*************************!*\ + !*** ./src/darkmode.js ***! + \*************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = exports.IS_BROWSER = void 0; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var IS_BROWSER = typeof window !== 'undefined'; +exports.IS_BROWSER = IS_BROWSER; + +var Darkmode = +/*#__PURE__*/ +function () { + function Darkmode(options) { + _classCallCheck(this, Darkmode); + + if (!IS_BROWSER) { + return; + } + + var defaultOptions = { + bottom: '32px', + right: '32px', + left: 'unset', + time: '0.3s', + mixColor: '#fff', + backgroundColor: '#fff', + buttonColorDark: '#100f2c', + buttonColorLight: '#fff', + label: '', + saveInCookies: true, + autoMatchOsTheme: true + }; + options = Object.assign({}, defaultOptions, options); + var css = "\n .darkmode-layer {\n position: fixed;\n pointer-events: none;\n background: ".concat(options.mixColor, ";\n transition: all ").concat(options.time, " ease;\n mix-blend-mode: difference;\n }\n\n .darkmode-layer--button {\n width: 2.9rem;\n height: 2.9rem;\n border-radius: 50%;\n right: ").concat(options.right, ";\n bottom: ").concat(options.bottom, ";\n left: ").concat(options.left, ";\n }\n\n .darkmode-layer--simple {\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n transform: scale(1) !important;\n }\n\n .darkmode-layer--expanded {\n transform: scale(100);\n border-radius: 0;\n }\n\n .darkmode-layer--no-transition {\n transition: none;\n }\n\n .darkmode-toggle {\n background: ").concat(options.buttonColorDark, ";\n width: 3rem;\n height: 3rem;\n position: fixed;\n border-radius: 50%;\n border:none;\n right: ").concat(options.right, ";\n bottom: ").concat(options.bottom, ";\n left: ").concat(options.left, ";\n cursor: pointer;\n transition: all 0.5s ease;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n\n .darkmode-toggle--white {\n background: ").concat(options.buttonColorLight, ";\n }\n\n .darkmode-toggle--inactive {\n display: none;\n }\n\n .darkmode-background {\n background: ").concat(options.backgroundColor, ";\n position: fixed;\n pointer-events: none;\n z-index: -10;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n }\n\n img, .darkmode-ignore {\n isolation: isolate;\n display: inline-block;\n }\n\n @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n .darkmode-toggle {display: none !important}\n }\n\n @supports (-ms-ime-align:auto), (-ms-accelerator:true) {\n .darkmode-toggle {display: none !important}\n }\n "); + var layer = document.createElement('div'); + var button = document.createElement('button'); + var background = document.createElement('div'); + button.innerHTML = options.label; + button.classList.add('darkmode-toggle--inactive'); + layer.classList.add('darkmode-layer'); + background.classList.add('darkmode-background'); + var darkmodeActivated = window.localStorage.getItem('darkmode') === 'true'; + var preferedThemeOs = options.autoMatchOsTheme && window.matchMedia('(prefers-color-scheme: dark)').matches; + var darkmodeNeverActivatedByAction = window.localStorage.getItem('darkmode') === null; + + if (darkmodeActivated === true && options.saveInCookies || darkmodeNeverActivatedByAction && preferedThemeOs) { + layer.classList.add('darkmode-layer--expanded', 'darkmode-layer--simple', 'darkmode-layer--no-transition'); + button.classList.add('darkmode-toggle--white'); + document.body.classList.add('darkmode--activated'); + } + + document.body.insertBefore(button, document.body.firstChild); + document.body.insertBefore(layer, document.body.firstChild); + document.body.insertBefore(background, document.body.firstChild); + this.addStyle(css); + this.button = button; + this.layer = layer; + this.saveInCookies = options.saveInCookies; + this.time = options.time; + } + + _createClass(Darkmode, [{ + key: "addStyle", + value: function addStyle(css) { + var linkElement = document.createElement('link'); + linkElement.setAttribute('rel', 'stylesheet'); + linkElement.setAttribute('type', 'text/css'); + linkElement.setAttribute('href', 'data:text/css;charset=UTF-8,' + encodeURIComponent(css)); + document.head.appendChild(linkElement); + } + }, { + key: "showWidget", + value: function showWidget() { + var _this = this; + + if (!IS_BROWSER) { + return; + } + + var button = this.button; + var layer = this.layer; + var time = parseFloat(this.time) * 1000; + button.classList.add('darkmode-toggle'); + button.classList.remove('darkmode-toggle--inactive'); + button.setAttribute("aria-label", "Activate dark mode"); + button.setAttribute("aria-checked", "false"); + button.setAttribute("role", "checkbox"); + layer.classList.add('darkmode-layer--button'); + button.addEventListener('click', function () { + var isDarkmode = _this.isActivated(); + + if (!isDarkmode) { + layer.classList.add('darkmode-layer--expanded'); + button.setAttribute('disabled', true); + setTimeout(function () { + layer.classList.add('darkmode-layer--no-transition'); + layer.classList.add('darkmode-layer--simple'); + button.removeAttribute('disabled'); + }, time); + } else { + layer.classList.remove('darkmode-layer--simple'); + button.setAttribute('disabled', true); + setTimeout(function () { + layer.classList.remove('darkmode-layer--no-transition'); + layer.classList.remove('darkmode-layer--expanded'); + button.removeAttribute('disabled'); + }, 1); + } + + button.classList.toggle('darkmode-toggle--white'); + document.body.classList.toggle('darkmode--activated'); + window.localStorage.setItem('darkmode', !isDarkmode); + }); + } + }, { + key: "toggle", + value: function toggle() { + if (!IS_BROWSER) { + return; + } + + var layer = this.layer; + var isDarkmode = this.isActivated(); + var button = this.button; + layer.classList.toggle('darkmode-layer--simple'); + document.body.classList.toggle('darkmode--activated'); + window.localStorage.setItem('darkmode', !isDarkmode); + button.setAttribute("aria-label", "De-activate dark mode"); + button.setAttribute("aria-checked", "true"); + } + }, { + key: "isActivated", + value: function isActivated() { + if (!IS_BROWSER) { + return null; + } + + return document.body.classList.contains('darkmode--activated'); + } + }]); + + return Darkmode; +}(); + +exports.default = Darkmode; + +/***/ }), + +/***/ "./src/index.js": +/*!**********************!*\ + !*** ./src/index.js ***! + \**********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _darkmode = _interopRequireWildcard(__webpack_require__(/*! ./darkmode */ "./src/darkmode.js")); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +var _default = _darkmode.default; +/* eslint-disable */ + +exports.default = _default; + +if (_darkmode.IS_BROWSER) { + (function (window) { + window.Darkmode = _darkmode.default; + })(window); +} +/* eslint-enable */ + + +module.exports = exports["default"]; + +/***/ }) + +/******/ }); +}); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9kYXJrbW9kZS1qcy93ZWJwYWNrL3VuaXZlcnNhbE1vZHVsZURlZmluaXRpb24iLCJ3ZWJwYWNrOi8vZGFya21vZGUtanMvd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vZGFya21vZGUtanMvLi9zcmMvZGFya21vZGUuanMiLCJ3ZWJwYWNrOi8vZGFya21vZGUtanMvLi9zcmMvaW5kZXguanMiXSwibmFtZXMiOlsiSVNfQlJPV1NFUiIsIndpbmRvdyIsIkRhcmttb2RlIiwib3B0aW9ucyIsImRlZmF1bHRPcHRpb25zIiwiYm90dG9tIiwicmlnaHQiLCJsZWZ0IiwidGltZSIsIm1peENvbG9yIiwiYmFja2dyb3VuZENvbG9yIiwiYnV0dG9uQ29sb3JEYXJrIiwiYnV0dG9uQ29sb3JMaWdodCIsImxhYmVsIiwic2F2ZUluQ29va2llcyIsImF1dG9NYXRjaE9zVGhlbWUiLCJPYmplY3QiLCJhc3NpZ24iLCJjc3MiLCJsYXllciIsImRvY3VtZW50IiwiY3JlYXRlRWxlbWVudCIsImJ1dHRvbiIsImJhY2tncm91bmQiLCJpbm5lckhUTUwiLCJjbGFzc0xpc3QiLCJhZGQiLCJkYXJrbW9kZUFjdGl2YXRlZCIsImxvY2FsU3RvcmFnZSIsImdldEl0ZW0iLCJwcmVmZXJlZFRoZW1lT3MiLCJtYXRjaE1lZGlhIiwibWF0Y2hlcyIsImRhcmttb2RlTmV2ZXJBY3RpdmF0ZWRCeUFjdGlvbiIsImJvZHkiLCJpbnNlcnRCZWZvcmUiLCJmaXJzdENoaWxkIiwiYWRkU3R5bGUiLCJsaW5rRWxlbWVudCIsInNldEF0dHJpYnV0ZSIsImVuY29kZVVSSUNvbXBvbmVudCIsImhlYWQiLCJhcHBlbmRDaGlsZCIsInBhcnNlRmxvYXQiLCJyZW1vdmUiLCJhZGRFdmVudExpc3RlbmVyIiwiaXNEYXJrbW9kZSIsImlzQWN0aXZhdGVkIiwic2V0VGltZW91dCIsInJlbW92ZUF0dHJpYnV0ZSIsInRvZ2dsZSIsInNldEl0ZW0iLCJjb250YWlucyJdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNELE87QUNWQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGtEQUEwQyxnQ0FBZ0M7QUFDMUU7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnRUFBd0Qsa0JBQWtCO0FBQzFFO0FBQ0EseURBQWlELGNBQWM7QUFDL0Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlEQUF5QyxpQ0FBaUM7QUFDMUUsd0hBQWdILG1CQUFtQixFQUFFO0FBQ3JJO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUNBQTJCLDBCQUEwQixFQUFFO0FBQ3ZELHlDQUFpQyxlQUFlO0FBQ2hEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhEQUFzRCwrREFBK0Q7O0FBRXJIO0FBQ0E7OztBQUdBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FDbEZPLElBQU1BLFVBQVUsR0FBRyxPQUFPQyxNQUFQLEtBQWtCLFdBQXJDOzs7SUFFY0MsUTs7O0FBQ25CLG9CQUFZQyxPQUFaLEVBQXFCO0FBQUE7O0FBQ25CLFFBQUksQ0FBQ0gsVUFBTCxFQUFpQjtBQUNmO0FBQ0Q7O0FBRUQsUUFBTUksY0FBYyxHQUFHO0FBQ3JCQyxZQUFNLEVBQUUsTUFEYTtBQUVyQkMsV0FBSyxFQUFFLE1BRmM7QUFHckJDLFVBQUksRUFBRSxPQUhlO0FBSXJCQyxVQUFJLEVBQUUsTUFKZTtBQUtyQkMsY0FBUSxFQUFFLE1BTFc7QUFNckJDLHFCQUFlLEVBQUUsTUFOSTtBQU9yQkMscUJBQWUsRUFBRSxTQVBJO0FBUXJCQyxzQkFBZ0IsRUFBRSxNQVJHO0FBU3JCQyxXQUFLLEVBQUUsRUFUYztBQVVyQkMsbUJBQWEsRUFBRSxJQVZNO0FBV3JCQyxzQkFBZ0IsRUFBRTtBQVhHLEtBQXZCO0FBY0FaLFdBQU8sR0FBR2EsTUFBTSxDQUFDQyxNQUFQLENBQWMsRUFBZCxFQUFrQmIsY0FBbEIsRUFBa0NELE9BQWxDLENBQVY7QUFFQSxRQUFNZSxHQUFHLHFIQUlTZixPQUFPLENBQUNNLFFBSmpCLHdDQUthTixPQUFPLENBQUNLLElBTHJCLG1NQWFJTCxPQUFPLENBQUNHLEtBYlosZ0NBY0tILE9BQU8sQ0FBQ0UsTUFkYiw4QkFlR0YsT0FBTyxDQUFDSSxJQWZYLHFhQW9DU0osT0FBTyxDQUFDUSxlQXBDakIseUpBMENJUixPQUFPLENBQUNHLEtBMUNaLGdDQTJDS0gsT0FBTyxDQUFDRSxNQTNDYiw4QkE0Q0dGLE9BQU8sQ0FBQ0ksSUE1Q1gsc09BcURTSixPQUFPLENBQUNTLGdCQXJEakIsb0pBNkRTVCxPQUFPLENBQUNPLGVBN0RqQiw4aUJBQVQ7QUFxRkEsUUFBTVMsS0FBSyxHQUFHQyxRQUFRLENBQUNDLGFBQVQsQ0FBdUIsS0FBdkIsQ0FBZDtBQUNBLFFBQU1DLE1BQU0sR0FBR0YsUUFBUSxDQUFDQyxhQUFULENBQXVCLFFBQXZCLENBQWY7QUFDQSxRQUFNRSxVQUFVLEdBQUdILFFBQVEsQ0FBQ0MsYUFBVCxDQUF1QixLQUF2QixDQUFuQjtBQUVBQyxVQUFNLENBQUNFLFNBQVAsR0FBbUJyQixPQUFPLENBQUNVLEtBQTNCO0FBQ0FTLFVBQU0sQ0FBQ0csU0FBUCxDQUFpQkMsR0FBakIsQ0FBcUIsMkJBQXJCO0FBQ0FQLFNBQUssQ0FBQ00sU0FBTixDQUFnQkMsR0FBaEIsQ0FBb0IsZ0JBQXBCO0FBQ0FILGNBQVUsQ0FBQ0UsU0FBWCxDQUFxQkMsR0FBckIsQ0FBeUIscUJBQXpCO0FBRUEsUUFBTUMsaUJBQWlCLEdBQ3JCMUIsTUFBTSxDQUFDMkIsWUFBUCxDQUFvQkMsT0FBcEIsQ0FBNEIsVUFBNUIsTUFBNEMsTUFEOUM7QUFFQSxRQUFNQyxlQUFlLEdBQ25CM0IsT0FBTyxDQUFDWSxnQkFBUixJQUNBZCxNQUFNLENBQUM4QixVQUFQLENBQWtCLDhCQUFsQixFQUFrREMsT0FGcEQ7QUFHQSxRQUFNQyw4QkFBOEIsR0FDbENoQyxNQUFNLENBQUMyQixZQUFQLENBQW9CQyxPQUFwQixDQUE0QixVQUE1QixNQUE0QyxJQUQ5Qzs7QUFHQSxRQUNHRixpQkFBaUIsS0FBSyxJQUF0QixJQUE4QnhCLE9BQU8sQ0FBQ1csYUFBdkMsSUFDQ21CLDhCQUE4QixJQUFJSCxlQUZyQyxFQUdFO0FBQ0FYLFdBQUssQ0FBQ00sU0FBTixDQUFnQkMsR0FBaEIsQ0FDRSwwQkFERixFQUVFLHdCQUZGLEVBR0UsK0JBSEY7QUFLQUosWUFBTSxDQUFDRyxTQUFQLENBQWlCQyxHQUFqQixDQUFxQix3QkFBckI7QUFDQU4sY0FBUSxDQUFDYyxJQUFULENBQWNULFNBQWQsQ0FBd0JDLEdBQXhCLENBQTRCLHFCQUE1QjtBQUNEOztBQUVETixZQUFRLENBQUNjLElBQVQsQ0FBY0MsWUFBZCxDQUEyQmIsTUFBM0IsRUFBbUNGLFFBQVEsQ0FBQ2MsSUFBVCxDQUFjRSxVQUFqRDtBQUNBaEIsWUFBUSxDQUFDYyxJQUFULENBQWNDLFlBQWQsQ0FBMkJoQixLQUEzQixFQUFrQ0MsUUFBUSxDQUFDYyxJQUFULENBQWNFLFVBQWhEO0FBQ0FoQixZQUFRLENBQUNjLElBQVQsQ0FBY0MsWUFBZCxDQUEyQlosVUFBM0IsRUFBdUNILFFBQVEsQ0FBQ2MsSUFBVCxDQUFjRSxVQUFyRDtBQUVBLFNBQUtDLFFBQUwsQ0FBY25CLEdBQWQ7QUFFQSxTQUFLSSxNQUFMLEdBQWNBLE1BQWQ7QUFDQSxTQUFLSCxLQUFMLEdBQWFBLEtBQWI7QUFDQSxTQUFLTCxhQUFMLEdBQXFCWCxPQUFPLENBQUNXLGFBQTdCO0FBQ0EsU0FBS04sSUFBTCxHQUFZTCxPQUFPLENBQUNLLElBQXBCO0FBQ0Q7Ozs7NkJBRVFVLEcsRUFBSztBQUNaLFVBQU1vQixXQUFXLEdBQUdsQixRQUFRLENBQUNDLGFBQVQsQ0FBdUIsTUFBdkIsQ0FBcEI7QUFFQWlCLGlCQUFXLENBQUNDLFlBQVosQ0FBeUIsS0FBekIsRUFBZ0MsWUFBaEM7QUFDQUQsaUJBQVcsQ0FBQ0MsWUFBWixDQUF5QixNQUF6QixFQUFpQyxVQUFqQztBQUNBRCxpQkFBVyxDQUFDQyxZQUFaLENBQ0UsTUFERixFQUVFLGlDQUFpQ0Msa0JBQWtCLENBQUN0QixHQUFELENBRnJEO0FBSUFFLGNBQVEsQ0FBQ3FCLElBQVQsQ0FBY0MsV0FBZCxDQUEwQkosV0FBMUI7QUFDRDs7O2lDQUVZO0FBQUE7O0FBQ1gsVUFBSSxDQUFDdEMsVUFBTCxFQUFpQjtBQUNmO0FBQ0Q7O0FBQ0QsVUFBTXNCLE1BQU0sR0FBRyxLQUFLQSxNQUFwQjtBQUNBLFVBQU1ILEtBQUssR0FBRyxLQUFLQSxLQUFuQjtBQUNBLFVBQU1YLElBQUksR0FBR21DLFVBQVUsQ0FBQyxLQUFLbkMsSUFBTixDQUFWLEdBQXdCLElBQXJDO0FBRUFjLFlBQU0sQ0FBQ0csU0FBUCxDQUFpQkMsR0FBakIsQ0FBcUIsaUJBQXJCO0FBQ0FKLFlBQU0sQ0FBQ0csU0FBUCxDQUFpQm1CLE1BQWpCLENBQXdCLDJCQUF4QjtBQUNBdEIsWUFBTSxDQUFDaUIsWUFBUCxDQUFvQixZQUFwQixFQUFrQyxvQkFBbEM7QUFDQWpCLFlBQU0sQ0FBQ2lCLFlBQVAsQ0FBb0IsY0FBcEIsRUFBb0MsT0FBcEM7QUFDQWpCLFlBQU0sQ0FBQ2lCLFlBQVAsQ0FBb0IsTUFBcEIsRUFBNEIsVUFBNUI7QUFDQXBCLFdBQUssQ0FBQ00sU0FBTixDQUFnQkMsR0FBaEIsQ0FBb0Isd0JBQXBCO0FBRUFKLFlBQU0sQ0FBQ3VCLGdCQUFQLENBQXdCLE9BQXhCLEVBQWlDLFlBQU07QUFDckMsWUFBTUMsVUFBVSxHQUFHLEtBQUksQ0FBQ0MsV0FBTCxFQUFuQjs7QUFFQSxZQUFJLENBQUNELFVBQUwsRUFBaUI7QUFDZjNCLGVBQUssQ0FBQ00sU0FBTixDQUFnQkMsR0FBaEIsQ0FBb0IsMEJBQXBCO0FBQ0FKLGdCQUFNLENBQUNpQixZQUFQLENBQW9CLFVBQXBCLEVBQWdDLElBQWhDO0FBQ0FTLG9CQUFVLENBQUMsWUFBTTtBQUNmN0IsaUJBQUssQ0FBQ00sU0FBTixDQUFnQkMsR0FBaEIsQ0FBb0IsK0JBQXBCO0FBQ0FQLGlCQUFLLENBQUNNLFNBQU4sQ0FBZ0JDLEdBQWhCLENBQW9CLHdCQUFwQjtBQUNBSixrQkFBTSxDQUFDMkIsZUFBUCxDQUF1QixVQUF2QjtBQUNELFdBSlMsRUFJUHpDLElBSk8sQ0FBVjtBQUtELFNBUkQsTUFRTztBQUNMVyxlQUFLLENBQUNNLFNBQU4sQ0FBZ0JtQixNQUFoQixDQUF1Qix3QkFBdkI7QUFDQXRCLGdCQUFNLENBQUNpQixZQUFQLENBQW9CLFVBQXBCLEVBQWdDLElBQWhDO0FBQ0FTLG9CQUFVLENBQUMsWUFBTTtBQUNmN0IsaUJBQUssQ0FBQ00sU0FBTixDQUFnQm1CLE1BQWhCLENBQXVCLCtCQUF2QjtBQUNBekIsaUJBQUssQ0FBQ00sU0FBTixDQUFnQm1CLE1BQWhCLENBQXVCLDBCQUF2QjtBQUNBdEIsa0JBQU0sQ0FBQzJCLGVBQVAsQ0FBdUIsVUFBdkI7QUFDRCxXQUpTLEVBSVAsQ0FKTyxDQUFWO0FBS0Q7O0FBRUQzQixjQUFNLENBQUNHLFNBQVAsQ0FBaUJ5QixNQUFqQixDQUF3Qix3QkFBeEI7QUFDQTlCLGdCQUFRLENBQUNjLElBQVQsQ0FBY1QsU0FBZCxDQUF3QnlCLE1BQXhCLENBQStCLHFCQUEvQjtBQUNBakQsY0FBTSxDQUFDMkIsWUFBUCxDQUFvQnVCLE9BQXBCLENBQTRCLFVBQTVCLEVBQXdDLENBQUNMLFVBQXpDO0FBQ0QsT0F4QkQ7QUF5QkQ7Ozs2QkFFUTtBQUNQLFVBQUksQ0FBQzlDLFVBQUwsRUFBaUI7QUFDZjtBQUNEOztBQUNELFVBQU1tQixLQUFLLEdBQUcsS0FBS0EsS0FBbkI7QUFDQSxVQUFNMkIsVUFBVSxHQUFHLEtBQUtDLFdBQUwsRUFBbkI7QUFDQSxVQUFNekIsTUFBTSxHQUFHLEtBQUtBLE1BQXBCO0FBRUFILFdBQUssQ0FBQ00sU0FBTixDQUFnQnlCLE1BQWhCLENBQXVCLHdCQUF2QjtBQUNBOUIsY0FBUSxDQUFDYyxJQUFULENBQWNULFNBQWQsQ0FBd0J5QixNQUF4QixDQUErQixxQkFBL0I7QUFDQWpELFlBQU0sQ0FBQzJCLFlBQVAsQ0FBb0J1QixPQUFwQixDQUE0QixVQUE1QixFQUF3QyxDQUFDTCxVQUF6QztBQUNBeEIsWUFBTSxDQUFDaUIsWUFBUCxDQUFvQixZQUFwQixFQUFrQyx1QkFBbEM7QUFDQWpCLFlBQU0sQ0FBQ2lCLFlBQVAsQ0FBb0IsY0FBcEIsRUFBb0MsTUFBcEM7QUFFRDs7O2tDQUVhO0FBQ1osVUFBSSxDQUFDdkMsVUFBTCxFQUFpQjtBQUNmLGVBQU8sSUFBUDtBQUNEOztBQUNELGFBQU9vQixRQUFRLENBQUNjLElBQVQsQ0FBY1QsU0FBZCxDQUF3QjJCLFFBQXhCLENBQWlDLHFCQUFqQyxDQUFQO0FBQ0Q7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUNsT0g7Ozs7O0FBR0E7Ozs7QUFDQSwwQkFBZ0I7QUFDZCxHQUFDLFVBQVNuRCxNQUFULEVBQWlCO0FBQ2hCQSxVQUFNLENBQUNDLFFBQVA7QUFDRCxHQUZELEVBRUdELE1BRkg7QUFHRDtBQUNEIiwiZmlsZSI6ImRhcmttb2RlLWpzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIHdlYnBhY2tVbml2ZXJzYWxNb2R1bGVEZWZpbml0aW9uKHJvb3QsIGZhY3RvcnkpIHtcblx0aWYodHlwZW9mIGV4cG9ydHMgPT09ICdvYmplY3QnICYmIHR5cGVvZiBtb2R1bGUgPT09ICdvYmplY3QnKVxuXHRcdG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeSgpO1xuXHRlbHNlIGlmKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZClcblx0XHRkZWZpbmUoXCJkYXJrbW9kZS1qc1wiLCBbXSwgZmFjdG9yeSk7XG5cdGVsc2UgaWYodHlwZW9mIGV4cG9ydHMgPT09ICdvYmplY3QnKVxuXHRcdGV4cG9ydHNbXCJkYXJrbW9kZS1qc1wiXSA9IGZhY3RvcnkoKTtcblx0ZWxzZVxuXHRcdHJvb3RbXCJkYXJrbW9kZS1qc1wiXSA9IGZhY3RvcnkoKTtcbn0pKHR5cGVvZiBzZWxmICE9PSAndW5kZWZpbmVkJyA/IHNlbGYgOiB0aGlzLCBmdW5jdGlvbigpIHtcbnJldHVybiAiLCIgXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXG4gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSkge1xuIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuIFx0XHR9XG4gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbiBcdFx0XHRpOiBtb2R1bGVJZCxcbiBcdFx0XHRsOiBmYWxzZSxcbiBcdFx0XHRleHBvcnRzOiB7fVxuIFx0XHR9O1xuXG4gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuIFx0XHRtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4gXHRcdG1vZHVsZS5sID0gdHJ1ZTtcblxuIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4gXHR9XG5cblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuXG4gXHQvLyBkZWZpbmUgZ2V0dGVyIGZ1bmN0aW9uIGZvciBoYXJtb255IGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uZCA9IGZ1bmN0aW9uKGV4cG9ydHMsIG5hbWUsIGdldHRlcikge1xuIFx0XHRpZighX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIG5hbWUpKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIG5hbWUsIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBnZXR0ZXIgfSk7XG4gXHRcdH1cbiBcdH07XG5cbiBcdC8vIGRlZmluZSBfX2VzTW9kdWxlIG9uIGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uciA9IGZ1bmN0aW9uKGV4cG9ydHMpIHtcbiBcdFx0aWYodHlwZW9mIFN5bWJvbCAhPT0gJ3VuZGVmaW5lZCcgJiYgU3ltYm9sLnRvU3RyaW5nVGFnKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFN5bWJvbC50b1N0cmluZ1RhZywgeyB2YWx1ZTogJ01vZHVsZScgfSk7XG4gXHRcdH1cbiBcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTtcbiBcdH07XG5cbiBcdC8vIGNyZWF0ZSBhIGZha2UgbmFtZXNwYWNlIG9iamVjdFxuIFx0Ly8gbW9kZSAmIDE6IHZhbHVlIGlzIGEgbW9kdWxlIGlkLCByZXF1aXJlIGl0XG4gXHQvLyBtb2RlICYgMjogbWVyZ2UgYWxsIHByb3BlcnRpZXMgb2YgdmFsdWUgaW50byB0aGUgbnNcbiBcdC8vIG1vZGUgJiA0OiByZXR1cm4gdmFsdWUgd2hlbiBhbHJlYWR5IG5zIG9iamVjdFxuIFx0Ly8gbW9kZSAmIDh8MTogYmVoYXZlIGxpa2UgcmVxdWlyZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy50ID0gZnVuY3Rpb24odmFsdWUsIG1vZGUpIHtcbiBcdFx0aWYobW9kZSAmIDEpIHZhbHVlID0gX193ZWJwYWNrX3JlcXVpcmVfXyh2YWx1ZSk7XG4gXHRcdGlmKG1vZGUgJiA4KSByZXR1cm4gdmFsdWU7XG4gXHRcdGlmKChtb2RlICYgNCkgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAmJiB2YWx1ZS5fX2VzTW9kdWxlKSByZXR1cm4gdmFsdWU7XG4gXHRcdHZhciBucyA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18ucihucyk7XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShucywgJ2RlZmF1bHQnLCB7IGVudW1lcmFibGU6IHRydWUsIHZhbHVlOiB2YWx1ZSB9KTtcbiBcdFx0aWYobW9kZSAmIDIgJiYgdHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSBmb3IodmFyIGtleSBpbiB2YWx1ZSkgX193ZWJwYWNrX3JlcXVpcmVfXy5kKG5zLCBrZXksIGZ1bmN0aW9uKGtleSkgeyByZXR1cm4gdmFsdWVba2V5XTsgfS5iaW5kKG51bGwsIGtleSkpO1xuIFx0XHRyZXR1cm4gbnM7XG4gXHR9O1xuXG4gXHQvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG4gXHRcdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuIFx0XHRcdGZ1bmN0aW9uIGdldERlZmF1bHQoKSB7IHJldHVybiBtb2R1bGVbJ2RlZmF1bHQnXTsgfSA6XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHsgcmV0dXJuIG1vZHVsZTsgfTtcbiBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuIFx0XHRyZXR1cm4gZ2V0dGVyO1xuIFx0fTtcblxuIFx0Ly8gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5KSB7IHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSk7IH07XG5cbiBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIlwiO1xuXG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oX193ZWJwYWNrX3JlcXVpcmVfXy5zID0gXCIuL3NyYy9pbmRleC5qc1wiKTtcbiIsImV4cG9ydCBjb25zdCBJU19CUk9XU0VSID0gdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCc7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIERhcmttb2RlIHtcbiAgY29uc3RydWN0b3Iob3B0aW9ucykge1xuICAgIGlmICghSVNfQlJPV1NFUikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGRlZmF1bHRPcHRpb25zID0ge1xuICAgICAgYm90dG9tOiAnMzJweCcsXG4gICAgICByaWdodDogJzMycHgnLFxuICAgICAgbGVmdDogJ3Vuc2V0JyxcbiAgICAgIHRpbWU6ICcwLjNzJyxcbiAgICAgIG1peENvbG9yOiAnI2ZmZicsXG4gICAgICBiYWNrZ3JvdW5kQ29sb3I6ICcjZmZmJyxcbiAgICAgIGJ1dHRvbkNvbG9yRGFyazogJyMxMDBmMmMnLFxuICAgICAgYnV0dG9uQ29sb3JMaWdodDogJyNmZmYnLFxuICAgICAgbGFiZWw6ICcnLFxuICAgICAgc2F2ZUluQ29va2llczogdHJ1ZSxcbiAgICAgIGF1dG9NYXRjaE9zVGhlbWU6IHRydWVcbiAgICB9O1xuXG4gICAgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oe30sIGRlZmF1bHRPcHRpb25zLCBvcHRpb25zKTtcblxuICAgIGNvbnN0IGNzcyA9IGBcbiAgICAgIC5kYXJrbW9kZS1sYXllciB7XG4gICAgICAgIHBvc2l0aW9uOiBmaXhlZDtcbiAgICAgICAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG4gICAgICAgIGJhY2tncm91bmQ6ICR7b3B0aW9ucy5taXhDb2xvcn07XG4gICAgICAgIHRyYW5zaXRpb246IGFsbCAke29wdGlvbnMudGltZX0gZWFzZTtcbiAgICAgICAgbWl4LWJsZW5kLW1vZGU6IGRpZmZlcmVuY2U7XG4gICAgICB9XG5cbiAgICAgIC5kYXJrbW9kZS1sYXllci0tYnV0dG9uIHtcbiAgICAgICAgd2lkdGg6IDIuOXJlbTtcbiAgICAgICAgaGVpZ2h0OiAyLjlyZW07XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICAgICAgcmlnaHQ6ICR7b3B0aW9ucy5yaWdodH07XG4gICAgICAgIGJvdHRvbTogJHtvcHRpb25zLmJvdHRvbX07XG4gICAgICAgIGxlZnQ6ICR7b3B0aW9ucy5sZWZ0fTtcbiAgICAgIH1cblxuICAgICAgLmRhcmttb2RlLWxheWVyLS1zaW1wbGUge1xuICAgICAgICB3aWR0aDogMTAwJTtcbiAgICAgICAgaGVpZ2h0OiAxMDAlO1xuICAgICAgICB0b3A6IDA7XG4gICAgICAgIGxlZnQ6IDA7XG4gICAgICAgIHRyYW5zZm9ybTogc2NhbGUoMSkgIWltcG9ydGFudDtcbiAgICAgIH1cblxuICAgICAgLmRhcmttb2RlLWxheWVyLS1leHBhbmRlZCB7XG4gICAgICAgIHRyYW5zZm9ybTogc2NhbGUoMTAwKTtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogMDtcbiAgICAgIH1cblxuICAgICAgLmRhcmttb2RlLWxheWVyLS1uby10cmFuc2l0aW9uIHtcbiAgICAgICAgdHJhbnNpdGlvbjogbm9uZTtcbiAgICAgIH1cblxuICAgICAgLmRhcmttb2RlLXRvZ2dsZSB7XG4gICAgICAgIGJhY2tncm91bmQ6ICR7b3B0aW9ucy5idXR0b25Db2xvckRhcmt9O1xuICAgICAgICB3aWR0aDogM3JlbTtcbiAgICAgICAgaGVpZ2h0OiAzcmVtO1xuICAgICAgICBwb3NpdGlvbjogZml4ZWQ7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICAgICAgYm9yZGVyOm5vbmU7XG4gICAgICAgIHJpZ2h0OiAke29wdGlvbnMucmlnaHR9O1xuICAgICAgICBib3R0b206ICR7b3B0aW9ucy5ib3R0b219O1xuICAgICAgICBsZWZ0OiAke29wdGlvbnMubGVmdH07XG4gICAgICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICAgICAgdHJhbnNpdGlvbjogYWxsIDAuNXMgZWFzZTtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICB9XG5cbiAgICAgIC5kYXJrbW9kZS10b2dnbGUtLXdoaXRlIHtcbiAgICAgICAgYmFja2dyb3VuZDogJHtvcHRpb25zLmJ1dHRvbkNvbG9yTGlnaHR9O1xuICAgICAgfVxuXG4gICAgICAuZGFya21vZGUtdG9nZ2xlLS1pbmFjdGl2ZSB7XG4gICAgICAgIGRpc3BsYXk6IG5vbmU7XG4gICAgICB9XG5cbiAgICAgIC5kYXJrbW9kZS1iYWNrZ3JvdW5kIHtcbiAgICAgICAgYmFja2dyb3VuZDogJHtvcHRpb25zLmJhY2tncm91bmRDb2xvcn07XG4gICAgICAgIHBvc2l0aW9uOiBmaXhlZDtcbiAgICAgICAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG4gICAgICAgIHotaW5kZXg6IC0xMDtcbiAgICAgICAgd2lkdGg6IDEwMCU7XG4gICAgICAgIGhlaWdodDogMTAwJTtcbiAgICAgICAgdG9wOiAwO1xuICAgICAgICBsZWZ0OiAwO1xuICAgICAgfVxuXG4gICAgICBpbWcsIC5kYXJrbW9kZS1pZ25vcmUge1xuICAgICAgICBpc29sYXRpb246IGlzb2xhdGU7XG4gICAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICAgIH1cblxuICAgICAgQG1lZGlhIHNjcmVlbiBhbmQgKC1tcy1oaWdoLWNvbnRyYXN0OiBhY3RpdmUpLCAoLW1zLWhpZ2gtY29udHJhc3Q6IG5vbmUpIHtcbiAgICAgICAgLmRhcmttb2RlLXRvZ2dsZSB7ZGlzcGxheTogbm9uZSAhaW1wb3J0YW50fVxuICAgICAgfVxuXG4gICAgICBAc3VwcG9ydHMgKC1tcy1pbWUtYWxpZ246YXV0byksICgtbXMtYWNjZWxlcmF0b3I6dHJ1ZSkge1xuICAgICAgICAuZGFya21vZGUtdG9nZ2xlIHtkaXNwbGF5OiBub25lICFpbXBvcnRhbnR9XG4gICAgICB9XG4gICAgYDtcblxuICAgIGNvbnN0IGxheWVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgY29uc3QgYnV0dG9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYnV0dG9uJyk7XG4gICAgY29uc3QgYmFja2dyb3VuZCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuXG4gICAgYnV0dG9uLmlubmVySFRNTCA9IG9wdGlvbnMubGFiZWw7XG4gICAgYnV0dG9uLmNsYXNzTGlzdC5hZGQoJ2Rhcmttb2RlLXRvZ2dsZS0taW5hY3RpdmUnKTtcbiAgICBsYXllci5jbGFzc0xpc3QuYWRkKCdkYXJrbW9kZS1sYXllcicpO1xuICAgIGJhY2tncm91bmQuY2xhc3NMaXN0LmFkZCgnZGFya21vZGUtYmFja2dyb3VuZCcpO1xuXG4gICAgY29uc3QgZGFya21vZGVBY3RpdmF0ZWQgPVxuICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5nZXRJdGVtKCdkYXJrbW9kZScpID09PSAndHJ1ZSc7XG4gICAgY29uc3QgcHJlZmVyZWRUaGVtZU9zID1cbiAgICAgIG9wdGlvbnMuYXV0b01hdGNoT3NUaGVtZSAmJlxuICAgICAgd2luZG93Lm1hdGNoTWVkaWEoJyhwcmVmZXJzLWNvbG9yLXNjaGVtZTogZGFyayknKS5tYXRjaGVzO1xuICAgIGNvbnN0IGRhcmttb2RlTmV2ZXJBY3RpdmF0ZWRCeUFjdGlvbiA9XG4gICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLmdldEl0ZW0oJ2Rhcmttb2RlJykgPT09IG51bGw7XG5cbiAgICBpZiAoXG4gICAgICAoZGFya21vZGVBY3RpdmF0ZWQgPT09IHRydWUgJiYgb3B0aW9ucy5zYXZlSW5Db29raWVzKSB8fFxuICAgICAgKGRhcmttb2RlTmV2ZXJBY3RpdmF0ZWRCeUFjdGlvbiAmJiBwcmVmZXJlZFRoZW1lT3MpXG4gICAgKSB7XG4gICAgICBsYXllci5jbGFzc0xpc3QuYWRkKFxuICAgICAgICAnZGFya21vZGUtbGF5ZXItLWV4cGFuZGVkJyxcbiAgICAgICAgJ2Rhcmttb2RlLWxheWVyLS1zaW1wbGUnLFxuICAgICAgICAnZGFya21vZGUtbGF5ZXItLW5vLXRyYW5zaXRpb24nXG4gICAgICApO1xuICAgICAgYnV0dG9uLmNsYXNzTGlzdC5hZGQoJ2Rhcmttb2RlLXRvZ2dsZS0td2hpdGUnKTtcbiAgICAgIGRvY3VtZW50LmJvZHkuY2xhc3NMaXN0LmFkZCgnZGFya21vZGUtLWFjdGl2YXRlZCcpO1xuICAgIH1cblxuICAgIGRvY3VtZW50LmJvZHkuaW5zZXJ0QmVmb3JlKGJ1dHRvbiwgZG9jdW1lbnQuYm9keS5maXJzdENoaWxkKTtcbiAgICBkb2N1bWVudC5ib2R5Lmluc2VydEJlZm9yZShsYXllciwgZG9jdW1lbnQuYm9keS5maXJzdENoaWxkKTtcbiAgICBkb2N1bWVudC5ib2R5Lmluc2VydEJlZm9yZShiYWNrZ3JvdW5kLCBkb2N1bWVudC5ib2R5LmZpcnN0Q2hpbGQpO1xuXG4gICAgdGhpcy5hZGRTdHlsZShjc3MpO1xuXG4gICAgdGhpcy5idXR0b24gPSBidXR0b247XG4gICAgdGhpcy5sYXllciA9IGxheWVyO1xuICAgIHRoaXMuc2F2ZUluQ29va2llcyA9IG9wdGlvbnMuc2F2ZUluQ29va2llcztcbiAgICB0aGlzLnRpbWUgPSBvcHRpb25zLnRpbWU7XG4gIH1cblxuICBhZGRTdHlsZShjc3MpIHtcbiAgICBjb25zdCBsaW5rRWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xpbmsnKTtcblxuICAgIGxpbmtFbGVtZW50LnNldEF0dHJpYnV0ZSgncmVsJywgJ3N0eWxlc2hlZXQnKTtcbiAgICBsaW5rRWxlbWVudC5zZXRBdHRyaWJ1dGUoJ3R5cGUnLCAndGV4dC9jc3MnKTtcbiAgICBsaW5rRWxlbWVudC5zZXRBdHRyaWJ1dGUoXG4gICAgICAnaHJlZicsXG4gICAgICAnZGF0YTp0ZXh0L2NzcztjaGFyc2V0PVVURi04LCcgKyBlbmNvZGVVUklDb21wb25lbnQoY3NzKVxuICAgICk7XG4gICAgZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChsaW5rRWxlbWVudCk7XG4gIH1cblxuICBzaG93V2lkZ2V0KCkge1xuICAgIGlmICghSVNfQlJPV1NFUikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBidXR0b24gPSB0aGlzLmJ1dHRvbjtcbiAgICBjb25zdCBsYXllciA9IHRoaXMubGF5ZXI7XG4gICAgY29uc3QgdGltZSA9IHBhcnNlRmxvYXQodGhpcy50aW1lKSAqIDEwMDA7XG5cbiAgICBidXR0b24uY2xhc3NMaXN0LmFkZCgnZGFya21vZGUtdG9nZ2xlJyk7XG4gICAgYnV0dG9uLmNsYXNzTGlzdC5yZW1vdmUoJ2Rhcmttb2RlLXRvZ2dsZS0taW5hY3RpdmUnKTtcbiAgICBidXR0b24uc2V0QXR0cmlidXRlKFwiYXJpYS1sYWJlbFwiLCBcIkFjdGl2YXRlIGRhcmsgbW9kZVwiKTtcbiAgICBidXR0b24uc2V0QXR0cmlidXRlKFwiYXJpYS1jaGVja2VkXCIsIFwiZmFsc2VcIik7XG4gICAgYnV0dG9uLnNldEF0dHJpYnV0ZShcInJvbGVcIiwgXCJjaGVja2JveFwiKTtcbiAgICBsYXllci5jbGFzc0xpc3QuYWRkKCdkYXJrbW9kZS1sYXllci0tYnV0dG9uJyk7XG5cbiAgICBidXR0b24uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB7XG4gICAgICBjb25zdCBpc0Rhcmttb2RlID0gdGhpcy5pc0FjdGl2YXRlZCgpO1xuXG4gICAgICBpZiAoIWlzRGFya21vZGUpIHtcbiAgICAgICAgbGF5ZXIuY2xhc3NMaXN0LmFkZCgnZGFya21vZGUtbGF5ZXItLWV4cGFuZGVkJyk7XG4gICAgICAgIGJ1dHRvbi5zZXRBdHRyaWJ1dGUoJ2Rpc2FibGVkJywgdHJ1ZSk7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIGxheWVyLmNsYXNzTGlzdC5hZGQoJ2Rhcmttb2RlLWxheWVyLS1uby10cmFuc2l0aW9uJyk7XG4gICAgICAgICAgbGF5ZXIuY2xhc3NMaXN0LmFkZCgnZGFya21vZGUtbGF5ZXItLXNpbXBsZScpO1xuICAgICAgICAgIGJ1dHRvbi5yZW1vdmVBdHRyaWJ1dGUoJ2Rpc2FibGVkJyk7XG4gICAgICAgIH0sIHRpbWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGF5ZXIuY2xhc3NMaXN0LnJlbW92ZSgnZGFya21vZGUtbGF5ZXItLXNpbXBsZScpO1xuICAgICAgICBidXR0b24uc2V0QXR0cmlidXRlKCdkaXNhYmxlZCcsIHRydWUpO1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICBsYXllci5jbGFzc0xpc3QucmVtb3ZlKCdkYXJrbW9kZS1sYXllci0tbm8tdHJhbnNpdGlvbicpO1xuICAgICAgICAgIGxheWVyLmNsYXNzTGlzdC5yZW1vdmUoJ2Rhcmttb2RlLWxheWVyLS1leHBhbmRlZCcpO1xuICAgICAgICAgIGJ1dHRvbi5yZW1vdmVBdHRyaWJ1dGUoJ2Rpc2FibGVkJyk7XG4gICAgICAgIH0sIDEpO1xuICAgICAgfVxuXG4gICAgICBidXR0b24uY2xhc3NMaXN0LnRvZ2dsZSgnZGFya21vZGUtdG9nZ2xlLS13aGl0ZScpO1xuICAgICAgZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QudG9nZ2xlKCdkYXJrbW9kZS0tYWN0aXZhdGVkJyk7XG4gICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLnNldEl0ZW0oJ2Rhcmttb2RlJywgIWlzRGFya21vZGUpO1xuICAgIH0pO1xuICB9XG5cbiAgdG9nZ2xlKCkge1xuICAgIGlmICghSVNfQlJPV1NFUikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBsYXllciA9IHRoaXMubGF5ZXI7XG4gICAgY29uc3QgaXNEYXJrbW9kZSA9IHRoaXMuaXNBY3RpdmF0ZWQoKTtcbiAgICBjb25zdCBidXR0b24gPSB0aGlzLmJ1dHRvbjtcblxuICAgIGxheWVyLmNsYXNzTGlzdC50b2dnbGUoJ2Rhcmttb2RlLWxheWVyLS1zaW1wbGUnKTtcbiAgICBkb2N1bWVudC5ib2R5LmNsYXNzTGlzdC50b2dnbGUoJ2Rhcmttb2RlLS1hY3RpdmF0ZWQnKTtcbiAgICB3aW5kb3cubG9jYWxTdG9yYWdlLnNldEl0ZW0oJ2Rhcmttb2RlJywgIWlzRGFya21vZGUpO1xuICAgIGJ1dHRvbi5zZXRBdHRyaWJ1dGUoXCJhcmlhLWxhYmVsXCIsIFwiRGUtYWN0aXZhdGUgZGFyayBtb2RlXCIpO1xuICAgIGJ1dHRvbi5zZXRBdHRyaWJ1dGUoXCJhcmlhLWNoZWNrZWRcIiwgXCJ0cnVlXCIpO1xuXG4gIH1cblxuICBpc0FjdGl2YXRlZCgpIHtcbiAgICBpZiAoIUlTX0JST1dTRVIpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4gZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QuY29udGFpbnMoJ2Rhcmttb2RlLS1hY3RpdmF0ZWQnKTtcbiAgfVxufVxuIiwiaW1wb3J0IERhcmttb2RlLCB7IElTX0JST1dTRVIgfSBmcm9tICcuL2Rhcmttb2RlJztcclxuZXhwb3J0IGRlZmF1bHQgRGFya21vZGU7XHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSAqL1xyXG5pZiAoSVNfQlJPV1NFUikge1xyXG4gIChmdW5jdGlvbih3aW5kb3cpIHtcclxuICAgIHdpbmRvdy5EYXJrbW9kZSA9IERhcmttb2RlO1xyXG4gIH0pKHdpbmRvdyk7XHJcbn1cclxuLyogZXNsaW50LWVuYWJsZSAqL1xyXG4iXSwic291cmNlUm9vdCI6IiJ9 \ No newline at end of file diff --git a/lib/darkmode-js/lib/darkmode-js.min.js b/lib/darkmode-js/lib/darkmode-js.min.js new file mode 100644 index 00000000..291031d5 --- /dev/null +++ b/lib/darkmode-js/lib/darkmode-js.min.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("darkmode-js",[],t):"object"==typeof exports?exports["darkmode-js"]=t():e["darkmode-js"]=t()}("undefined"!=typeof self?self:this,(function(){return function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n)){var o=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(e,n):{};o.get||o.set?Object.defineProperty(t,n,o):t[n]=e[n]}return t.default=e,t}(n(1));var r=o.default;t.default=r,o.IS_BROWSER&&function(e){e.Darkmode=o.default}(window),e.exports=t.default},function(e,t,n){"use strict";function o(e,t){for(var n=0;n= 2.1.2 < 3"}},"ignore-walk":{"version":"3.0.1","bundled":true,"dev":true,"optional":true,"requires":{"minimatch":"^3.0.4"}},"inflight":{"version":"1.0.6","bundled":true,"dev":true,"optional":true,"requires":{"once":"^1.3.0","wrappy":"1"}},"inherits":{"version":"2.0.3","bundled":true,"dev":true,"optional":true},"ini":{"version":"1.3.5","bundled":true,"dev":true,"optional":true},"is-fullwidth-code-point":{"version":"1.0.0","bundled":true,"dev":true,"optional":true,"requires":{"number-is-nan":"^1.0.0"}},"isarray":{"version":"1.0.0","bundled":true,"dev":true,"optional":true},"minimatch":{"version":"3.0.4","bundled":true,"dev":true,"optional":true,"requires":{"brace-expansion":"^1.1.7"}},"minimist":{"version":"0.0.8","bundled":true,"dev":true,"optional":true},"minipass":{"version":"2.3.5","bundled":true,"dev":true,"optional":true,"requires":{"safe-buffer":"^5.1.2","yallist":"^3.0.0"}},"minizlib":{"version":"1.2.1","bundled":true,"dev":true,"optional":true,"requires":{"minipass":"^2.2.1"}},"mkdirp":{"version":"0.5.1","bundled":true,"dev":true,"optional":true,"requires":{"minimist":"0.0.8"}},"ms":{"version":"2.1.1","bundled":true,"dev":true,"optional":true},"needle":{"version":"2.3.0","bundled":true,"dev":true,"optional":true,"requires":{"debug":"^4.1.0","iconv-lite":"^0.4.4","sax":"^1.2.4"}},"node-pre-gyp":{"version":"0.12.0","bundled":true,"dev":true,"optional":true,"requires":{"detect-libc":"^1.0.2","mkdirp":"^0.5.1","needle":"^2.2.1","nopt":"^4.0.1","npm-packlist":"^1.1.6","npmlog":"^4.0.2","rc":"^1.2.7","rimraf":"^2.6.1","semver":"^5.3.0","tar":"^4"}},"nopt":{"version":"4.0.1","bundled":true,"dev":true,"optional":true,"requires":{"abbrev":"1","osenv":"^0.1.4"}},"npm-bundled":{"version":"1.0.6","bundled":true,"dev":true,"optional":true},"npm-packlist":{"version":"1.4.1","bundled":true,"dev":true,"optional":true,"requires":{"ignore-walk":"^3.0.1","npm-bundled":"^1.0.1"}},"npmlog":{"version":"4.1.2","bundled":true,"dev":true,"optional":true,"requires":{"are-we-there-yet":"~1.1.2","console-control-strings":"~1.1.0","gauge":"~2.7.3","set-blocking":"~2.0.0"}},"number-is-nan":{"version":"1.0.1","bundled":true,"dev":true,"optional":true},"object-assign":{"version":"4.1.1","bundled":true,"dev":true,"optional":true},"once":{"version":"1.4.0","bundled":true,"dev":true,"optional":true,"requires":{"wrappy":"1"}},"os-homedir":{"version":"1.0.2","bundled":true,"dev":true,"optional":true},"os-tmpdir":{"version":"1.0.2","bundled":true,"dev":true,"optional":true},"osenv":{"version":"0.1.5","bundled":true,"dev":true,"optional":true,"requires":{"os-homedir":"^1.0.0","os-tmpdir":"^1.0.0"}},"path-is-absolute":{"version":"1.0.1","bundled":true,"dev":true,"optional":true},"process-nextick-args":{"version":"2.0.0","bundled":true,"dev":true,"optional":true},"rc":{"version":"1.2.8","bundled":true,"dev":true,"optional":true,"requires":{"deep-extend":"^0.6.0","ini":"~1.3.0","minimist":"^1.2.0","strip-json-comments":"~2.0.1"},"dependencies":{"minimist":{"version":"1.2.0","bundled":true,"dev":true,"optional":true}}},"readable-stream":{"version":"2.3.6","bundled":true,"dev":true,"optional":true,"requires":{"core-util-is":"~1.0.0","inherits":"~2.0.3","isarray":"~1.0.0","process-nextick-args":"~2.0.0","safe-buffer":"~5.1.1","string_decoder":"~1.1.1","util-deprecate":"~1.0.1"}},"rimraf":{"version":"2.6.3","bundled":true,"dev":true,"optional":true,"requires":{"glob":"^7.1.3"}},"safe-buffer":{"version":"5.1.2","bundled":true,"dev":true,"optional":true},"safer-buffer":{"version":"2.1.2","bundled":true,"dev":true,"optional":true},"sax":{"version":"1.2.4","bundled":true,"dev":true,"optional":true},"semver":{"version":"5.7.0","bundled":true,"dev":true,"optional":true},"set-blocking":{"version":"2.0.0","bundled":true,"dev":true,"optional":true},"signal-exit":{"version":"3.0.2","bundled":true,"dev":true,"optional":true},"string-width":{"version":"1.0.2","bundled":true,"dev":true,"optional":true,"requires":{"code-point-at":"^1.0.0","is-fullwidth-code-point":"^1.0.0","strip-ansi":"^3.0.0"}},"string_decoder":{"version":"1.1.1","bundled":true,"dev":true,"optional":true,"requires":{"safe-buffer":"~5.1.0"}},"strip-ansi":{"version":"3.0.1","bundled":true,"dev":true,"optional":true,"requires":{"ansi-regex":"^2.0.0"}},"strip-json-comments":{"version":"2.0.1","bundled":true,"dev":true,"optional":true},"tar":{"version":"4.4.8","bundled":true,"dev":true,"optional":true,"requires":{"chownr":"^1.1.1","fs-minipass":"^1.2.5","minipass":"^2.3.4","minizlib":"^1.1.1","mkdirp":"^0.5.0","safe-buffer":"^5.1.2","yallist":"^3.0.2"}},"util-deprecate":{"version":"1.0.2","bundled":true,"dev":true,"optional":true},"wide-align":{"version":"1.1.3","bundled":true,"dev":true,"optional":true,"requires":{"string-width":"^1.0.2 || 2"}},"wrappy":{"version":"1.0.2","bundled":true,"dev":true,"optional":true},"yallist":{"version":"3.0.3","bundled":true,"dev":true,"optional":true}}},"function-bind":{"version":"1.1.1","resolved":"https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz","integrity":"sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==","dev":true},"functional-red-black-tree":{"version":"1.0.1","resolved":"https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz","integrity":"sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=","dev":true},"get-caller-file":{"version":"1.0.3","resolved":"https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz","integrity":"sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==","dev":true},"get-func-name":{"version":"2.0.0","resolved":"https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz","integrity":"sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=","dev":true},"get-stream":{"version":"3.0.0","resolved":"https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz","integrity":"sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=","dev":true},"get-value":{"version":"2.0.6","resolved":"https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz","integrity":"sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=","dev":true},"getpass":{"version":"0.1.7","resolved":"https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz","integrity":"sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=","dev":true,"requires":{"assert-plus":"^1.0.0"}},"glob":{"version":"7.1.3","resolved":"https://registry.npmjs.org/glob/-/glob-7.1.3.tgz","integrity":"sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==","dev":true,"requires":{"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"}},"glob-base":{"version":"0.3.0","resolved":"https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz","integrity":"sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=","dev":true,"requires":{"glob-parent":"^2.0.0","is-glob":"^2.0.0"},"dependencies":{"glob-parent":{"version":"2.0.0","resolved":"https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz","integrity":"sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=","dev":true,"requires":{"is-glob":"^2.0.0"}},"is-extglob":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz","integrity":"sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=","dev":true},"is-glob":{"version":"2.0.1","resolved":"https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz","integrity":"sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=","dev":true,"requires":{"is-extglob":"^1.0.0"}}}},"glob-parent":{"version":"3.1.0","resolved":"https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz","integrity":"sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=","dev":true,"requires":{"is-glob":"^3.1.0","path-dirname":"^1.0.0"},"dependencies":{"is-glob":{"version":"3.1.0","resolved":"https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz","integrity":"sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=","dev":true,"requires":{"is-extglob":"^2.1.0"}}}},"global-modules-path":{"version":"2.3.0","resolved":"https://registry.npmjs.org/global-modules-path/-/global-modules-path-2.3.0.tgz","integrity":"sha512-HchvMJNYh9dGSCy8pOQ2O8u/hoXaL+0XhnrwH0RyLiSXMMTl9W3N6KUU73+JFOg5PGjtzl6VZzUQsnrpm7Szag==","dev":true},"globals":{"version":"11.9.0","resolved":"https://registry.npmjs.org/globals/-/globals-11.9.0.tgz","integrity":"sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==","dev":true},"graceful-fs":{"version":"4.1.15","resolved":"https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz","integrity":"sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==","dev":true},"growl":{"version":"1.10.3","resolved":"https://registry.npmjs.org/growl/-/growl-1.10.3.tgz","integrity":"sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==","dev":true},"handlebars":{"version":"4.4.0","resolved":"https://registry.npmjs.org/handlebars/-/handlebars-4.4.0.tgz","integrity":"sha512-xkRtOt3/3DzTKMOt3xahj2M/EqNhY988T+imYSlMgs5fVhLN2fmKVVj0LtEGmb+3UUYV5Qmm1052Mm3dIQxOvw==","dev":true,"requires":{"neo-async":"^2.6.0","optimist":"^0.6.1","source-map":"^0.6.1","uglify-js":"^3.1.4"},"dependencies":{"commander":{"version":"2.20.1","resolved":"https://registry.npmjs.org/commander/-/commander-2.20.1.tgz","integrity":"sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==","dev":true,"optional":true},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true},"uglify-js":{"version":"3.6.0","resolved":"https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz","integrity":"sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==","dev":true,"optional":true,"requires":{"commander":"~2.20.0","source-map":"~0.6.1"}}}},"har-schema":{"version":"2.0.0","resolved":"https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz","integrity":"sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=","dev":true},"har-validator":{"version":"5.1.3","resolved":"https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz","integrity":"sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==","dev":true,"requires":{"ajv":"^6.5.5","har-schema":"^2.0.0"}},"has":{"version":"1.0.3","resolved":"https://registry.npmjs.org/has/-/has-1.0.3.tgz","integrity":"sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==","dev":true,"requires":{"function-bind":"^1.1.1"}},"has-flag":{"version":"3.0.0","resolved":"https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz","integrity":"sha1-tdRU3CGZriJWmfNGfloH87lVuv0=","dev":true},"has-symbols":{"version":"1.0.0","resolved":"https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz","integrity":"sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=","dev":true},"has-value":{"version":"1.0.0","resolved":"https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz","integrity":"sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=","dev":true,"requires":{"get-value":"^2.0.6","has-values":"^1.0.0","isobject":"^3.0.0"}},"has-values":{"version":"1.0.0","resolved":"https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz","integrity":"sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=","dev":true,"requires":{"is-number":"^3.0.0","kind-of":"^4.0.0"},"dependencies":{"kind-of":{"version":"4.0.0","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz","integrity":"sha1-IIE989cSkosgc3hpGkUGb65y3Vc=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"hash-base":{"version":"3.0.4","resolved":"https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz","integrity":"sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=","dev":true,"requires":{"inherits":"^2.0.1","safe-buffer":"^5.0.1"}},"hash.js":{"version":"1.1.5","resolved":"https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz","integrity":"sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==","dev":true,"requires":{"inherits":"^2.0.3","minimalistic-assert":"^1.0.1"}},"hasha":{"version":"3.0.0","resolved":"https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz","integrity":"sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=","dev":true,"requires":{"is-stream":"^1.0.1"}},"he":{"version":"1.1.1","resolved":"https://registry.npmjs.org/he/-/he-1.1.1.tgz","integrity":"sha1-k0EP0hsAlzUVH4howvJx80J+I/0=","dev":true},"hmac-drbg":{"version":"1.0.1","resolved":"https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz","integrity":"sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=","dev":true,"requires":{"hash.js":"^1.0.3","minimalistic-assert":"^1.0.0","minimalistic-crypto-utils":"^1.0.1"}},"home-or-tmp":{"version":"3.0.0","resolved":"https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-3.0.0.tgz","integrity":"sha1-V6j+JM8zzdUkhgoVgh3cJchmcfs=","dev":true},"hosted-git-info":{"version":"2.7.1","resolved":"https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz","integrity":"sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==","dev":true},"html-encoding-sniffer":{"version":"1.0.2","resolved":"https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz","integrity":"sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==","dev":true,"requires":{"whatwg-encoding":"^1.0.1"}},"http-proxy":{"version":"1.17.0","resolved":"https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz","integrity":"sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==","dev":true,"requires":{"eventemitter3":"^3.0.0","follow-redirects":"^1.0.0","requires-port":"^1.0.0"}},"http-server":{"version":"0.11.1","resolved":"https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz","integrity":"sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==","dev":true,"requires":{"colors":"1.0.3","corser":"~2.0.0","ecstatic":"^3.0.0","http-proxy":"^1.8.1","opener":"~1.4.0","optimist":"0.6.x","portfinder":"^1.0.13","union":"~0.4.3"}},"http-signature":{"version":"1.2.0","resolved":"https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz","integrity":"sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=","dev":true,"requires":{"assert-plus":"^1.0.0","jsprim":"^1.2.2","sshpk":"^1.7.0"}},"https-browserify":{"version":"1.0.0","resolved":"https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz","integrity":"sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=","dev":true},"iconv-lite":{"version":"0.4.24","resolved":"https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz","integrity":"sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==","dev":true,"requires":{"safer-buffer":">= 2.1.2 < 3"}},"ieee754":{"version":"1.1.12","resolved":"https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz","integrity":"sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==","dev":true},"iferr":{"version":"0.1.5","resolved":"https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz","integrity":"sha1-xg7taebY/bazEEofy8ocGS3FtQE=","dev":true},"ignore":{"version":"4.0.6","resolved":"https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz","integrity":"sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==","dev":true},"import-local":{"version":"2.0.0","resolved":"https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz","integrity":"sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==","dev":true,"requires":{"pkg-dir":"^3.0.0","resolve-cwd":"^2.0.0"},"dependencies":{"find-up":{"version":"3.0.0","resolved":"https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz","integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"locate-path":{"version":"3.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz","integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"p-limit":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz","integrity":"sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz","integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz","integrity":"sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==","dev":true},"pkg-dir":{"version":"3.0.0","resolved":"https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz","integrity":"sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==","dev":true,"requires":{"find-up":"^3.0.0"}}}},"imurmurhash":{"version":"0.1.4","resolved":"https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz","integrity":"sha1-khi5srkoojixPcT7a21XbyMUU+o=","dev":true},"indexof":{"version":"0.0.1","resolved":"https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz","integrity":"sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=","dev":true},"inflight":{"version":"1.0.6","resolved":"https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz","integrity":"sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=","dev":true,"requires":{"once":"^1.3.0","wrappy":"1"}},"inherits":{"version":"2.0.3","resolved":"https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz","integrity":"sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=","dev":true},"inquirer":{"version":"6.2.0","resolved":"https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz","integrity":"sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==","dev":true,"requires":{"ansi-escapes":"^3.0.0","chalk":"^2.0.0","cli-cursor":"^2.1.0","cli-width":"^2.0.0","external-editor":"^3.0.0","figures":"^2.0.0","lodash":"^4.17.10","mute-stream":"0.0.7","run-async":"^2.2.0","rxjs":"^6.1.0","string-width":"^2.1.0","strip-ansi":"^4.0.0","through":"^2.3.6"}},"interpret":{"version":"1.1.0","resolved":"https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz","integrity":"sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=","dev":true},"invariant":{"version":"2.2.4","resolved":"https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz","integrity":"sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==","dev":true,"requires":{"loose-envify":"^1.0.0"}},"invert-kv":{"version":"2.0.0","resolved":"https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz","integrity":"sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==","dev":true},"is-accessor-descriptor":{"version":"0.1.6","resolved":"https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz","integrity":"sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=","dev":true,"requires":{"kind-of":"^3.0.2"},"dependencies":{"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"is-arrayish":{"version":"0.2.1","resolved":"https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz","integrity":"sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=","dev":true},"is-binary-path":{"version":"1.0.1","resolved":"https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz","integrity":"sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=","dev":true,"requires":{"binary-extensions":"^1.0.0"}},"is-buffer":{"version":"1.1.6","resolved":"https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz","integrity":"sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==","dev":true},"is-builtin-module":{"version":"1.0.0","resolved":"http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz","integrity":"sha1-VAVy0096wxGfj3bDDLwbHgN6/74=","dev":true,"requires":{"builtin-modules":"^1.0.0"}},"is-callable":{"version":"1.1.4","resolved":"https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz","integrity":"sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==","dev":true},"is-data-descriptor":{"version":"0.1.4","resolved":"https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz","integrity":"sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=","dev":true,"requires":{"kind-of":"^3.0.2"},"dependencies":{"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"is-date-object":{"version":"1.0.1","resolved":"https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz","integrity":"sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=","dev":true},"is-descriptor":{"version":"0.1.6","resolved":"https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz","integrity":"sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==","dev":true,"requires":{"is-accessor-descriptor":"^0.1.6","is-data-descriptor":"^0.1.4","kind-of":"^5.0.0"},"dependencies":{"kind-of":{"version":"5.1.0","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz","integrity":"sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==","dev":true}}},"is-dotfile":{"version":"1.0.3","resolved":"https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz","integrity":"sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=","dev":true},"is-equal-shallow":{"version":"0.1.3","resolved":"https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz","integrity":"sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=","dev":true,"requires":{"is-primitive":"^2.0.0"}},"is-extendable":{"version":"0.1.1","resolved":"https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz","integrity":"sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=","dev":true},"is-extglob":{"version":"2.1.1","resolved":"https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz","integrity":"sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=","dev":true},"is-fullwidth-code-point":{"version":"2.0.0","resolved":"https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz","integrity":"sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=","dev":true},"is-glob":{"version":"4.0.0","resolved":"https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz","integrity":"sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=","dev":true,"requires":{"is-extglob":"^2.1.1"}},"is-number":{"version":"3.0.0","resolved":"https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz","integrity":"sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=","dev":true,"requires":{"kind-of":"^3.0.2"},"dependencies":{"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"is-plain-obj":{"version":"1.1.0","resolved":"https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz","integrity":"sha1-caUMhCnfync8kqOQpKA7OfzVHT4=","dev":true},"is-plain-object":{"version":"2.0.4","resolved":"https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz","integrity":"sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==","dev":true,"requires":{"isobject":"^3.0.1"}},"is-posix-bracket":{"version":"0.1.1","resolved":"https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz","integrity":"sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=","dev":true},"is-primitive":{"version":"2.0.0","resolved":"https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz","integrity":"sha1-IHurkWOEmcB7Kt8kCkGochADRXU=","dev":true},"is-promise":{"version":"2.1.0","resolved":"https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz","integrity":"sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=","dev":true},"is-regex":{"version":"1.0.4","resolved":"https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz","integrity":"sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=","dev":true,"requires":{"has":"^1.0.1"}},"is-resolvable":{"version":"1.1.0","resolved":"https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz","integrity":"sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==","dev":true},"is-stream":{"version":"1.1.0","resolved":"https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz","integrity":"sha1-EtSj3U5o4Lec6428hBc66A2RykQ=","dev":true},"is-symbol":{"version":"1.0.2","resolved":"https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz","integrity":"sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==","dev":true,"requires":{"has-symbols":"^1.0.0"}},"is-typedarray":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz","integrity":"sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=","dev":true},"is-windows":{"version":"1.0.2","resolved":"https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz","integrity":"sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==","dev":true},"isarray":{"version":"1.0.0","resolved":"https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz","integrity":"sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=","dev":true},"isexe":{"version":"2.0.0","resolved":"https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz","integrity":"sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=","dev":true},"isobject":{"version":"3.0.1","resolved":"https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz","integrity":"sha1-TkMekrEalzFjaqH5yNHMvP2reN8=","dev":true},"isstream":{"version":"0.1.2","resolved":"https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz","integrity":"sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=","dev":true},"istanbul-lib-coverage":{"version":"2.0.1","resolved":"https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz","integrity":"sha512-nPvSZsVlbG9aLhZYaC3Oi1gT/tpyo3Yt5fNyf6NmcKIayz4VV/txxJFFKAK/gU4dcNn8ehsanBbVHVl0+amOLA==","dev":true},"istanbul-lib-hook":{"version":"2.0.7","resolved":"https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz","integrity":"sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==","dev":true,"requires":{"append-transform":"^1.0.0"}},"istanbul-lib-instrument":{"version":"3.0.0","resolved":"https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.0.0.tgz","integrity":"sha512-eQY9vN9elYjdgN9Iv6NS/00bptm02EBBk70lRMaVjeA6QYocQgenVrSgC28TJurdnZa80AGO3ASdFN+w/njGiQ==","dev":true,"requires":{"@babel/generator":"^7.0.0","@babel/parser":"^7.0.0","@babel/template":"^7.0.0","@babel/traverse":"^7.0.0","@babel/types":"^7.0.0","istanbul-lib-coverage":"^2.0.1","semver":"^5.5.0"}},"istanbul-lib-report":{"version":"2.0.8","resolved":"https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz","integrity":"sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==","dev":true,"requires":{"istanbul-lib-coverage":"^2.0.5","make-dir":"^2.1.0","supports-color":"^6.1.0"},"dependencies":{"istanbul-lib-coverage":{"version":"2.0.5","resolved":"https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz","integrity":"sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==","dev":true},"make-dir":{"version":"2.1.0","resolved":"https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz","integrity":"sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==","dev":true,"requires":{"pify":"^4.0.1","semver":"^5.6.0"}},"pify":{"version":"4.0.1","resolved":"https://registry.npmjs.org/pify/-/pify-4.0.1.tgz","integrity":"sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==","dev":true},"supports-color":{"version":"6.1.0","resolved":"https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz","integrity":"sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==","dev":true,"requires":{"has-flag":"^3.0.0"}}}},"istanbul-lib-source-maps":{"version":"3.0.6","resolved":"https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz","integrity":"sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==","dev":true,"requires":{"debug":"^4.1.1","istanbul-lib-coverage":"^2.0.5","make-dir":"^2.1.0","rimraf":"^2.6.3","source-map":"^0.6.1"},"dependencies":{"debug":{"version":"4.1.1","resolved":"https://registry.npmjs.org/debug/-/debug-4.1.1.tgz","integrity":"sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==","dev":true,"requires":{"ms":"^2.1.1"}},"istanbul-lib-coverage":{"version":"2.0.5","resolved":"https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz","integrity":"sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==","dev":true},"make-dir":{"version":"2.1.0","resolved":"https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz","integrity":"sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==","dev":true,"requires":{"pify":"^4.0.1","semver":"^5.6.0"}},"pify":{"version":"4.0.1","resolved":"https://registry.npmjs.org/pify/-/pify-4.0.1.tgz","integrity":"sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==","dev":true},"rimraf":{"version":"2.6.3","resolved":"https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz","integrity":"sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==","dev":true,"requires":{"glob":"^7.1.3"}},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true}}},"istanbul-reports":{"version":"2.2.6","resolved":"https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz","integrity":"sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==","dev":true,"requires":{"handlebars":"^4.1.2"}},"js-levenshtein":{"version":"1.1.4","resolved":"https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz","integrity":"sha512-PxfGzSs0ztShKrUYPIn5r0MtyAhYcCwmndozzpz8YObbPnD1jFxzlBGbRnX2mIu6Z13xN6+PTu05TQFnZFlzow==","dev":true},"js-tokens":{"version":"4.0.0","resolved":"https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz","integrity":"sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==","dev":true},"js-yaml":{"version":"3.13.1","resolved":"https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz","integrity":"sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==","dev":true,"requires":{"argparse":"^1.0.7","esprima":"^4.0.0"}},"jsbn":{"version":"0.1.1","resolved":"https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz","integrity":"sha1-peZUwuWi3rXyAdls77yoDA7y9RM=","dev":true},"jsdom":{"version":"11.11.0","resolved":"https://registry.npmjs.org/jsdom/-/jsdom-11.11.0.tgz","integrity":"sha512-ou1VyfjwsSuWkudGxb03FotDajxAto6USAlmMZjE2lc0jCznt7sBWkhfRBRaWwbnmDqdMSTKTLT5d9sBFkkM7A==","dev":true,"requires":{"abab":"^1.0.4","acorn":"^5.3.0","acorn-globals":"^4.1.0","array-equal":"^1.0.0","cssom":">= 0.3.2 < 0.4.0","cssstyle":">= 0.3.1 < 0.4.0","data-urls":"^1.0.0","domexception":"^1.0.0","escodegen":"^1.9.0","html-encoding-sniffer":"^1.0.2","left-pad":"^1.2.0","nwsapi":"^2.0.0","parse5":"4.0.0","pn":"^1.1.0","request":"^2.83.0","request-promise-native":"^1.0.5","sax":"^1.2.4","symbol-tree":"^3.2.2","tough-cookie":"^2.3.3","w3c-hr-time":"^1.0.1","webidl-conversions":"^4.0.2","whatwg-encoding":"^1.0.3","whatwg-mimetype":"^2.1.0","whatwg-url":"^6.4.1","ws":"^4.0.0","xml-name-validator":"^3.0.0"},"dependencies":{"acorn":{"version":"5.7.4","resolved":"https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz","integrity":"sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==","dev":true}}},"jsdom-global":{"version":"3.0.2","resolved":"https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz","integrity":"sha1-a9KZwTsMRiay2iwDk81DhdYGrLk=","dev":true},"jsesc":{"version":"2.5.2","resolved":"https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz","integrity":"sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==","dev":true},"json-parse-better-errors":{"version":"1.0.2","resolved":"https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz","integrity":"sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==","dev":true},"json-schema":{"version":"0.2.3","resolved":"https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz","integrity":"sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=","dev":true},"json-schema-traverse":{"version":"0.4.1","resolved":"https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz","integrity":"sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==","dev":true},"json-stable-stringify-without-jsonify":{"version":"1.0.1","resolved":"https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz","integrity":"sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=","dev":true},"json-stringify-safe":{"version":"5.0.1","resolved":"https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz","integrity":"sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=","dev":true},"json5":{"version":"2.1.0","resolved":"https://registry.npmjs.org/json5/-/json5-2.1.0.tgz","integrity":"sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==","dev":true,"requires":{"minimist":"^1.2.0"},"dependencies":{"minimist":{"version":"1.2.0","resolved":"https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz","integrity":"sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=","dev":true}}},"jsprim":{"version":"1.4.1","resolved":"https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz","integrity":"sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=","dev":true,"requires":{"assert-plus":"1.0.0","extsprintf":"1.3.0","json-schema":"0.2.3","verror":"1.10.0"}},"kind-of":{"version":"6.0.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz","integrity":"sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==","dev":true},"lcid":{"version":"2.0.0","resolved":"https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz","integrity":"sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==","dev":true,"requires":{"invert-kv":"^2.0.0"}},"left-pad":{"version":"1.3.0","resolved":"https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz","integrity":"sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==","dev":true},"levn":{"version":"0.3.0","resolved":"https://registry.npmjs.org/levn/-/levn-0.3.0.tgz","integrity":"sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=","dev":true,"requires":{"prelude-ls":"~1.1.2","type-check":"~0.3.2"}},"load-json-file":{"version":"4.0.0","resolved":"https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz","integrity":"sha1-L19Fq5HjMhYjT9U62rZo607AmTs=","dev":true,"requires":{"graceful-fs":"^4.1.2","parse-json":"^4.0.0","pify":"^3.0.0","strip-bom":"^3.0.0"}},"loader-fs-cache":{"version":"1.0.1","resolved":"https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz","integrity":"sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw=","dev":true,"requires":{"find-cache-dir":"^0.1.1","mkdirp":"0.5.1"},"dependencies":{"find-cache-dir":{"version":"0.1.1","resolved":"https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz","integrity":"sha1-yN765XyKUqinhPnjHFfHQumToLk=","dev":true,"requires":{"commondir":"^1.0.1","mkdirp":"^0.5.1","pkg-dir":"^1.0.0"}},"find-up":{"version":"1.1.2","resolved":"https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz","integrity":"sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=","dev":true,"requires":{"path-exists":"^2.0.0","pinkie-promise":"^2.0.0"}},"path-exists":{"version":"2.1.0","resolved":"https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz","integrity":"sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=","dev":true,"requires":{"pinkie-promise":"^2.0.0"}},"pkg-dir":{"version":"1.0.0","resolved":"https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz","integrity":"sha1-ektQio1bstYp1EcFb/TpyTFM89Q=","dev":true,"requires":{"find-up":"^1.0.0"}}}},"loader-runner":{"version":"2.3.1","resolved":"https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.1.tgz","integrity":"sha512-By6ZFY7ETWOc9RFaAIb23IjJVcM4dvJC/N57nmdz9RSkMXvAXGI7SyVlAw3v8vjtDRlqThgVDVmTnr9fqMlxkw==","dev":true},"loader-utils":{"version":"1.1.0","resolved":"https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz","integrity":"sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=","dev":true,"requires":{"big.js":"^3.1.3","emojis-list":"^2.0.0","json5":"^0.5.0"},"dependencies":{"json5":{"version":"0.5.1","resolved":"https://registry.npmjs.org/json5/-/json5-0.5.1.tgz","integrity":"sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=","dev":true}}},"locate-path":{"version":"2.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz","integrity":"sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=","dev":true,"requires":{"p-locate":"^2.0.0","path-exists":"^3.0.0"}},"lodash":{"version":"4.17.14","resolved":"https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz","integrity":"sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==","dev":true},"lodash.debounce":{"version":"4.0.8","resolved":"https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz","integrity":"sha1-gteb/zCmfEAF/9XiUVMArZyk168=","dev":true},"lodash.flattendeep":{"version":"4.4.0","resolved":"https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz","integrity":"sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=","dev":true},"lodash.sortby":{"version":"4.7.0","resolved":"https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz","integrity":"sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=","dev":true},"loose-envify":{"version":"1.4.0","resolved":"https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz","integrity":"sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==","dev":true,"requires":{"js-tokens":"^3.0.0 || ^4.0.0"}},"lru-cache":{"version":"4.1.4","resolved":"https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.4.tgz","integrity":"sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==","dev":true,"requires":{"pseudomap":"^1.0.2","yallist":"^3.0.2"}},"make-dir":{"version":"1.3.0","resolved":"https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz","integrity":"sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==","dev":true,"requires":{"pify":"^3.0.0"}},"map-age-cleaner":{"version":"0.1.3","resolved":"https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz","integrity":"sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==","dev":true,"requires":{"p-defer":"^1.0.0"}},"map-cache":{"version":"0.2.2","resolved":"https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz","integrity":"sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=","dev":true},"map-visit":{"version":"1.0.0","resolved":"https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz","integrity":"sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=","dev":true,"requires":{"object-visit":"^1.0.0"}},"math-random":{"version":"1.0.1","resolved":"https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz","integrity":"sha1-izqsWIuKZuSXXjzepn97sylgH6w=","dev":true},"md5.js":{"version":"1.3.5","resolved":"https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz","integrity":"sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==","dev":true,"requires":{"hash-base":"^3.0.0","inherits":"^2.0.1","safe-buffer":"^5.1.2"}},"mem":{"version":"4.0.0","resolved":"https://registry.npmjs.org/mem/-/mem-4.0.0.tgz","integrity":"sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==","dev":true,"requires":{"map-age-cleaner":"^0.1.1","mimic-fn":"^1.0.0","p-is-promise":"^1.1.0"}},"memory-fs":{"version":"0.4.1","resolved":"https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz","integrity":"sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=","dev":true,"requires":{"errno":"^0.1.3","readable-stream":"^2.0.1"}},"merge-source-map":{"version":"1.1.0","resolved":"https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz","integrity":"sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==","dev":true,"requires":{"source-map":"^0.6.1"},"dependencies":{"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true}}},"micromatch":{"version":"3.1.10","resolved":"https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz","integrity":"sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==","dev":true,"requires":{"arr-diff":"^4.0.0","array-unique":"^0.3.2","braces":"^2.3.1","define-property":"^2.0.2","extend-shallow":"^3.0.2","extglob":"^2.0.4","fragment-cache":"^0.2.1","kind-of":"^6.0.2","nanomatch":"^1.2.9","object.pick":"^1.3.0","regex-not":"^1.0.0","snapdragon":"^0.8.1","to-regex":"^3.0.2"}},"miller-rabin":{"version":"4.0.1","resolved":"https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz","integrity":"sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==","dev":true,"requires":{"bn.js":"^4.0.0","brorand":"^1.0.1"}},"mime":{"version":"1.6.0","resolved":"https://registry.npmjs.org/mime/-/mime-1.6.0.tgz","integrity":"sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==","dev":true},"mime-db":{"version":"1.37.0","resolved":"https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz","integrity":"sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==","dev":true},"mime-types":{"version":"2.1.21","resolved":"https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz","integrity":"sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==","dev":true,"requires":{"mime-db":"~1.37.0"}},"mimic-fn":{"version":"1.2.0","resolved":"https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz","integrity":"sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==","dev":true},"minimalistic-assert":{"version":"1.0.1","resolved":"https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz","integrity":"sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==","dev":true},"minimalistic-crypto-utils":{"version":"1.0.1","resolved":"https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz","integrity":"sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=","dev":true},"minimatch":{"version":"3.0.4","resolved":"https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz","integrity":"sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==","dev":true,"requires":{"brace-expansion":"^1.1.7"}},"minimist":{"version":"0.0.8","resolved":"https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz","integrity":"sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=","dev":true},"mississippi":{"version":"2.0.0","resolved":"https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz","integrity":"sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==","dev":true,"requires":{"concat-stream":"^1.5.0","duplexify":"^3.4.2","end-of-stream":"^1.1.0","flush-write-stream":"^1.0.0","from2":"^2.1.0","parallel-transform":"^1.1.0","pump":"^2.0.1","pumpify":"^1.3.3","stream-each":"^1.1.0","through2":"^2.0.0"}},"mixin-deep":{"version":"1.3.2","resolved":"https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz","integrity":"sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==","dev":true,"requires":{"for-in":"^1.0.2","is-extendable":"^1.0.1"},"dependencies":{"is-extendable":{"version":"1.0.1","resolved":"https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz","integrity":"sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==","dev":true,"requires":{"is-plain-object":"^2.0.4"}}}},"mkdirp":{"version":"0.5.1","resolved":"http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz","integrity":"sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=","dev":true,"requires":{"minimist":"0.0.8"}},"mocha":{"version":"4.1.0","resolved":"https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz","integrity":"sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==","dev":true,"requires":{"browser-stdout":"1.3.0","commander":"2.11.0","debug":"3.1.0","diff":"3.3.1","escape-string-regexp":"1.0.5","glob":"7.1.2","growl":"1.10.3","he":"1.1.1","mkdirp":"0.5.1","supports-color":"4.4.0"},"dependencies":{"commander":{"version":"2.11.0","resolved":"https://registry.npmjs.org/commander/-/commander-2.11.0.tgz","integrity":"sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==","dev":true},"debug":{"version":"3.1.0","resolved":"https://registry.npmjs.org/debug/-/debug-3.1.0.tgz","integrity":"sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==","dev":true,"requires":{"ms":"2.0.0"}},"glob":{"version":"7.1.2","resolved":"https://registry.npmjs.org/glob/-/glob-7.1.2.tgz","integrity":"sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==","dev":true,"requires":{"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"}},"has-flag":{"version":"2.0.0","resolved":"https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz","integrity":"sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=","dev":true},"ms":{"version":"2.0.0","resolved":"https://registry.npmjs.org/ms/-/ms-2.0.0.tgz","integrity":"sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=","dev":true},"supports-color":{"version":"4.4.0","resolved":"https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz","integrity":"sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==","dev":true,"requires":{"has-flag":"^2.0.0"}}}},"move-concurrently":{"version":"1.0.1","resolved":"https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz","integrity":"sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=","dev":true,"requires":{"aproba":"^1.1.1","copy-concurrently":"^1.0.0","fs-write-stream-atomic":"^1.0.8","mkdirp":"^0.5.1","rimraf":"^2.5.4","run-queue":"^1.0.3"}},"ms":{"version":"2.1.1","resolved":"https://registry.npmjs.org/ms/-/ms-2.1.1.tgz","integrity":"sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==","dev":true},"mute-stream":{"version":"0.0.7","resolved":"https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz","integrity":"sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=","dev":true},"nan":{"version":"2.14.0","resolved":"https://registry.npmjs.org/nan/-/nan-2.14.0.tgz","integrity":"sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==","dev":true,"optional":true},"nanomatch":{"version":"1.2.13","resolved":"https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz","integrity":"sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==","dev":true,"requires":{"arr-diff":"^4.0.0","array-unique":"^0.3.2","define-property":"^2.0.2","extend-shallow":"^3.0.2","fragment-cache":"^0.2.1","is-windows":"^1.0.2","kind-of":"^6.0.2","object.pick":"^1.3.0","regex-not":"^1.0.0","snapdragon":"^0.8.1","to-regex":"^3.0.1"}},"natural-compare":{"version":"1.4.0","resolved":"https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz","integrity":"sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=","dev":true},"neo-async":{"version":"2.6.0","resolved":"https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz","integrity":"sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==","dev":true},"nested-error-stacks":{"version":"2.1.0","resolved":"https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz","integrity":"sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==","dev":true},"nice-try":{"version":"1.0.5","resolved":"https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz","integrity":"sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==","dev":true},"node-libs-browser":{"version":"2.1.0","resolved":"https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz","integrity":"sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==","dev":true,"requires":{"assert":"^1.1.1","browserify-zlib":"^0.2.0","buffer":"^4.3.0","console-browserify":"^1.1.0","constants-browserify":"^1.0.0","crypto-browserify":"^3.11.0","domain-browser":"^1.1.1","events":"^1.0.0","https-browserify":"^1.0.0","os-browserify":"^0.3.0","path-browserify":"0.0.0","process":"^0.11.10","punycode":"^1.2.4","querystring-es3":"^0.2.0","readable-stream":"^2.3.3","stream-browserify":"^2.0.1","stream-http":"^2.7.2","string_decoder":"^1.0.0","timers-browserify":"^2.0.4","tty-browserify":"0.0.0","url":"^0.11.0","util":"^0.10.3","vm-browserify":"0.0.4"},"dependencies":{"punycode":{"version":"1.4.1","resolved":"https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz","integrity":"sha1-wNWmOycYgArY4esPpSachN1BhF4=","dev":true}}},"node-modules-regexp":{"version":"1.0.0","resolved":"https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz","integrity":"sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=","dev":true},"node-releases":{"version":"1.0.4","resolved":"https://registry.npmjs.org/node-releases/-/node-releases-1.0.4.tgz","integrity":"sha512-GqRV9GcHw8JCRDaP/JoeNMNzEGzHAknMvIHqMb2VeTOmg1Cf9+ej8bkV12tHfzWHQMCkQ5zUFgwFUkfraynNCw==","dev":true,"requires":{"semver":"^5.3.0"}},"normalize-package-data":{"version":"2.4.0","resolved":"https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz","integrity":"sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==","dev":true,"requires":{"hosted-git-info":"^2.1.4","is-builtin-module":"^1.0.0","semver":"2 || 3 || 4 || 5","validate-npm-package-license":"^3.0.1"}},"normalize-path":{"version":"2.1.1","resolved":"https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz","integrity":"sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=","dev":true,"requires":{"remove-trailing-separator":"^1.0.1"}},"npm-run-path":{"version":"2.0.2","resolved":"https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz","integrity":"sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=","dev":true,"requires":{"path-key":"^2.0.0"}},"number-is-nan":{"version":"1.0.1","resolved":"https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz","integrity":"sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=","dev":true},"nwsapi":{"version":"2.0.9","resolved":"https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz","integrity":"sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==","dev":true},"nyc":{"version":"14.1.1","resolved":"https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz","integrity":"sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==","dev":true,"requires":{"archy":"^1.0.0","caching-transform":"^3.0.2","convert-source-map":"^1.6.0","cp-file":"^6.2.0","find-cache-dir":"^2.1.0","find-up":"^3.0.0","foreground-child":"^1.5.6","glob":"^7.1.3","istanbul-lib-coverage":"^2.0.5","istanbul-lib-hook":"^2.0.7","istanbul-lib-instrument":"^3.3.0","istanbul-lib-report":"^2.0.8","istanbul-lib-source-maps":"^3.0.6","istanbul-reports":"^2.2.4","js-yaml":"^3.13.1","make-dir":"^2.1.0","merge-source-map":"^1.1.0","resolve-from":"^4.0.0","rimraf":"^2.6.3","signal-exit":"^3.0.2","spawn-wrap":"^1.4.2","test-exclude":"^5.2.3","uuid":"^3.3.2","yargs":"^13.2.2","yargs-parser":"^13.0.0"},"dependencies":{"@babel/generator":{"version":"7.4.4","resolved":"https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz","integrity":"sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==","dev":true,"requires":{"@babel/types":"^7.4.4","jsesc":"^2.5.1","lodash":"^4.17.11","source-map":"^0.5.0","trim-right":"^1.0.1"}},"@babel/helper-split-export-declaration":{"version":"7.4.4","resolved":"https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz","integrity":"sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==","dev":true,"requires":{"@babel/types":"^7.4.4"}},"@babel/parser":{"version":"7.4.5","resolved":"https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz","integrity":"sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==","dev":true},"@babel/template":{"version":"7.4.4","resolved":"https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz","integrity":"sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==","dev":true,"requires":{"@babel/code-frame":"^7.0.0","@babel/parser":"^7.4.4","@babel/types":"^7.4.4"}},"@babel/traverse":{"version":"7.4.5","resolved":"https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz","integrity":"sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==","dev":true,"requires":{"@babel/code-frame":"^7.0.0","@babel/generator":"^7.4.4","@babel/helper-function-name":"^7.1.0","@babel/helper-split-export-declaration":"^7.4.4","@babel/parser":"^7.4.5","@babel/types":"^7.4.4","debug":"^4.1.0","globals":"^11.1.0","lodash":"^4.17.11"}},"@babel/types":{"version":"7.4.4","resolved":"https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz","integrity":"sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==","dev":true,"requires":{"esutils":"^2.0.2","lodash":"^4.17.11","to-fast-properties":"^2.0.0"}},"ansi-regex":{"version":"4.1.0","resolved":"https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz","integrity":"sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==","dev":true},"cliui":{"version":"5.0.0","resolved":"https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz","integrity":"sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==","dev":true,"requires":{"string-width":"^3.1.0","strip-ansi":"^5.2.0","wrap-ansi":"^5.1.0"}},"execa":{"version":"1.0.0","resolved":"https://registry.npmjs.org/execa/-/execa-1.0.0.tgz","integrity":"sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==","dev":true,"requires":{"cross-spawn":"^6.0.0","get-stream":"^4.0.0","is-stream":"^1.1.0","npm-run-path":"^2.0.0","p-finally":"^1.0.0","signal-exit":"^3.0.0","strip-eof":"^1.0.0"}},"find-cache-dir":{"version":"2.1.0","resolved":"https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz","integrity":"sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==","dev":true,"requires":{"commondir":"^1.0.1","make-dir":"^2.0.0","pkg-dir":"^3.0.0"}},"find-up":{"version":"3.0.0","resolved":false,"integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"get-caller-file":{"version":"2.0.5","resolved":"https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz","integrity":"sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==","dev":true},"get-stream":{"version":"4.1.0","resolved":"https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz","integrity":"sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==","dev":true,"requires":{"pump":"^3.0.0"}},"istanbul-lib-coverage":{"version":"2.0.5","resolved":"https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz","integrity":"sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==","dev":true},"istanbul-lib-instrument":{"version":"3.3.0","resolved":"https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz","integrity":"sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==","dev":true,"requires":{"@babel/generator":"^7.4.0","@babel/parser":"^7.4.3","@babel/template":"^7.4.0","@babel/traverse":"^7.4.3","@babel/types":"^7.4.0","istanbul-lib-coverage":"^2.0.5","semver":"^6.0.0"},"dependencies":{"semver":{"version":"6.1.1","resolved":"https://registry.npmjs.org/semver/-/semver-6.1.1.tgz","integrity":"sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==","dev":true}}},"locate-path":{"version":"3.0.0","resolved":false,"integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"make-dir":{"version":"2.1.0","resolved":"https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz","integrity":"sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==","dev":true,"requires":{"pify":"^4.0.1","semver":"^5.6.0"}},"os-locale":{"version":"3.1.0","resolved":"https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz","integrity":"sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==","dev":true,"requires":{"execa":"^1.0.0","lcid":"^2.0.0","mem":"^4.0.0"}},"p-limit":{"version":"2.2.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz","integrity":"sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":false,"integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.2.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz","integrity":"sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==","dev":true},"pify":{"version":"4.0.1","resolved":"https://registry.npmjs.org/pify/-/pify-4.0.1.tgz","integrity":"sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==","dev":true},"pkg-dir":{"version":"3.0.0","resolved":false,"integrity":"sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==","dev":true,"requires":{"find-up":"^3.0.0"}},"pump":{"version":"3.0.0","resolved":"https://registry.npmjs.org/pump/-/pump-3.0.0.tgz","integrity":"sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==","dev":true,"requires":{"end-of-stream":"^1.1.0","once":"^1.3.1"}},"require-main-filename":{"version":"2.0.0","resolved":"https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz","integrity":"sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==","dev":true},"resolve-from":{"version":"4.0.0","resolved":false,"integrity":"sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==","dev":true},"rimraf":{"version":"2.6.3","resolved":"https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz","integrity":"sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==","dev":true,"requires":{"glob":"^7.1.3"}},"string-width":{"version":"3.1.0","resolved":"https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz","integrity":"sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==","dev":true,"requires":{"emoji-regex":"^7.0.1","is-fullwidth-code-point":"^2.0.0","strip-ansi":"^5.1.0"}},"strip-ansi":{"version":"5.2.0","resolved":"https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz","integrity":"sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==","dev":true,"requires":{"ansi-regex":"^4.1.0"}},"test-exclude":{"version":"5.2.3","resolved":"https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz","integrity":"sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==","dev":true,"requires":{"glob":"^7.1.3","minimatch":"^3.0.4","read-pkg-up":"^4.0.0","require-main-filename":"^2.0.0"}},"wrap-ansi":{"version":"5.1.0","resolved":"https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz","integrity":"sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==","dev":true,"requires":{"ansi-styles":"^3.2.0","string-width":"^3.0.0","strip-ansi":"^5.0.0"}},"yargs":{"version":"13.2.4","resolved":"https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz","integrity":"sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==","dev":true,"requires":{"cliui":"^5.0.0","find-up":"^3.0.0","get-caller-file":"^2.0.1","os-locale":"^3.1.0","require-directory":"^2.1.1","require-main-filename":"^2.0.0","set-blocking":"^2.0.0","string-width":"^3.0.0","which-module":"^2.0.0","y18n":"^4.0.0","yargs-parser":"^13.1.0"}},"yargs-parser":{"version":"13.1.1","resolved":"https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz","integrity":"sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==","dev":true,"requires":{"camelcase":"^5.0.0","decamelize":"^1.2.0"}}}},"oauth-sign":{"version":"0.9.0","resolved":"https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz","integrity":"sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==","dev":true},"object-assign":{"version":"4.1.1","resolved":"https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz","integrity":"sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=","dev":true},"object-copy":{"version":"0.1.0","resolved":"https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz","integrity":"sha1-fn2Fi3gb18mRpBupde04EnVOmYw=","dev":true,"requires":{"copy-descriptor":"^0.1.0","define-property":"^0.2.5","kind-of":"^3.0.3"},"dependencies":{"define-property":{"version":"0.2.5","resolved":"https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz","integrity":"sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=","dev":true,"requires":{"is-descriptor":"^0.1.0"}},"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"object-hash":{"version":"1.3.1","resolved":"https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz","integrity":"sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==","dev":true},"object-keys":{"version":"1.0.12","resolved":"https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz","integrity":"sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==","dev":true},"object-visit":{"version":"1.0.1","resolved":"https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz","integrity":"sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=","dev":true,"requires":{"isobject":"^3.0.0"}},"object.getownpropertydescriptors":{"version":"2.0.3","resolved":"https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz","integrity":"sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=","dev":true,"requires":{"define-properties":"^1.1.2","es-abstract":"^1.5.1"}},"object.omit":{"version":"2.0.1","resolved":"https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz","integrity":"sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=","dev":true,"requires":{"for-own":"^0.1.4","is-extendable":"^0.1.1"}},"object.pick":{"version":"1.3.0","resolved":"https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz","integrity":"sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=","dev":true,"requires":{"isobject":"^3.0.1"}},"once":{"version":"1.4.0","resolved":"https://registry.npmjs.org/once/-/once-1.4.0.tgz","integrity":"sha1-WDsap3WWHUsROsF9nFC6753Xa9E=","dev":true,"requires":{"wrappy":"1"}},"onetime":{"version":"2.0.1","resolved":"https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz","integrity":"sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=","dev":true,"requires":{"mimic-fn":"^1.0.0"}},"opener":{"version":"1.4.3","resolved":"https://registry.npmjs.org/opener/-/opener-1.4.3.tgz","integrity":"sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=","dev":true},"optimist":{"version":"0.6.1","resolved":"https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz","integrity":"sha1-2j6nRob6IaGaERwybpDrFaAZZoY=","dev":true,"requires":{"minimist":"~0.0.1","wordwrap":"~0.0.2"},"dependencies":{"wordwrap":{"version":"0.0.3","resolved":"https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz","integrity":"sha1-o9XabNXAvAAI03I0u68b7WMFkQc=","dev":true}}},"optionator":{"version":"0.8.2","resolved":"https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz","integrity":"sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=","dev":true,"requires":{"deep-is":"~0.1.3","fast-levenshtein":"~2.0.4","levn":"~0.3.0","prelude-ls":"~1.1.2","type-check":"~0.3.2","wordwrap":"~1.0.0"}},"os-browserify":{"version":"0.3.0","resolved":"https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz","integrity":"sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=","dev":true},"os-homedir":{"version":"1.0.2","resolved":"https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz","integrity":"sha1-/7xJiDNuDoM94MFox+8VISGqf7M=","dev":true},"os-locale":{"version":"3.0.1","resolved":"https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz","integrity":"sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==","dev":true,"requires":{"execa":"^0.10.0","lcid":"^2.0.0","mem":"^4.0.0"}},"os-tmpdir":{"version":"1.0.2","resolved":"http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz","integrity":"sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=","dev":true},"output-file-sync":{"version":"2.0.1","resolved":"https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz","integrity":"sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ==","dev":true,"requires":{"graceful-fs":"^4.1.11","is-plain-obj":"^1.1.0","mkdirp":"^0.5.1"}},"p-defer":{"version":"1.0.0","resolved":"https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz","integrity":"sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=","dev":true},"p-finally":{"version":"1.0.0","resolved":"https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz","integrity":"sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=","dev":true},"p-is-promise":{"version":"1.1.0","resolved":"http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz","integrity":"sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=","dev":true},"p-limit":{"version":"1.3.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz","integrity":"sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==","dev":true,"requires":{"p-try":"^1.0.0"}},"p-locate":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz","integrity":"sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=","dev":true,"requires":{"p-limit":"^1.1.0"}},"p-try":{"version":"1.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz","integrity":"sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=","dev":true},"package-hash":{"version":"3.0.0","resolved":"https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz","integrity":"sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==","dev":true,"requires":{"graceful-fs":"^4.1.15","hasha":"^3.0.0","lodash.flattendeep":"^4.4.0","release-zalgo":"^1.0.0"}},"pako":{"version":"1.0.6","resolved":"https://registry.npmjs.org/pako/-/pako-1.0.6.tgz","integrity":"sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==","dev":true},"parallel-transform":{"version":"1.1.0","resolved":"https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz","integrity":"sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=","dev":true,"requires":{"cyclist":"~0.2.2","inherits":"^2.0.3","readable-stream":"^2.1.5"}},"parse-asn1":{"version":"5.1.1","resolved":"http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz","integrity":"sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==","dev":true,"requires":{"asn1.js":"^4.0.0","browserify-aes":"^1.0.0","create-hash":"^1.1.0","evp_bytestokey":"^1.0.0","pbkdf2":"^3.0.3"}},"parse-glob":{"version":"3.0.4","resolved":"https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz","integrity":"sha1-ssN2z7EfNVE7rdFz7wu246OIORw=","dev":true,"requires":{"glob-base":"^0.3.0","is-dotfile":"^1.0.0","is-extglob":"^1.0.0","is-glob":"^2.0.0"},"dependencies":{"is-extglob":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz","integrity":"sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=","dev":true},"is-glob":{"version":"2.0.1","resolved":"https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz","integrity":"sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=","dev":true,"requires":{"is-extglob":"^1.0.0"}}}},"parse-json":{"version":"4.0.0","resolved":"https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz","integrity":"sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=","dev":true,"requires":{"error-ex":"^1.3.1","json-parse-better-errors":"^1.0.1"}},"parse5":{"version":"4.0.0","resolved":"https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz","integrity":"sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==","dev":true},"pascalcase":{"version":"0.1.1","resolved":"https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz","integrity":"sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=","dev":true},"path-browserify":{"version":"0.0.0","resolved":"https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz","integrity":"sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=","dev":true},"path-dirname":{"version":"1.0.2","resolved":"https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz","integrity":"sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=","dev":true},"path-exists":{"version":"3.0.0","resolved":"https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz","integrity":"sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=","dev":true},"path-is-absolute":{"version":"1.0.1","resolved":"http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz","integrity":"sha1-F0uSaHNVNP+8es5r9TpanhtcX18=","dev":true},"path-is-inside":{"version":"1.0.2","resolved":"https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz","integrity":"sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=","dev":true},"path-key":{"version":"2.0.1","resolved":"https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz","integrity":"sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=","dev":true},"path-parse":{"version":"1.0.6","resolved":"https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz","integrity":"sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==","dev":true},"path-type":{"version":"3.0.0","resolved":"https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz","integrity":"sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==","dev":true,"requires":{"pify":"^3.0.0"}},"pathval":{"version":"1.1.0","resolved":"https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz","integrity":"sha1-uULm1L3mUwBe9rcTYd74cn0GReA=","dev":true},"pbkdf2":{"version":"3.0.17","resolved":"https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz","integrity":"sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==","dev":true,"requires":{"create-hash":"^1.1.2","create-hmac":"^1.1.4","ripemd160":"^2.0.1","safe-buffer":"^5.0.1","sha.js":"^2.4.8"}},"performance-now":{"version":"2.1.0","resolved":"https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz","integrity":"sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=","dev":true},"pify":{"version":"3.0.0","resolved":"https://registry.npmjs.org/pify/-/pify-3.0.0.tgz","integrity":"sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=","dev":true},"pinkie":{"version":"2.0.4","resolved":"https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz","integrity":"sha1-clVrgM+g1IqXToDnckjoDtT3+HA=","dev":true},"pinkie-promise":{"version":"2.0.1","resolved":"https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz","integrity":"sha1-ITXW36ejWMBprJsXh3YogihFD/o=","dev":true,"requires":{"pinkie":"^2.0.0"}},"pirates":{"version":"3.0.2","resolved":"https://registry.npmjs.org/pirates/-/pirates-3.0.2.tgz","integrity":"sha512-c5CgUJq6H2k6MJz72Ak1F5sN9n9wlSlJyEnwvpm9/y3WB4E3pHBDT2c6PEiS1vyJvq2bUxUAIu0EGf8Cx4Ic7Q==","dev":true,"requires":{"node-modules-regexp":"^1.0.0"}},"pkg-dir":{"version":"2.0.0","resolved":"https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz","integrity":"sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=","dev":true,"requires":{"find-up":"^2.1.0"}},"pluralize":{"version":"7.0.0","resolved":"https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz","integrity":"sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==","dev":true},"pn":{"version":"1.1.0","resolved":"https://registry.npmjs.org/pn/-/pn-1.1.0.tgz","integrity":"sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==","dev":true},"portfinder":{"version":"1.0.20","resolved":"https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz","integrity":"sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==","dev":true,"requires":{"async":"^1.5.2","debug":"^2.2.0","mkdirp":"0.5.x"},"dependencies":{"debug":{"version":"2.6.9","resolved":"https://registry.npmjs.org/debug/-/debug-2.6.9.tgz","integrity":"sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==","dev":true,"requires":{"ms":"2.0.0"}},"ms":{"version":"2.0.0","resolved":"https://registry.npmjs.org/ms/-/ms-2.0.0.tgz","integrity":"sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=","dev":true}}},"posix-character-classes":{"version":"0.1.1","resolved":"https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz","integrity":"sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=","dev":true},"prelude-ls":{"version":"1.1.2","resolved":"https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz","integrity":"sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=","dev":true},"preserve":{"version":"0.2.0","resolved":"https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz","integrity":"sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=","dev":true},"private":{"version":"0.1.8","resolved":"https://registry.npmjs.org/private/-/private-0.1.8.tgz","integrity":"sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==","dev":true},"process":{"version":"0.11.10","resolved":"https://registry.npmjs.org/process/-/process-0.11.10.tgz","integrity":"sha1-czIwDoQBYb2j5podHZGn1LwW8YI=","dev":true},"process-nextick-args":{"version":"2.0.0","resolved":"https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz","integrity":"sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==","dev":true},"progress":{"version":"2.0.1","resolved":"https://registry.npmjs.org/progress/-/progress-2.0.1.tgz","integrity":"sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==","dev":true},"promise-inflight":{"version":"1.0.1","resolved":"https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz","integrity":"sha1-mEcocL8igTL8vdhoEputEsPAKeM=","dev":true},"prr":{"version":"1.0.1","resolved":"https://registry.npmjs.org/prr/-/prr-1.0.1.tgz","integrity":"sha1-0/wRS6BplaRexok/SEzrHXj19HY=","dev":true},"pseudomap":{"version":"1.0.2","resolved":"https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz","integrity":"sha1-8FKijacOYYkX7wqKw0wa5aaChrM=","dev":true},"psl":{"version":"1.1.29","resolved":"https://registry.npmjs.org/psl/-/psl-1.1.29.tgz","integrity":"sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==","dev":true},"public-encrypt":{"version":"4.0.3","resolved":"https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz","integrity":"sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==","dev":true,"requires":{"bn.js":"^4.1.0","browserify-rsa":"^4.0.0","create-hash":"^1.1.0","parse-asn1":"^5.0.0","randombytes":"^2.0.1","safe-buffer":"^5.1.2"}},"pump":{"version":"2.0.1","resolved":"https://registry.npmjs.org/pump/-/pump-2.0.1.tgz","integrity":"sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==","dev":true,"requires":{"end-of-stream":"^1.1.0","once":"^1.3.1"}},"pumpify":{"version":"1.5.1","resolved":"https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz","integrity":"sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==","dev":true,"requires":{"duplexify":"^3.6.0","inherits":"^2.0.3","pump":"^2.0.0"}},"punycode":{"version":"2.1.1","resolved":"https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz","integrity":"sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==","dev":true},"qs":{"version":"6.5.2","resolved":"https://registry.npmjs.org/qs/-/qs-6.5.2.tgz","integrity":"sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==","dev":true},"querystring":{"version":"0.2.0","resolved":"https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz","integrity":"sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=","dev":true},"querystring-es3":{"version":"0.2.1","resolved":"https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz","integrity":"sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=","dev":true},"randomatic":{"version":"3.1.1","resolved":"https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz","integrity":"sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==","dev":true,"requires":{"is-number":"^4.0.0","kind-of":"^6.0.0","math-random":"^1.0.1"},"dependencies":{"is-number":{"version":"4.0.0","resolved":"https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz","integrity":"sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==","dev":true}}},"randombytes":{"version":"2.0.6","resolved":"https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz","integrity":"sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==","dev":true,"requires":{"safe-buffer":"^5.1.0"}},"randomfill":{"version":"1.0.4","resolved":"https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz","integrity":"sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==","dev":true,"requires":{"randombytes":"^2.0.5","safe-buffer":"^5.1.0"}},"read-pkg":{"version":"3.0.0","resolved":"https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz","integrity":"sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=","dev":true,"requires":{"load-json-file":"^4.0.0","normalize-package-data":"^2.3.2","path-type":"^3.0.0"}},"read-pkg-up":{"version":"4.0.0","resolved":"https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz","integrity":"sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==","dev":true,"requires":{"find-up":"^3.0.0","read-pkg":"^3.0.0"},"dependencies":{"find-up":{"version":"3.0.0","resolved":"https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz","integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"locate-path":{"version":"3.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz","integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"p-limit":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz","integrity":"sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz","integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz","integrity":"sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==","dev":true}}},"readable-stream":{"version":"2.3.6","resolved":"http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz","integrity":"sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==","dev":true,"requires":{"core-util-is":"~1.0.0","inherits":"~2.0.3","isarray":"~1.0.0","process-nextick-args":"~2.0.0","safe-buffer":"~5.1.1","string_decoder":"~1.1.1","util-deprecate":"~1.0.1"}},"readdirp":{"version":"2.2.1","resolved":"https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz","integrity":"sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==","dev":true,"requires":{"graceful-fs":"^4.1.11","micromatch":"^3.1.10","readable-stream":"^2.0.2"}},"regenerate":{"version":"1.4.0","resolved":"https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz","integrity":"sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==","dev":true},"regenerate-unicode-properties":{"version":"7.0.0","resolved":"https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz","integrity":"sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==","dev":true,"requires":{"regenerate":"^1.4.0"}},"regenerator-runtime":{"version":"0.11.1","resolved":"https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz","integrity":"sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==","dev":true},"regenerator-transform":{"version":"0.13.3","resolved":"https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz","integrity":"sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==","dev":true,"requires":{"private":"^0.1.6"}},"regex-cache":{"version":"0.4.4","resolved":"https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz","integrity":"sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==","dev":true,"requires":{"is-equal-shallow":"^0.1.3"}},"regex-not":{"version":"1.0.2","resolved":"https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz","integrity":"sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==","dev":true,"requires":{"extend-shallow":"^3.0.2","safe-regex":"^1.1.0"}},"regexpp":{"version":"2.0.1","resolved":"https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz","integrity":"sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==","dev":true},"regexpu-core":{"version":"4.2.0","resolved":"https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz","integrity":"sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==","dev":true,"requires":{"regenerate":"^1.4.0","regenerate-unicode-properties":"^7.0.0","regjsgen":"^0.4.0","regjsparser":"^0.3.0","unicode-match-property-ecmascript":"^1.0.4","unicode-match-property-value-ecmascript":"^1.0.2"}},"regjsgen":{"version":"0.4.0","resolved":"https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz","integrity":"sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA==","dev":true},"regjsparser":{"version":"0.3.0","resolved":"https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz","integrity":"sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==","dev":true,"requires":{"jsesc":"~0.5.0"},"dependencies":{"jsesc":{"version":"0.5.0","resolved":"https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz","integrity":"sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=","dev":true}}},"release-zalgo":{"version":"1.0.0","resolved":"https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz","integrity":"sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=","dev":true,"requires":{"es6-error":"^4.0.1"}},"remove-trailing-separator":{"version":"1.1.0","resolved":"https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz","integrity":"sha1-wkvOKig62tW8P1jg1IJJuSN52O8=","dev":true},"repeat-element":{"version":"1.1.3","resolved":"https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz","integrity":"sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==","dev":true},"repeat-string":{"version":"1.6.1","resolved":"https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz","integrity":"sha1-jcrkcOHIirwtYA//Sndihtp15jc=","dev":true},"request":{"version":"2.88.0","resolved":"https://registry.npmjs.org/request/-/request-2.88.0.tgz","integrity":"sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==","dev":true,"requires":{"aws-sign2":"~0.7.0","aws4":"^1.8.0","caseless":"~0.12.0","combined-stream":"~1.0.6","extend":"~3.0.2","forever-agent":"~0.6.1","form-data":"~2.3.2","har-validator":"~5.1.0","http-signature":"~1.2.0","is-typedarray":"~1.0.0","isstream":"~0.1.2","json-stringify-safe":"~5.0.1","mime-types":"~2.1.19","oauth-sign":"~0.9.0","performance-now":"^2.1.0","qs":"~6.5.2","safe-buffer":"^5.1.2","tough-cookie":"~2.4.3","tunnel-agent":"^0.6.0","uuid":"^3.3.2"}},"request-promise-core":{"version":"1.1.1","resolved":"https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz","integrity":"sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=","dev":true,"requires":{"lodash":"^4.13.1"}},"request-promise-native":{"version":"1.0.5","resolved":"https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz","integrity":"sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=","dev":true,"requires":{"request-promise-core":"1.1.1","stealthy-require":"^1.1.0","tough-cookie":">=2.3.3"}},"require-directory":{"version":"2.1.1","resolved":"https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz","integrity":"sha1-jGStX9MNqxyXbiNE/+f3kqam30I=","dev":true},"require-main-filename":{"version":"1.0.1","resolved":"https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz","integrity":"sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=","dev":true},"require-uncached":{"version":"1.0.3","resolved":"http://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz","integrity":"sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=","dev":true,"requires":{"caller-path":"^0.1.0","resolve-from":"^1.0.0"}},"requires-port":{"version":"1.0.0","resolved":"https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz","integrity":"sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=","dev":true},"resolve":{"version":"1.8.1","resolved":"https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz","integrity":"sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==","dev":true,"requires":{"path-parse":"^1.0.5"}},"resolve-cwd":{"version":"2.0.0","resolved":"https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz","integrity":"sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=","dev":true,"requires":{"resolve-from":"^3.0.0"},"dependencies":{"resolve-from":{"version":"3.0.0","resolved":"https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz","integrity":"sha1-six699nWiBvItuZTM17rywoYh0g=","dev":true}}},"resolve-from":{"version":"1.0.1","resolved":"https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz","integrity":"sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=","dev":true},"resolve-url":{"version":"0.2.1","resolved":"https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz","integrity":"sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=","dev":true},"restore-cursor":{"version":"2.0.0","resolved":"https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz","integrity":"sha1-n37ih/gv0ybU/RYpI9YhKe7g368=","dev":true,"requires":{"onetime":"^2.0.0","signal-exit":"^3.0.2"}},"ret":{"version":"0.1.15","resolved":"https://registry.npmjs.org/ret/-/ret-0.1.15.tgz","integrity":"sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==","dev":true},"rimraf":{"version":"2.6.2","resolved":"https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz","integrity":"sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==","dev":true,"requires":{"glob":"^7.0.5"}},"ripemd160":{"version":"2.0.2","resolved":"https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz","integrity":"sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==","dev":true,"requires":{"hash-base":"^3.0.0","inherits":"^2.0.1"}},"run-async":{"version":"2.3.0","resolved":"https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz","integrity":"sha1-A3GrSuC91yDUFm19/aZP96RFpsA=","dev":true,"requires":{"is-promise":"^2.1.0"}},"run-queue":{"version":"1.0.3","resolved":"https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz","integrity":"sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=","dev":true,"requires":{"aproba":"^1.1.1"}},"rxjs":{"version":"6.3.3","resolved":"https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz","integrity":"sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==","dev":true,"requires":{"tslib":"^1.9.0"}},"safe-buffer":{"version":"5.1.2","resolved":"https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz","integrity":"sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==","dev":true},"safe-regex":{"version":"1.1.0","resolved":"http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz","integrity":"sha1-QKNmnzsHfR6UPURinhV91IAjvy4=","dev":true,"requires":{"ret":"~0.1.10"}},"safer-buffer":{"version":"2.1.2","resolved":"https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz","integrity":"sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==","dev":true},"sax":{"version":"1.2.4","resolved":"https://registry.npmjs.org/sax/-/sax-1.2.4.tgz","integrity":"sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==","dev":true},"schema-utils":{"version":"0.4.7","resolved":"https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz","integrity":"sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==","dev":true,"requires":{"ajv":"^6.1.0","ajv-keywords":"^3.1.0"}},"semver":{"version":"5.6.0","resolved":"https://registry.npmjs.org/semver/-/semver-5.6.0.tgz","integrity":"sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==","dev":true},"serialize-javascript":{"version":"1.5.0","resolved":"https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz","integrity":"sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==","dev":true},"set-blocking":{"version":"2.0.0","resolved":"https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz","integrity":"sha1-BF+XgtARrppoA93TgrJDkrPYkPc=","dev":true},"set-value":{"version":"2.0.1","resolved":"https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz","integrity":"sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==","dev":true,"requires":{"extend-shallow":"^2.0.1","is-extendable":"^0.1.1","is-plain-object":"^2.0.3","split-string":"^3.0.1"},"dependencies":{"extend-shallow":{"version":"2.0.1","resolved":"https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz","integrity":"sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=","dev":true,"requires":{"is-extendable":"^0.1.0"}}}},"setimmediate":{"version":"1.0.5","resolved":"https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz","integrity":"sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=","dev":true},"sha.js":{"version":"2.4.11","resolved":"http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz","integrity":"sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==","dev":true,"requires":{"inherits":"^2.0.1","safe-buffer":"^5.0.1"}},"shebang-command":{"version":"1.2.0","resolved":"https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz","integrity":"sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=","dev":true,"requires":{"shebang-regex":"^1.0.0"}},"shebang-regex":{"version":"1.0.0","resolved":"https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz","integrity":"sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=","dev":true},"signal-exit":{"version":"3.0.2","resolved":"https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz","integrity":"sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=","dev":true},"slash":{"version":"2.0.0","resolved":"https://registry.npmjs.org/slash/-/slash-2.0.0.tgz","integrity":"sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==","dev":true},"slice-ansi":{"version":"1.0.0","resolved":"https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz","integrity":"sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==","dev":true,"requires":{"is-fullwidth-code-point":"^2.0.0"}},"snapdragon":{"version":"0.8.2","resolved":"https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz","integrity":"sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==","dev":true,"requires":{"base":"^0.11.1","debug":"^2.2.0","define-property":"^0.2.5","extend-shallow":"^2.0.1","map-cache":"^0.2.2","source-map":"^0.5.6","source-map-resolve":"^0.5.0","use":"^3.1.0"},"dependencies":{"debug":{"version":"2.6.9","resolved":"https://registry.npmjs.org/debug/-/debug-2.6.9.tgz","integrity":"sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==","dev":true,"requires":{"ms":"2.0.0"}},"define-property":{"version":"0.2.5","resolved":"https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz","integrity":"sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=","dev":true,"requires":{"is-descriptor":"^0.1.0"}},"extend-shallow":{"version":"2.0.1","resolved":"https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz","integrity":"sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=","dev":true,"requires":{"is-extendable":"^0.1.0"}},"ms":{"version":"2.0.0","resolved":"https://registry.npmjs.org/ms/-/ms-2.0.0.tgz","integrity":"sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=","dev":true}}},"snapdragon-node":{"version":"2.1.1","resolved":"https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz","integrity":"sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==","dev":true,"requires":{"define-property":"^1.0.0","isobject":"^3.0.0","snapdragon-util":"^3.0.1"},"dependencies":{"define-property":{"version":"1.0.0","resolved":"https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz","integrity":"sha1-dp66rz9KY6rTr56NMEybvnm/sOY=","dev":true,"requires":{"is-descriptor":"^1.0.0"}},"is-accessor-descriptor":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz","integrity":"sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==","dev":true,"requires":{"kind-of":"^6.0.0"}},"is-data-descriptor":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz","integrity":"sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==","dev":true,"requires":{"kind-of":"^6.0.0"}},"is-descriptor":{"version":"1.0.2","resolved":"https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz","integrity":"sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==","dev":true,"requires":{"is-accessor-descriptor":"^1.0.0","is-data-descriptor":"^1.0.0","kind-of":"^6.0.2"}}}},"snapdragon-util":{"version":"3.0.1","resolved":"https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz","integrity":"sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==","dev":true,"requires":{"kind-of":"^3.2.0"},"dependencies":{"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"source-list-map":{"version":"2.0.1","resolved":"https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz","integrity":"sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==","dev":true},"source-map":{"version":"0.5.7","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz","integrity":"sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=","dev":true},"source-map-resolve":{"version":"0.5.2","resolved":"https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz","integrity":"sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==","dev":true,"requires":{"atob":"^2.1.1","decode-uri-component":"^0.2.0","resolve-url":"^0.2.1","source-map-url":"^0.4.0","urix":"^0.1.0"}},"source-map-support":{"version":"0.4.18","resolved":"https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz","integrity":"sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==","dev":true,"requires":{"source-map":"^0.5.6"}},"source-map-url":{"version":"0.4.0","resolved":"https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz","integrity":"sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=","dev":true},"spawn-wrap":{"version":"1.4.2","resolved":"https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz","integrity":"sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==","dev":true,"requires":{"foreground-child":"^1.5.6","mkdirp":"^0.5.0","os-homedir":"^1.0.1","rimraf":"^2.6.2","signal-exit":"^3.0.2","which":"^1.3.0"}},"spdx-correct":{"version":"3.0.2","resolved":"https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz","integrity":"sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==","dev":true,"requires":{"spdx-expression-parse":"^3.0.0","spdx-license-ids":"^3.0.0"}},"spdx-exceptions":{"version":"2.2.0","resolved":"https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz","integrity":"sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==","dev":true},"spdx-expression-parse":{"version":"3.0.0","resolved":"https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz","integrity":"sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==","dev":true,"requires":{"spdx-exceptions":"^2.1.0","spdx-license-ids":"^3.0.0"}},"spdx-license-ids":{"version":"3.0.2","resolved":"https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz","integrity":"sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==","dev":true},"split-string":{"version":"3.1.0","resolved":"https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz","integrity":"sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==","dev":true,"requires":{"extend-shallow":"^3.0.0"}},"sprintf-js":{"version":"1.0.3","resolved":"https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz","integrity":"sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=","dev":true},"sshpk":{"version":"1.15.2","resolved":"https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz","integrity":"sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==","dev":true,"requires":{"asn1":"~0.2.3","assert-plus":"^1.0.0","bcrypt-pbkdf":"^1.0.0","dashdash":"^1.12.0","ecc-jsbn":"~0.1.1","getpass":"^0.1.1","jsbn":"~0.1.0","safer-buffer":"^2.0.2","tweetnacl":"~0.14.0"}},"ssri":{"version":"5.3.0","resolved":"https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz","integrity":"sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==","dev":true,"requires":{"safe-buffer":"^5.1.1"}},"static-extend":{"version":"0.1.2","resolved":"https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz","integrity":"sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=","dev":true,"requires":{"define-property":"^0.2.5","object-copy":"^0.1.0"},"dependencies":{"define-property":{"version":"0.2.5","resolved":"https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz","integrity":"sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=","dev":true,"requires":{"is-descriptor":"^0.1.0"}}}},"stealthy-require":{"version":"1.1.1","resolved":"https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz","integrity":"sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=","dev":true},"stream-browserify":{"version":"2.0.1","resolved":"http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz","integrity":"sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=","dev":true,"requires":{"inherits":"~2.0.1","readable-stream":"^2.0.2"}},"stream-each":{"version":"1.2.3","resolved":"https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz","integrity":"sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==","dev":true,"requires":{"end-of-stream":"^1.1.0","stream-shift":"^1.0.0"}},"stream-http":{"version":"2.8.3","resolved":"https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz","integrity":"sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==","dev":true,"requires":{"builtin-status-codes":"^3.0.0","inherits":"^2.0.1","readable-stream":"^2.3.6","to-arraybuffer":"^1.0.0","xtend":"^4.0.0"}},"stream-shift":{"version":"1.0.0","resolved":"https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz","integrity":"sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=","dev":true},"string-width":{"version":"2.1.1","resolved":"https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz","integrity":"sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==","dev":true,"requires":{"is-fullwidth-code-point":"^2.0.0","strip-ansi":"^4.0.0"}},"string_decoder":{"version":"1.1.1","resolved":"https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz","integrity":"sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==","dev":true,"requires":{"safe-buffer":"~5.1.0"}},"strip-ansi":{"version":"4.0.0","resolved":"https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz","integrity":"sha1-qEeQIusaw2iocTibY1JixQXuNo8=","dev":true,"requires":{"ansi-regex":"^3.0.0"}},"strip-bom":{"version":"3.0.0","resolved":"https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz","integrity":"sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=","dev":true},"strip-eof":{"version":"1.0.0","resolved":"http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz","integrity":"sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=","dev":true},"strip-json-comments":{"version":"2.0.1","resolved":"https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz","integrity":"sha1-PFMZQukIwml8DsNEhYwobHygpgo=","dev":true},"supports-color":{"version":"5.5.0","resolved":"https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz","integrity":"sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==","dev":true,"requires":{"has-flag":"^3.0.0"}},"symbol-tree":{"version":"3.2.2","resolved":"https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz","integrity":"sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=","dev":true},"table":{"version":"5.1.0","resolved":"https://registry.npmjs.org/table/-/table-5.1.0.tgz","integrity":"sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==","dev":true,"requires":{"ajv":"^6.5.3","lodash":"^4.17.10","slice-ansi":"1.0.0","string-width":"^2.1.1"}},"tapable":{"version":"1.1.0","resolved":"https://registry.npmjs.org/tapable/-/tapable-1.1.0.tgz","integrity":"sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==","dev":true},"terser":{"version":"3.10.12","resolved":"https://registry.npmjs.org/terser/-/terser-3.10.12.tgz","integrity":"sha512-3ODPC1eVt25EVNb04s/PkHxOmzKBQUF6bwwuR6h2DbEF8/j265Y1UkwNtOk9am/pRxfJ5HPapOlUlO6c16mKQQ==","dev":true,"requires":{"commander":"~2.17.1","source-map":"~0.6.1","source-map-support":"~0.5.6"},"dependencies":{"commander":{"version":"2.17.1","resolved":"https://registry.npmjs.org/commander/-/commander-2.17.1.tgz","integrity":"sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==","dev":true},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true},"source-map-support":{"version":"0.5.9","resolved":"https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz","integrity":"sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==","dev":true,"requires":{"buffer-from":"^1.0.0","source-map":"^0.6.0"}}}},"terser-webpack-plugin":{"version":"1.1.0","resolved":"https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz","integrity":"sha512-61lV0DSxMAZ8AyZG7/A4a3UPlrbOBo8NIQ4tJzLPAdGOQ+yoNC7l5ijEow27lBAL2humer01KLS6bGIMYQxKoA==","dev":true,"requires":{"cacache":"^11.0.2","find-cache-dir":"^2.0.0","schema-utils":"^1.0.0","serialize-javascript":"^1.4.0","source-map":"^0.6.1","terser":"^3.8.1","webpack-sources":"^1.1.0","worker-farm":"^1.5.2"},"dependencies":{"cacache":{"version":"11.3.1","resolved":"https://registry.npmjs.org/cacache/-/cacache-11.3.1.tgz","integrity":"sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==","dev":true,"requires":{"bluebird":"^3.5.1","chownr":"^1.0.1","figgy-pudding":"^3.1.0","glob":"^7.1.2","graceful-fs":"^4.1.11","lru-cache":"^4.1.3","mississippi":"^3.0.0","mkdirp":"^0.5.1","move-concurrently":"^1.0.1","promise-inflight":"^1.0.1","rimraf":"^2.6.2","ssri":"^6.0.0","unique-filename":"^1.1.0","y18n":"^4.0.0"}},"find-cache-dir":{"version":"2.0.0","resolved":"https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz","integrity":"sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==","dev":true,"requires":{"commondir":"^1.0.1","make-dir":"^1.0.0","pkg-dir":"^3.0.0"}},"find-up":{"version":"3.0.0","resolved":"https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz","integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"locate-path":{"version":"3.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz","integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"mississippi":{"version":"3.0.0","resolved":"https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz","integrity":"sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==","dev":true,"requires":{"concat-stream":"^1.5.0","duplexify":"^3.4.2","end-of-stream":"^1.1.0","flush-write-stream":"^1.0.0","from2":"^2.1.0","parallel-transform":"^1.1.0","pump":"^3.0.0","pumpify":"^1.3.3","stream-each":"^1.1.0","through2":"^2.0.0"}},"p-limit":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz","integrity":"sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz","integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz","integrity":"sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==","dev":true},"pkg-dir":{"version":"3.0.0","resolved":"https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz","integrity":"sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==","dev":true,"requires":{"find-up":"^3.0.0"}},"pump":{"version":"3.0.0","resolved":"https://registry.npmjs.org/pump/-/pump-3.0.0.tgz","integrity":"sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==","dev":true,"requires":{"end-of-stream":"^1.1.0","once":"^1.3.1"}},"schema-utils":{"version":"1.0.0","resolved":"https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz","integrity":"sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==","dev":true,"requires":{"ajv":"^6.1.0","ajv-errors":"^1.0.0","ajv-keywords":"^3.1.0"}},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true},"ssri":{"version":"6.0.1","resolved":"https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz","integrity":"sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==","dev":true,"requires":{"figgy-pudding":"^3.5.1"}}}},"test-exclude":{"version":"5.0.0","resolved":"https://registry.npmjs.org/test-exclude/-/test-exclude-5.0.0.tgz","integrity":"sha512-bO3Lj5+qFa9YLfYW2ZcXMOV1pmQvw+KS/DpjqhyX6Y6UZ8zstpZJ+mA2ERkXfpOqhxsJlQiLeVXD3Smsrs6oLw==","dev":true,"requires":{"arrify":"^1.0.1","minimatch":"^3.0.4","read-pkg-up":"^4.0.0","require-main-filename":"^1.0.1"}},"text-table":{"version":"0.2.0","resolved":"https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz","integrity":"sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=","dev":true},"through":{"version":"2.3.8","resolved":"http://registry.npmjs.org/through/-/through-2.3.8.tgz","integrity":"sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=","dev":true},"through2":{"version":"2.0.5","resolved":"https://registry.npmjs.org/through2/-/through2-2.0.5.tgz","integrity":"sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==","dev":true,"requires":{"readable-stream":"~2.3.6","xtend":"~4.0.1"}},"timers-browserify":{"version":"2.0.10","resolved":"https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz","integrity":"sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==","dev":true,"requires":{"setimmediate":"^1.0.4"}},"tmp":{"version":"0.0.33","resolved":"https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz","integrity":"sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==","dev":true,"requires":{"os-tmpdir":"~1.0.2"}},"to-arraybuffer":{"version":"1.0.1","resolved":"https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz","integrity":"sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=","dev":true},"to-fast-properties":{"version":"2.0.0","resolved":"https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz","integrity":"sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=","dev":true},"to-object-path":{"version":"0.3.0","resolved":"https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz","integrity":"sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=","dev":true,"requires":{"kind-of":"^3.0.2"},"dependencies":{"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"to-regex":{"version":"3.0.2","resolved":"https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz","integrity":"sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==","dev":true,"requires":{"define-property":"^2.0.2","extend-shallow":"^3.0.2","regex-not":"^1.0.2","safe-regex":"^1.1.0"}},"to-regex-range":{"version":"2.1.1","resolved":"https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz","integrity":"sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=","dev":true,"requires":{"is-number":"^3.0.0","repeat-string":"^1.6.1"}},"tough-cookie":{"version":"2.4.3","resolved":"https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz","integrity":"sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==","dev":true,"requires":{"psl":"^1.1.24","punycode":"^1.4.1"},"dependencies":{"punycode":{"version":"1.4.1","resolved":"https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz","integrity":"sha1-wNWmOycYgArY4esPpSachN1BhF4=","dev":true}}},"tr46":{"version":"1.0.1","resolved":"https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz","integrity":"sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=","dev":true,"requires":{"punycode":"^2.1.0"}},"trim-right":{"version":"1.0.1","resolved":"https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz","integrity":"sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=","dev":true},"tslib":{"version":"1.9.3","resolved":"https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz","integrity":"sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==","dev":true},"tty-browserify":{"version":"0.0.0","resolved":"https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz","integrity":"sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=","dev":true},"tunnel-agent":{"version":"0.6.0","resolved":"https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz","integrity":"sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=","dev":true,"requires":{"safe-buffer":"^5.0.1"}},"tweetnacl":{"version":"0.14.5","resolved":"https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz","integrity":"sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=","dev":true},"type-check":{"version":"0.3.2","resolved":"https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz","integrity":"sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=","dev":true,"requires":{"prelude-ls":"~1.1.2"}},"type-detect":{"version":"4.0.8","resolved":"https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz","integrity":"sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==","dev":true},"typedarray":{"version":"0.0.6","resolved":"https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz","integrity":"sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=","dev":true},"uglify-es":{"version":"3.3.9","resolved":"https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz","integrity":"sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==","dev":true,"requires":{"commander":"~2.13.0","source-map":"~0.6.1"},"dependencies":{"commander":{"version":"2.13.0","resolved":"https://registry.npmjs.org/commander/-/commander-2.13.0.tgz","integrity":"sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==","dev":true},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true}}},"uglifyjs-webpack-plugin":{"version":"1.3.0","resolved":"https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz","integrity":"sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==","dev":true,"requires":{"cacache":"^10.0.4","find-cache-dir":"^1.0.0","schema-utils":"^0.4.5","serialize-javascript":"^1.4.0","source-map":"^0.6.1","uglify-es":"^3.3.4","webpack-sources":"^1.1.0","worker-farm":"^1.5.2"},"dependencies":{"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true}}},"unicode-canonical-property-names-ecmascript":{"version":"1.0.4","resolved":"https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz","integrity":"sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==","dev":true},"unicode-match-property-ecmascript":{"version":"1.0.4","resolved":"https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz","integrity":"sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==","dev":true,"requires":{"unicode-canonical-property-names-ecmascript":"^1.0.4","unicode-property-aliases-ecmascript":"^1.0.4"}},"unicode-match-property-value-ecmascript":{"version":"1.0.2","resolved":"https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz","integrity":"sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ==","dev":true},"unicode-property-aliases-ecmascript":{"version":"1.0.4","resolved":"https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz","integrity":"sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg==","dev":true},"union":{"version":"0.4.6","resolved":"https://registry.npmjs.org/union/-/union-0.4.6.tgz","integrity":"sha1-GY+9rrolTniLDvy2MLwR8kopWeA=","dev":true,"requires":{"qs":"~2.3.3"},"dependencies":{"qs":{"version":"2.3.3","resolved":"https://registry.npmjs.org/qs/-/qs-2.3.3.tgz","integrity":"sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=","dev":true}}},"union-value":{"version":"1.0.1","resolved":"https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz","integrity":"sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==","dev":true,"requires":{"arr-union":"^3.1.0","get-value":"^2.0.6","is-extendable":"^0.1.1","set-value":"^2.0.1"}},"unique-filename":{"version":"1.1.1","resolved":"https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz","integrity":"sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==","dev":true,"requires":{"unique-slug":"^2.0.0"}},"unique-slug":{"version":"2.0.1","resolved":"https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz","integrity":"sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==","dev":true,"requires":{"imurmurhash":"^0.1.4"}},"unset-value":{"version":"1.0.0","resolved":"https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz","integrity":"sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=","dev":true,"requires":{"has-value":"^0.3.1","isobject":"^3.0.0"},"dependencies":{"has-value":{"version":"0.3.1","resolved":"https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz","integrity":"sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=","dev":true,"requires":{"get-value":"^2.0.3","has-values":"^0.1.4","isobject":"^2.0.0"},"dependencies":{"isobject":{"version":"2.1.0","resolved":"https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz","integrity":"sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=","dev":true,"requires":{"isarray":"1.0.0"}}}},"has-values":{"version":"0.1.4","resolved":"https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz","integrity":"sha1-bWHeldkd/Km5oCCJrThL/49it3E=","dev":true}}},"upath":{"version":"1.1.0","resolved":"https://registry.npmjs.org/upath/-/upath-1.1.0.tgz","integrity":"sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==","dev":true},"uri-js":{"version":"4.2.2","resolved":"https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz","integrity":"sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==","dev":true,"requires":{"punycode":"^2.1.0"}},"urix":{"version":"0.1.0","resolved":"https://registry.npmjs.org/urix/-/urix-0.1.0.tgz","integrity":"sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=","dev":true},"url":{"version":"0.11.0","resolved":"https://registry.npmjs.org/url/-/url-0.11.0.tgz","integrity":"sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=","dev":true,"requires":{"punycode":"1.3.2","querystring":"0.2.0"},"dependencies":{"punycode":{"version":"1.3.2","resolved":"https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz","integrity":"sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=","dev":true}}},"url-join":{"version":"2.0.5","resolved":"https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz","integrity":"sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=","dev":true},"use":{"version":"3.1.1","resolved":"https://registry.npmjs.org/use/-/use-3.1.1.tgz","integrity":"sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==","dev":true},"util":{"version":"0.10.4","resolved":"https://registry.npmjs.org/util/-/util-0.10.4.tgz","integrity":"sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==","dev":true,"requires":{"inherits":"2.0.3"}},"util-deprecate":{"version":"1.0.2","resolved":"https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz","integrity":"sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=","dev":true},"util.promisify":{"version":"1.0.0","resolved":"https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz","integrity":"sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==","dev":true,"requires":{"define-properties":"^1.1.2","object.getownpropertydescriptors":"^2.0.3"}},"uuid":{"version":"3.3.2","resolved":"https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz","integrity":"sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==","dev":true},"v8-compile-cache":{"version":"2.0.2","resolved":"https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz","integrity":"sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw==","dev":true},"validate-npm-package-license":{"version":"3.0.4","resolved":"https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz","integrity":"sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==","dev":true,"requires":{"spdx-correct":"^3.0.0","spdx-expression-parse":"^3.0.0"}},"verror":{"version":"1.10.0","resolved":"https://registry.npmjs.org/verror/-/verror-1.10.0.tgz","integrity":"sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=","dev":true,"requires":{"assert-plus":"^1.0.0","core-util-is":"1.0.2","extsprintf":"^1.2.0"}},"vm-browserify":{"version":"0.0.4","resolved":"https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz","integrity":"sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=","dev":true,"requires":{"indexof":"0.0.1"}},"w3c-hr-time":{"version":"1.0.1","resolved":"https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz","integrity":"sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=","dev":true,"requires":{"browser-process-hrtime":"^0.1.2"}},"watchpack":{"version":"1.6.0","resolved":"https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz","integrity":"sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==","dev":true,"requires":{"chokidar":"^2.0.2","graceful-fs":"^4.1.2","neo-async":"^2.5.0"}},"webidl-conversions":{"version":"4.0.2","resolved":"https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz","integrity":"sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==","dev":true},"webpack":{"version":"4.26.0","resolved":"https://registry.npmjs.org/webpack/-/webpack-4.26.0.tgz","integrity":"sha512-J/dP9SJIc5OtX2FZ/+U9ikQtd6H6Mcbqt0xeXtmPwYGDKf8nkbOQQA9KL2Y0rJOsN1Al9Pdn+/j63X58ub8gvQ==","dev":true,"requires":{"@webassemblyjs/ast":"1.7.11","@webassemblyjs/helper-module-context":"1.7.11","@webassemblyjs/wasm-edit":"1.7.11","@webassemblyjs/wasm-parser":"1.7.11","acorn":"^5.6.2","acorn-dynamic-import":"^3.0.0","ajv":"^6.1.0","ajv-keywords":"^3.1.0","chrome-trace-event":"^1.0.0","enhanced-resolve":"^4.1.0","eslint-scope":"^4.0.0","json-parse-better-errors":"^1.0.2","loader-runner":"^2.3.0","loader-utils":"^1.1.0","memory-fs":"~0.4.1","micromatch":"^3.1.8","mkdirp":"~0.5.0","neo-async":"^2.5.0","node-libs-browser":"^2.0.0","schema-utils":"^0.4.4","tapable":"^1.1.0","terser-webpack-plugin":"^1.1.0","watchpack":"^1.5.0","webpack-sources":"^1.3.0"},"dependencies":{"acorn":{"version":"5.7.4","resolved":"https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz","integrity":"sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==","dev":true},"eslint-scope":{"version":"4.0.0","resolved":"https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz","integrity":"sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==","dev":true,"requires":{"esrecurse":"^4.1.0","estraverse":"^4.1.1"}}}},"webpack-cli":{"version":"3.1.2","resolved":"https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.1.2.tgz","integrity":"sha512-Cnqo7CeqeSvC6PTdts+dywNi5CRlIPbLx1AoUPK2T6vC1YAugMG3IOoO9DmEscd+Dghw7uRlnzV1KwOe5IrtgQ==","dev":true,"requires":{"chalk":"^2.4.1","cross-spawn":"^6.0.5","enhanced-resolve":"^4.1.0","global-modules-path":"^2.3.0","import-local":"^2.0.0","interpret":"^1.1.0","loader-utils":"^1.1.0","supports-color":"^5.5.0","v8-compile-cache":"^2.0.2","yargs":"^12.0.2"},"dependencies":{"find-up":{"version":"3.0.0","resolved":"https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz","integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"locate-path":{"version":"3.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz","integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"p-limit":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz","integrity":"sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz","integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz","integrity":"sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==","dev":true},"yargs":{"version":"12.0.5","resolved":"https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz","integrity":"sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==","dev":true,"requires":{"cliui":"^4.0.0","decamelize":"^1.2.0","find-up":"^3.0.0","get-caller-file":"^1.0.1","os-locale":"^3.0.0","require-directory":"^2.1.1","require-main-filename":"^1.0.1","set-blocking":"^2.0.0","string-width":"^2.0.0","which-module":"^2.0.0","y18n":"^3.2.1 || ^4.0.0","yargs-parser":"^11.1.1"}}}},"webpack-sources":{"version":"1.3.0","resolved":"https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz","integrity":"sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==","dev":true,"requires":{"source-list-map":"^2.0.0","source-map":"~0.6.1"},"dependencies":{"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true}}},"whatwg-encoding":{"version":"1.0.5","resolved":"https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz","integrity":"sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==","dev":true,"requires":{"iconv-lite":"0.4.24"}},"whatwg-mimetype":{"version":"2.3.0","resolved":"https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz","integrity":"sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==","dev":true},"whatwg-url":{"version":"6.5.0","resolved":"https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz","integrity":"sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==","dev":true,"requires":{"lodash.sortby":"^4.7.0","tr46":"^1.0.1","webidl-conversions":"^4.0.2"}},"which":{"version":"1.3.1","resolved":"https://registry.npmjs.org/which/-/which-1.3.1.tgz","integrity":"sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==","dev":true,"requires":{"isexe":"^2.0.0"}},"which-module":{"version":"2.0.0","resolved":"https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz","integrity":"sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=","dev":true},"wordwrap":{"version":"1.0.0","resolved":"https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz","integrity":"sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=","dev":true},"worker-farm":{"version":"1.6.0","resolved":"https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz","integrity":"sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==","dev":true,"requires":{"errno":"~0.1.7"}},"wrap-ansi":{"version":"2.1.0","resolved":"https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz","integrity":"sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=","dev":true,"requires":{"string-width":"^1.0.1","strip-ansi":"^3.0.1"},"dependencies":{"ansi-regex":{"version":"2.1.1","resolved":"https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz","integrity":"sha1-w7M6te42DYbg5ijwRorn7yfWVN8=","dev":true},"is-fullwidth-code-point":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz","integrity":"sha1-754xOG8DGn8NZDr4L95QxFfvAMs=","dev":true,"requires":{"number-is-nan":"^1.0.0"}},"string-width":{"version":"1.0.2","resolved":"https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz","integrity":"sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=","dev":true,"requires":{"code-point-at":"^1.0.0","is-fullwidth-code-point":"^1.0.0","strip-ansi":"^3.0.0"}},"strip-ansi":{"version":"3.0.1","resolved":"https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz","integrity":"sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=","dev":true,"requires":{"ansi-regex":"^2.0.0"}}}},"wrappy":{"version":"1.0.2","resolved":"https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz","integrity":"sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=","dev":true},"write":{"version":"0.2.1","resolved":"https://registry.npmjs.org/write/-/write-0.2.1.tgz","integrity":"sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=","dev":true,"requires":{"mkdirp":"^0.5.1"}},"write-file-atomic":{"version":"2.4.3","resolved":"https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz","integrity":"sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==","dev":true,"requires":{"graceful-fs":"^4.1.11","imurmurhash":"^0.1.4","signal-exit":"^3.0.2"}},"ws":{"version":"4.1.0","resolved":"http://registry.npmjs.org/ws/-/ws-4.1.0.tgz","integrity":"sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==","dev":true,"requires":{"async-limiter":"~1.0.0","safe-buffer":"~5.1.0"}},"xml-name-validator":{"version":"3.0.0","resolved":"https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz","integrity":"sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==","dev":true},"xtend":{"version":"4.0.1","resolved":"https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz","integrity":"sha1-pcbVMr5lbiPbgg77lDofBJmNY68=","dev":true},"y18n":{"version":"4.0.0","resolved":"https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz","integrity":"sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==","dev":true},"yallist":{"version":"3.0.3","resolved":"https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz","integrity":"sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==","dev":true},"yargs":{"version":"10.1.2","resolved":"https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz","integrity":"sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==","dev":true,"requires":{"cliui":"^4.0.0","decamelize":"^1.1.1","find-up":"^2.1.0","get-caller-file":"^1.0.1","os-locale":"^2.0.0","require-directory":"^2.1.1","require-main-filename":"^1.0.1","set-blocking":"^2.0.0","string-width":"^2.0.0","which-module":"^2.0.0","y18n":"^3.2.1","yargs-parser":"^8.1.0"},"dependencies":{"camelcase":{"version":"4.1.0","resolved":"https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz","integrity":"sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=","dev":true},"cross-spawn":{"version":"5.1.0","resolved":"https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz","integrity":"sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=","dev":true,"requires":{"lru-cache":"^4.0.1","shebang-command":"^1.2.0","which":"^1.2.9"}},"execa":{"version":"0.7.0","resolved":"https://registry.npmjs.org/execa/-/execa-0.7.0.tgz","integrity":"sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=","dev":true,"requires":{"cross-spawn":"^5.0.1","get-stream":"^3.0.0","is-stream":"^1.1.0","npm-run-path":"^2.0.0","p-finally":"^1.0.0","signal-exit":"^3.0.0","strip-eof":"^1.0.0"}},"invert-kv":{"version":"1.0.0","resolved":"https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz","integrity":"sha1-EEqOSqym09jNFXqO+L+rLXo//bY=","dev":true},"lcid":{"version":"1.0.0","resolved":"https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz","integrity":"sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=","dev":true,"requires":{"invert-kv":"^1.0.0"}},"mem":{"version":"1.1.0","resolved":"https://registry.npmjs.org/mem/-/mem-1.1.0.tgz","integrity":"sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=","dev":true,"requires":{"mimic-fn":"^1.0.0"}},"os-locale":{"version":"2.1.0","resolved":"https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz","integrity":"sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==","dev":true,"requires":{"execa":"^0.7.0","lcid":"^1.0.0","mem":"^1.1.0"}},"y18n":{"version":"3.2.1","resolved":"https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz","integrity":"sha1-bRX7qITAhnnA136I53WegR4H+kE=","dev":true},"yargs-parser":{"version":"8.1.0","resolved":"https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz","integrity":"sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==","dev":true,"requires":{"camelcase":"^4.1.0"}}}},"yargs-parser":{"version":"11.1.1","resolved":"https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz","integrity":"sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==","dev":true,"requires":{"camelcase":"^5.0.0","decamelize":"^1.2.0"}}}} \ No newline at end of file diff --git a/lib/darkmode-js/package.json b/lib/darkmode-js/package.json new file mode 100644 index 00000000..013a50b3 --- /dev/null +++ b/lib/darkmode-js/package.json @@ -0,0 +1 @@ +{"name":"darkmode-js","version":"1.5.7","description":"🌓 Add darkmode / nightmode to your website in a few seconds","main":"lib/darkmode-js.js","scripts":{"build":"webpack --env dev && webpack --env build && npm run test","dev":"webpack --progress --colors --watch --env dev","serve":"http-server","test":"mocha --require babel-register --colors ./test/*.spec.js","test:watch":"mocha --require babel-register --colors -w ./test/*.spec.js","test:cover":"cross-env NODE_ENV=test nyc mocha --require babel-register --colors test/*.js","repl":"node -i -e \"$(< ./lib/darkmode-js.js)\""},"repository":{"type":"git","url":"https://github.com/sandoche/Darkmode.js.git"},"keywords":["darkmode","dark","nightmode","night","dark-mode","night-mode","darktheme","dark-theme","vanilla","vanillajs","widget"],"author":"Sandoche Adittane","license":"MIT","bugs":{"url":"https://github.com/sandoche/Darkmode.js/issues"},"homepage":"https://github.com/sandoche/Darkmode.js","devDependencies":{"@babel/cli":"^7.0.0-beta.51","@babel/core":"^7.0.0-beta.51","@babel/preset-env":"^7.0.0-beta.51","babel-eslint":"^8.0.3","babel-loader":"^8.0.0-beta.4","babel-plugin-add-module-exports":"^0.2.1","babel-plugin-istanbul":"^5.1.0","babel-preset-env":"^7.0.0-beta.3","babel-register":"^7.0.0-beta.3","chai":"^4.1.2","chai-dom":"^1.8.1","cross-env":"^5.2.0","eslint":"^5.0.1","eslint-loader":"^2.0.0","http-server":"^0.11.1","jsdom":"11.11.0","jsdom-global":"3.0.2","mocha":"^4.0.1","nyc":"^14.1.1","uglifyjs-webpack-plugin":"^1.2.7","webpack":"^4.12.2","webpack-cli":"^3.0.8","yargs":"^10.0.3"},"nyc":{"sourceMap":false,"instrument":false}} \ No newline at end of file diff --git a/lib/darkmode-js/src/darkmode.js b/lib/darkmode-js/src/darkmode.js new file mode 100644 index 00000000..967b082a --- /dev/null +++ b/lib/darkmode-js/src/darkmode.js @@ -0,0 +1,228 @@ +export const IS_BROWSER = typeof window !== 'undefined'; + +export default class Darkmode { + constructor(options) { + if (!IS_BROWSER) { + return; + } + + const defaultOptions = { + bottom: '32px', + right: '32px', + left: 'unset', + time: '0.3s', + mixColor: '#fff', + backgroundColor: '#fff', + buttonColorDark: '#100f2c', + buttonColorLight: '#fff', + label: '', + saveInCookies: true, + autoMatchOsTheme: true + }; + + options = Object.assign({}, defaultOptions, options); + + const css = ` + .darkmode-layer { + position: fixed; + pointer-events: none; + background: ${options.mixColor}; + transition: all ${options.time} ease; + mix-blend-mode: difference; + } + + .darkmode-layer--button { + width: 2.9rem; + height: 2.9rem; + border-radius: 50%; + right: ${options.right}; + bottom: ${options.bottom}; + left: ${options.left}; + } + + .darkmode-layer--simple { + width: 100%; + height: 100%; + top: 0; + left: 0; + transform: scale(1) !important; + } + + .darkmode-layer--expanded { + transform: scale(100); + border-radius: 0; + } + + .darkmode-layer--no-transition { + transition: none; + } + + .darkmode-toggle { + background: ${options.buttonColorDark}; + width: 3rem; + height: 3rem; + position: fixed; + border-radius: 50%; + border:none; + right: ${options.right}; + bottom: ${options.bottom}; + left: ${options.left}; + cursor: pointer; + transition: all 0.5s ease; + display: flex; + justify-content: center; + align-items: center; + } + + .darkmode-toggle--white { + background: ${options.buttonColorLight}; + } + + .darkmode-toggle--inactive { + display: none; + } + + .darkmode-background { + background: ${options.backgroundColor}; + position: fixed; + pointer-events: none; + z-index: -10; + width: 100%; + height: 100%; + top: 0; + left: 0; + } + + img, .darkmode-ignore { + isolation: isolate; + display: inline-block; + } + + @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .darkmode-toggle {display: none !important} + } + + @supports (-ms-ime-align:auto), (-ms-accelerator:true) { + .darkmode-toggle {display: none !important} + } + `; + + const layer = document.createElement('div'); + const button = document.createElement('button'); + const background = document.createElement('div'); + + button.innerHTML = options.label; + button.classList.add('darkmode-toggle--inactive'); + layer.classList.add('darkmode-layer'); + background.classList.add('darkmode-background'); + + const darkmodeActivated = + window.localStorage.getItem('darkmode') === 'true'; + const preferedThemeOs = + options.autoMatchOsTheme && + window.matchMedia('(prefers-color-scheme: dark)').matches; + const darkmodeNeverActivatedByAction = + window.localStorage.getItem('darkmode') === null; + + if ( + (darkmodeActivated === true && options.saveInCookies) || + (darkmodeNeverActivatedByAction && preferedThemeOs) + ) { + layer.classList.add( + 'darkmode-layer--expanded', + 'darkmode-layer--simple', + 'darkmode-layer--no-transition' + ); + button.classList.add('darkmode-toggle--white'); + document.body.classList.add('darkmode--activated'); + } + + document.body.insertBefore(button, document.body.firstChild); + document.body.insertBefore(layer, document.body.firstChild); + document.body.insertBefore(background, document.body.firstChild); + + this.addStyle(css); + + this.button = button; + this.layer = layer; + this.saveInCookies = options.saveInCookies; + this.time = options.time; + } + + addStyle(css) { + const linkElement = document.createElement('link'); + + linkElement.setAttribute('rel', 'stylesheet'); + linkElement.setAttribute('type', 'text/css'); + linkElement.setAttribute( + 'href', + 'data:text/css;charset=UTF-8,' + encodeURIComponent(css) + ); + document.head.appendChild(linkElement); + } + + showWidget() { + if (!IS_BROWSER) { + return; + } + const button = this.button; + const layer = this.layer; + const time = parseFloat(this.time) * 1000; + + button.classList.add('darkmode-toggle'); + button.classList.remove('darkmode-toggle--inactive'); + button.setAttribute("aria-label", "Activate dark mode"); + button.setAttribute("aria-checked", "false"); + button.setAttribute("role", "checkbox"); + layer.classList.add('darkmode-layer--button'); + + button.addEventListener('click', () => { + const isDarkmode = this.isActivated(); + + if (!isDarkmode) { + layer.classList.add('darkmode-layer--expanded'); + button.setAttribute('disabled', true); + setTimeout(() => { + layer.classList.add('darkmode-layer--no-transition'); + layer.classList.add('darkmode-layer--simple'); + button.removeAttribute('disabled'); + }, time); + } else { + layer.classList.remove('darkmode-layer--simple'); + button.setAttribute('disabled', true); + setTimeout(() => { + layer.classList.remove('darkmode-layer--no-transition'); + layer.classList.remove('darkmode-layer--expanded'); + button.removeAttribute('disabled'); + }, 1); + } + + button.classList.toggle('darkmode-toggle--white'); + document.body.classList.toggle('darkmode--activated'); + window.localStorage.setItem('darkmode', !isDarkmode); + }); + } + + toggle() { + if (!IS_BROWSER) { + return; + } + const layer = this.layer; + const isDarkmode = this.isActivated(); + const button = this.button; + + layer.classList.toggle('darkmode-layer--simple'); + document.body.classList.toggle('darkmode--activated'); + window.localStorage.setItem('darkmode', !isDarkmode); + button.setAttribute("aria-label", "De-activate dark mode"); + button.setAttribute("aria-checked", "true"); + + } + + isActivated() { + if (!IS_BROWSER) { + return null; + } + return document.body.classList.contains('darkmode--activated'); + } +} diff --git a/lib/darkmode-js/src/index.js b/lib/darkmode-js/src/index.js new file mode 100644 index 00000000..4fbdcd40 --- /dev/null +++ b/lib/darkmode-js/src/index.js @@ -0,0 +1,10 @@ +import Darkmode, { IS_BROWSER } from './darkmode'; +export default Darkmode; + +/* eslint-disable */ +if (IS_BROWSER) { + (function(window) { + window.Darkmode = Darkmode; + })(window); +} +/* eslint-enable */ diff --git a/lib/darkmode-js/test/index.html b/lib/darkmode-js/test/index.html new file mode 100644 index 00000000..7e8edd18 --- /dev/null +++ b/lib/darkmode-js/test/index.html @@ -0,0 +1,38 @@ + + + + Manual testing of Darkmode widget + + + +
    +
    +

    Darkmode manual test

    +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Massa tempor nec feugiat nisl pretium. In iaculis nunc sed augue lacus viverra vitae congue eu. At tellus at urna condimentum mattis pellentesque id nibh. Pretium aenean pharetra magna ac placerat vestibulum. Integer enim neque volutpat ac tincidunt vitae semper. Dictum sit amet justo donec enim diam vulputate ut. Ut tellus elementum sagittis vitae et leo duis. Vitae sapien pellentesque habitant morbi. Pellentesque diam volutpat commodo sed egestas egestas fringilla. A arcu cursus vitae congue mauris rhoncus aenean vel elit. Potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed. +

    +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Massa tempor nec feugiat nisl pretium. In iaculis nunc sed augue lacus viverra vitae congue eu. At tellus at urna condimentum mattis pellentesque id nibh. Pretium aenean pharetra magna ac placerat vestibulum. Integer enim neque volutpat ac tincidunt vitae semper. Dictum sit amet justo donec enim diam vulputate ut. Ut tellus elementum sagittis vitae et leo duis. Vitae sapien pellentesque habitant morbi. Pellentesque diam volutpat commodo sed egestas egestas fringilla. A arcu cursus vitae congue mauris rhoncus aenean vel elit. Potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed. +

    +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Massa tempor nec feugiat nisl pretium. In iaculis nunc sed augue lacus viverra vitae congue eu. At tellus at urna condimentum mattis pellentesque id nibh. Pretium aenean pharetra magna ac placerat vestibulum. Integer enim neque volutpat ac tincidunt vitae semper. Dictum sit amet justo donec enim diam vulputate ut. Ut tellus elementum sagittis vitae et leo duis. Vitae sapien pellentesque habitant morbi. Pellentesque diam volutpat commodo sed egestas egestas fringilla. A arcu cursus vitae congue mauris rhoncus aenean vel elit. Potenti nullam ac tortor vitae purus faucibus ornare suspendisse sed. +

    +
    +
    + + + + \ No newline at end of file diff --git a/lib/darkmode-js/test/index.spec.js b/lib/darkmode-js/test/index.spec.js new file mode 100644 index 00000000..33a8bb42 --- /dev/null +++ b/lib/darkmode-js/test/index.spec.js @@ -0,0 +1,72 @@ +/* global describe, it, before */ + +import chai from 'chai'; +import Darkmode from '../lib/darkmode-js'; + +chai.use(require('chai-dom')); +chai.expect(); + +const expect = chai.expect; + +// mocking local storage +global.window = { + localStorage: { + getItem: function(id) { + return true; + }, + setItem: function() {} + }, + matchMedia() { + return { + matches: false + } + } +}; + +describe('Given an instance of Darkmode', () => { + var darkmode = new Darkmode({ + bottom: '64px', + right: 'unset', + left: '32px', + time: '0.5s', + mixColor: '#fff', + buttonColorDark: '#100f2c', + buttonColorLight: '#fff', + saveInCookies: false, + label: '🌓', + autoMatchOsTheme: true + }); + describe('After creating an instance', () => { + it('should not activate darkmode', () => { + expect(darkmode.isActivated()).to.be.false; + }) + + it('should set the widget as inactive', () => { + expect(document.getElementsByClassName('darkmode-toggle--inactive')[0]).to.not.be.undefined; + }) + }) + describe('When I run toggle()', () => { + it('should activate darkmode', () => { + darkmode.toggle(); + expect(darkmode.isActivated()).to.be.true; + }) + }) + describe('When I run toggle() a second time', () => { + it('should disactivate darkmode', () => { + darkmode.toggle(); + expect(darkmode.isActivated()).to.be.false; + }) + }) + describe('When I run showWidget()', () => { + it('the widget should have its label', () => { + darkmode.showWidget(); + expect(document.getElementsByClassName('darkmode-toggle')[0]).to.have.html('🌓'); + }) + + it('should make the widget visible', () => { + darkmode.showWidget(); + expect(document.getElementsByClassName('darkmode-toggle')[0].classList.toString()).to.not.include('darkmode-toggle--inactive'); + }) + }) + +}); diff --git a/lib/darkmode-js/test/mocha.opts b/lib/darkmode-js/test/mocha.opts new file mode 100644 index 00000000..df2a0f2f --- /dev/null +++ b/lib/darkmode-js/test/mocha.opts @@ -0,0 +1 @@ +-r jsdom-global/register \ No newline at end of file diff --git a/lib/darkmode-js/webpack.config.js b/lib/darkmode-js/webpack.config.js new file mode 100644 index 00000000..5613944b --- /dev/null +++ b/lib/darkmode-js/webpack.config.js @@ -0,0 +1,54 @@ +/* global __dirname, require, module*/ + +const path = require('path'); +const env = require('yargs').argv.env; // use --env with webpack 2 +const pkg = require('./package.json'); + +let libraryName = pkg.name; + +let outputFile, mode; + +if (env === 'build') { + mode = 'production'; + outputFile = libraryName + '.min.js'; +} else { + mode = 'development'; + outputFile = libraryName + '.js'; +} + +const config = { + mode: mode, + entry: __dirname + '/src/index.js', + devtool: mode === 'production' ? false : 'inline-source-map', + output: { + path: __dirname + '/lib', + filename: outputFile, + library: libraryName, + libraryTarget: 'umd', + umdNamedDefine: true, + globalObject: "typeof self !== 'undefined' ? self : this" + }, + module: { + rules: [ + { + test: /(\.js)$/, + loader: 'babel-loader', + exclude: /(node_modules)/ + }, + { + test: /(\.js)$/, + loader: 'eslint-loader', + exclude: /node_modules/, + options: { + fix: true + } + } + ] + }, + resolve: { + modules: [path.resolve('./node_modules'), path.resolve('./src')], + extensions: ['.json', '.js'] + } +}; + +module.exports = config; diff --git a/page/2/index.html b/page/2/index.html index 4d6337d6..63be88ce 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -2648,6 +2648,10 @@

    前言程序员阿淼 + + diff --git a/page/3/index.html b/page/3/index.html index 2ed61eb6..8609301f 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -2681,6 +2681,10 @@

    程序员阿淼 + + diff --git a/page/4/index.html b/page/4/index.html index e1cab829..afc2e8bc 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -1355,6 +1355,10 @@

    程序员阿淼 + + diff --git a/post/102cd3d9.html b/post/102cd3d9.html index aa7c2297..a29194c1 100644 --- a/post/102cd3d9.html +++ b/post/102cd3d9.html @@ -1074,6 +1074,10 @@

    总结程序员阿淼 + + diff --git a/post/11cb7677.html b/post/11cb7677.html index bf3a3dfa..52171253 100644 --- a/post/11cb7677.html +++ b/post/11cb7677.html @@ -925,6 +925,10 @@

    总结程序员阿淼 + + diff --git a/post/192cb539.html b/post/192cb539.html index 82d0fa36..183dda96 100644 --- a/post/192cb539.html +++ b/post/192cb539.html @@ -989,6 +989,10 @@

    程序员阿淼 + + diff --git a/post/24042edf.html b/post/24042edf.html index b2a48891..6d7933e3 100644 --- a/post/24042edf.html +++ b/post/24042edf.html @@ -997,6 +997,10 @@

    总结程序员阿淼 + + diff --git a/post/24cb2421.html b/post/24cb2421.html index 0ed33907..9b9effab 100644 --- a/post/24cb2421.html +++ b/post/24cb2421.html @@ -930,6 +930,10 @@

    总结程序员阿淼 + + diff --git a/post/315ff4dc.html b/post/315ff4dc.html index d28cefa4..b74c6c7f 100644 --- a/post/315ff4dc.html +++ b/post/315ff4dc.html @@ -909,6 +909,10 @@

    总结程序员阿淼 + + diff --git a/post/34755d6c.html b/post/34755d6c.html index e7261a6f..1b70bbc7 100644 --- a/post/34755d6c.html +++ b/post/34755d6c.html @@ -904,6 +904,10 @@

    总结程序员阿淼 + + diff --git a/post/3ae0ff4e.html b/post/3ae0ff4e.html index 336f29ea..9563d092 100644 --- a/post/3ae0ff4e.html +++ b/post/3ae0ff4e.html @@ -971,6 +971,10 @@

    总结程序员阿淼 + + diff --git a/post/4615256d.html b/post/4615256d.html index 3eea11d2..e834889d 100644 --- a/post/4615256d.html +++ b/post/4615256d.html @@ -980,6 +980,10 @@

    程序员阿淼 + + diff --git a/post/4b00e13c.html b/post/4b00e13c.html index 687749ed..32c9a635 100644 --- a/post/4b00e13c.html +++ b/post/4b00e13c.html @@ -1079,6 +1079,10 @@

    总结程序员阿淼 + + diff --git a/post/4ea48fa7.html b/post/4ea48fa7.html index dbaed950..2d91ce30 100644 --- a/post/4ea48fa7.html +++ b/post/4ea48fa7.html @@ -912,6 +912,10 @@

    总结程序员阿淼 + + diff --git a/post/51e5bd99.html b/post/51e5bd99.html index 4ad47a6e..af202998 100644 --- a/post/51e5bd99.html +++ b/post/51e5bd99.html @@ -953,6 +953,10 @@

    程序员阿淼 + + diff --git a/post/558ca0bd.html b/post/558ca0bd.html index 82aaf8ea..5193c3f6 100644 --- a/post/558ca0bd.html +++ b/post/558ca0bd.html @@ -914,6 +914,10 @@

    3 程序员阿淼 + + diff --git a/post/710bd10b.html b/post/710bd10b.html index 719f8033..6cd2170b 100644 --- a/post/710bd10b.html +++ b/post/710bd10b.html @@ -959,6 +959,10 @@

    总结程序员阿淼 + + diff --git a/post/7528c810.html b/post/7528c810.html index cbc30491..693ca628 100644 --- a/post/7528c810.html +++ b/post/7528c810.html @@ -942,6 +942,10 @@

    总结程序员阿淼 + + diff --git a/post/7b9ead86.html b/post/7b9ead86.html index b0c63c3e..0be368b4 100644 --- a/post/7b9ead86.html +++ b/post/7b9ead86.html @@ -942,6 +942,10 @@

    总结程序员阿淼 + + diff --git a/post/7eb2637f.html b/post/7eb2637f.html index 285e126f..cd5c1d98 100644 --- a/post/7eb2637f.html +++ b/post/7eb2637f.html @@ -981,6 +981,10 @@

    程序员阿淼 + + diff --git a/post/817c7d82.html b/post/817c7d82.html index 81af1513..e0770b10 100644 --- a/post/817c7d82.html +++ b/post/817c7d82.html @@ -1550,6 +1550,10 @@

    程序员阿淼 + + diff --git a/post/8a061473.html b/post/8a061473.html index 2174e520..f8bc0486 100644 --- a/post/8a061473.html +++ b/post/8a061473.html @@ -1018,6 +1018,10 @@
    程序员阿淼 + + diff --git a/post/8bd965a0.html b/post/8bd965a0.html index 34b12d25..5caf3cb9 100644 --- a/post/8bd965a0.html +++ b/post/8bd965a0.html @@ -941,6 +941,10 @@

    程序员阿淼 + + diff --git a/post/99ea2970.html b/post/99ea2970.html index 8795637c..0e1f3731 100644 --- a/post/99ea2970.html +++ b/post/99ea2970.html @@ -937,6 +937,10 @@

    程序员阿淼 + + diff --git a/post/a38c0645.html b/post/a38c0645.html index 4e3dd653..bb783372 100644 --- a/post/a38c0645.html +++ b/post/a38c0645.html @@ -921,6 +921,10 @@

    总结程序员阿淼 + + diff --git a/post/ab706eb5.html b/post/ab706eb5.html index 736b4b1b..236c6c2c 100644 --- a/post/ab706eb5.html +++ b/post/ab706eb5.html @@ -924,6 +924,10 @@

    总结程序员阿淼 + + diff --git a/post/b1d4025b.html b/post/b1d4025b.html index 8e328a65..79d137b9 100644 --- a/post/b1d4025b.html +++ b/post/b1d4025b.html @@ -854,6 +854,10 @@

    hello world

    程序员阿淼 + + diff --git a/post/bc557e1a.html b/post/bc557e1a.html index d6c1ad2f..6fbc2f99 100644 --- a/post/bc557e1a.html +++ b/post/bc557e1a.html @@ -989,6 +989,10 @@
    程序员阿淼 + + diff --git a/post/bfcdfeaf.html b/post/bfcdfeaf.html index 494f2c98..2e035134 100644 --- a/post/bfcdfeaf.html +++ b/post/bfcdfeaf.html @@ -941,6 +941,10 @@

    程序员阿淼 + + diff --git a/post/c34b451f.html b/post/c34b451f.html index 25ec5d6c..3453d808 100644 --- a/post/c34b451f.html +++ b/post/c34b451f.html @@ -980,6 +980,10 @@

    总结程序员阿淼 + + diff --git a/post/d7d0fc76.html b/post/d7d0fc76.html index 6d3a27e7..5b55b4e3 100644 --- a/post/d7d0fc76.html +++ b/post/d7d0fc76.html @@ -906,6 +906,10 @@

    程序员阿淼 + + diff --git a/post/e09f0428.html b/post/e09f0428.html index 96261fcb..572a4574 100644 --- a/post/e09f0428.html +++ b/post/e09f0428.html @@ -911,6 +911,10 @@

    程序员阿淼 + + diff --git a/post/ee27c07f.html b/post/ee27c07f.html index 18bd93a8..2cdba6da 100644 --- a/post/ee27c07f.html +++ b/post/ee27c07f.html @@ -904,6 +904,10 @@

    程序员阿淼 + + diff --git a/post/f440d00b.html b/post/f440d00b.html index dd399129..89bc0539 100644 --- a/post/f440d00b.html +++ b/post/f440d00b.html @@ -940,6 +940,10 @@

    总结程序员阿淼 + + diff --git a/post/f92758d8.html b/post/f92758d8.html index 2438aded..86197d9b 100644 --- a/post/f92758d8.html +++ b/post/f92758d8.html @@ -928,6 +928,10 @@

    总结程序员阿淼 + + diff --git a/post/fa75f5d7.html b/post/fa75f5d7.html index b09530f1..36c0fe87 100644 --- a/post/fa75f5d7.html +++ b/post/fa75f5d7.html @@ -944,6 +944,10 @@

    程序员阿淼 + + diff --git a/post/fe76043.html b/post/fe76043.html index b8a79417..ee35c702 100644 --- a/post/fe76043.html +++ b/post/fe76043.html @@ -907,6 +907,10 @@

    总结程序员阿淼 + + diff --git a/tags/Bloom-filter/index.html b/tags/Bloom-filter/index.html index fe9f223b..60e744fb 100644 --- a/tags/Bloom-filter/index.html +++ b/tags/Bloom-filter/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/CAP\345\256\232\347\220\206/index.html" "b/tags/CAP\345\256\232\347\220\206/index.html" index 8904dd5e..3adcad18 100644 --- "a/tags/CAP\345\256\232\347\220\206/index.html" +++ "b/tags/CAP\345\256\232\347\220\206/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/Constructor-\346\263\250\345\205\245/index.html" "b/tags/Constructor-\346\263\250\345\205\245/index.html" index 09896de9..362af5c3 100644 --- "a/tags/Constructor-\346\263\250\345\205\245/index.html" +++ "b/tags/Constructor-\346\263\250\345\205\245/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/Eureka/index.html b/tags/Eureka/index.html index 4da77089..c663f4a3 100644 --- a/tags/Eureka/index.html +++ b/tags/Eureka/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/GC/index.html b/tags/GC/index.html index 478a40a8..924b942e 100644 --- a/tags/GC/index.html +++ b/tags/GC/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/Guava/index.html b/tags/Guava/index.html index 93d4c071..53168c02 100644 --- a/tags/Guava/index.html +++ b/tags/Guava/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/IDEA/index.html b/tags/IDEA/index.html index a5ebcd59..5b001867 100644 --- a/tags/IDEA/index.html +++ b/tags/IDEA/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/IO\346\250\241\345\236\213/index.html" "b/tags/IO\346\250\241\345\236\213/index.html" index 3c573b89..abef1b24 100644 --- "a/tags/IO\346\250\241\345\236\213/index.html" +++ "b/tags/IO\346\250\241\345\236\213/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/IoC/index.html b/tags/IoC/index.html index f2414ff2..23e05897 100644 --- a/tags/IoC/index.html +++ b/tags/IoC/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/JDK/index.html b/tags/JDK/index.html index c6cb285f..f86a6544 100644 --- a/tags/JDK/index.html +++ b/tags/JDK/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/JVM/index.html b/tags/JVM/index.html index 255bdd43..18582a65 100644 --- a/tags/JVM/index.html +++ b/tags/JVM/index.html @@ -639,6 +639,10 @@

    程序员阿淼 + + diff --git "a/tags/Java-\345\216\237\347\220\206/index.html" "b/tags/Java-\345\216\237\347\220\206/index.html" index f73195b5..ad198d95 100644 --- "a/tags/Java-\345\216\237\347\220\206/index.html" +++ "b/tags/Java-\345\216\237\347\220\206/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/Java-\345\271\266\345\217\221/index.html" "b/tags/Java-\345\271\266\345\217\221/index.html" index c677164e..a463ce9b 100644 --- "a/tags/Java-\345\271\266\345\217\221/index.html" +++ "b/tags/Java-\345\271\266\345\217\221/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/Java/index.html b/tags/Java/index.html index 454c0d4f..6678b751 100644 --- a/tags/Java/index.html +++ b/tags/Java/index.html @@ -851,6 +851,10 @@

    程序员阿淼 + + diff --git a/tags/Java/page/2/index.html b/tags/Java/page/2/index.html index 11548ccf..fb6aa654 100644 --- a/tags/Java/page/2/index.html +++ b/tags/Java/page/2/index.html @@ -851,6 +851,10 @@

    程序员阿淼 + + diff --git a/tags/Java/page/3/index.html b/tags/Java/page/3/index.html index 833fa459..d7c9f653 100644 --- a/tags/Java/page/3/index.html +++ b/tags/Java/page/3/index.html @@ -825,6 +825,10 @@

    程序员阿淼 + + diff --git "a/tags/Linux\347\254\224\350\256\260/index.html" "b/tags/Linux\347\254\224\350\256\260/index.html" index 14d2885b..3f2025b2 100644 --- "a/tags/Linux\347\254\224\350\256\260/index.html" +++ "b/tags/Linux\347\254\224\350\256\260/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/List/index.html b/tags/List/index.html index bcbcb6d3..720b495f 100644 --- a/tags/List/index.html +++ b/tags/List/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/RabbitMQ/index.html b/tags/RabbitMQ/index.html index 48d83f60..e578ac82 100644 --- a/tags/RabbitMQ/index.html +++ b/tags/RabbitMQ/index.html @@ -639,6 +639,10 @@

    程序员阿淼 + + diff --git a/tags/Spring/index.html b/tags/Spring/index.html index ae0ddee8..c920902f 100644 --- a/tags/Spring/index.html +++ b/tags/Spring/index.html @@ -665,6 +665,10 @@

    程序员阿淼 + + diff --git a/tags/String/index.html b/tags/String/index.html index 037c769b..2275a65b 100644 --- a/tags/String/index.html +++ b/tags/String/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/index.html b/tags/index.html index 71740201..1e35a094 100644 --- a/tags/index.html +++ b/tags/index.html @@ -605,6 +605,10 @@

    程序员阿淼 + + diff --git a/tags/mockito/index.html b/tags/mockito/index.html index 712bf758..e93b2168 100644 --- a/tags/mockito/index.html +++ b/tags/mockito/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git a/tags/test/index.html b/tags/test/index.html index 3412e160..3c217426 100644 --- a/tags/test/index.html +++ b/tags/test/index.html @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" index 7b8411a1..b44eafed 100644 --- "a/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" +++ "b/tags/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/\345\217\215\345\260\204/index.html" "b/tags/\345\217\215\345\260\204/index.html" index bbf2373a..9ca54774 100644 --- "a/tags/\345\217\215\345\260\204/index.html" +++ "b/tags/\345\217\215\345\260\204/index.html" @@ -639,6 +639,10 @@

    程序员阿淼 + + diff --git "a/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/tags/\345\244\232\347\272\277\347\250\213/index.html" index 969e285f..434f971c 100644 --- "a/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -639,6 +639,10 @@

    程序员阿淼 + + diff --git "a/tags/\345\267\245\345\205\267/index.html" "b/tags/\345\267\245\345\205\267/index.html" index 0dab8383..8679a096 100644 --- "a/tags/\345\267\245\345\205\267/index.html" +++ "b/tags/\345\267\245\345\205\267/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" index fe6bb789..4e38e557 100644 --- "a/tags/\345\271\266\345\217\221/index.html" +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -639,6 +639,10 @@

    程序员阿淼 + + diff --git "a/tags/\345\274\202\346\255\245/index.html" "b/tags/\345\274\202\346\255\245/index.html" index 4b9736f2..3cd424db 100644 --- "a/tags/\345\274\202\346\255\245/index.html" +++ "b/tags/\345\274\202\346\255\245/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" index 36512bdc..aade9e72 100644 --- "a/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" +++ "b/tags/\346\234\215\345\212\241\345\217\221\347\216\260/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" index 118590f0..f6352b8a 100644 --- "a/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" +++ "b/tags/\347\211\210\346\234\254\347\256\241\347\220\206\345\267\245\345\205\267/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/\347\274\223\345\255\230/index.html" "b/tags/\347\274\223\345\255\230/index.html" index 82a4bba3..6dd3fb11 100644 --- "a/tags/\347\274\223\345\255\230/index.html" +++ "b/tags/\347\274\223\345\255\230/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + diff --git "a/tags/\351\207\215\346\236\204/index.html" "b/tags/\351\207\215\346\236\204/index.html" index bbd34da4..c75b4b84 100644 --- "a/tags/\351\207\215\346\236\204/index.html" +++ "b/tags/\351\207\215\346\236\204/index.html" @@ -613,6 +613,10 @@

    程序员阿淼 + + From 4feca2d915bc8773dff1fe18600e8d62ca501a82 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 06:41:36 +0000 Subject: [PATCH 19/19] Bump lodash from 4.17.14 to 4.17.20 in /lib/darkmode-js Bumps [lodash](https://github.com/lodash/lodash) from 4.17.14 to 4.17.20. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.14...4.17.20) Signed-off-by: dependabot[bot] --- lib/darkmode-js/package-lock.json | 9343 ++++++++++++++++++++++++++++- 1 file changed, 9342 insertions(+), 1 deletion(-) diff --git a/lib/darkmode-js/package-lock.json b/lib/darkmode-js/package-lock.json index a6688cec..3e3b5ce0 100644 --- a/lib/darkmode-js/package-lock.json +++ b/lib/darkmode-js/package-lock.json @@ -1 +1,9342 @@ -{"name":"darkmode-js","version":"1.5.6","lockfileVersion":1,"requires":true,"dependencies":{"@babel/cli":{"version":"7.1.5","resolved":"https://registry.npmjs.org/@babel/cli/-/cli-7.1.5.tgz","integrity":"sha512-zbO/DtTnaDappBflIU3zYEgATLToRDmW5uN/EGH1GXaes7ydfjqmAoK++xmJIA+8HfDw7UyPZNdM8fhGhfmMhw==","dev":true,"requires":{"chokidar":"^2.0.3","commander":"^2.8.1","convert-source-map":"^1.1.0","fs-readdir-recursive":"^1.1.0","glob":"^7.0.0","lodash":"^4.17.10","mkdirp":"^0.5.1","output-file-sync":"^2.0.0","slash":"^2.0.0","source-map":"^0.5.0"}},"@babel/code-frame":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz","integrity":"sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==","dev":true,"requires":{"@babel/highlight":"^7.0.0"}},"@babel/core":{"version":"7.1.6","resolved":"https://registry.npmjs.org/@babel/core/-/core-7.1.6.tgz","integrity":"sha512-Hz6PJT6e44iUNpAn8AoyAs6B3bl60g7MJQaI0rZEar6ECzh6+srYO1xlIdssio34mPaUtAb1y+XlkkSJzok3yw==","dev":true,"requires":{"@babel/code-frame":"^7.0.0","@babel/generator":"^7.1.6","@babel/helpers":"^7.1.5","@babel/parser":"^7.1.6","@babel/template":"^7.1.2","@babel/traverse":"^7.1.6","@babel/types":"^7.1.6","convert-source-map":"^1.1.0","debug":"^4.1.0","json5":"^2.1.0","lodash":"^4.17.10","resolve":"^1.3.2","semver":"^5.4.1","source-map":"^0.5.0"}},"@babel/generator":{"version":"7.1.6","resolved":"https://registry.npmjs.org/@babel/generator/-/generator-7.1.6.tgz","integrity":"sha512-brwPBtVvdYdGxtenbQgfCdDPmtkmUBZPjUoK5SXJEBuHaA5BCubh9ly65fzXz7R6o5rA76Rs22ES8Z+HCc0YIQ==","dev":true,"requires":{"@babel/types":"^7.1.6","jsesc":"^2.5.1","lodash":"^4.17.10","source-map":"^0.5.0","trim-right":"^1.0.1"}},"@babel/helper-annotate-as-pure":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz","integrity":"sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==","dev":true,"requires":{"@babel/types":"^7.0.0"}},"@babel/helper-builder-binary-assignment-operator-visitor":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz","integrity":"sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==","dev":true,"requires":{"@babel/helper-explode-assignable-expression":"^7.1.0","@babel/types":"^7.0.0"}},"@babel/helper-call-delegate":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz","integrity":"sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==","dev":true,"requires":{"@babel/helper-hoist-variables":"^7.0.0","@babel/traverse":"^7.1.0","@babel/types":"^7.0.0"}},"@babel/helper-define-map":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz","integrity":"sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==","dev":true,"requires":{"@babel/helper-function-name":"^7.1.0","@babel/types":"^7.0.0","lodash":"^4.17.10"}},"@babel/helper-explode-assignable-expression":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz","integrity":"sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==","dev":true,"requires":{"@babel/traverse":"^7.1.0","@babel/types":"^7.0.0"}},"@babel/helper-function-name":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz","integrity":"sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==","dev":true,"requires":{"@babel/helper-get-function-arity":"^7.0.0","@babel/template":"^7.1.0","@babel/types":"^7.0.0"}},"@babel/helper-get-function-arity":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz","integrity":"sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==","dev":true,"requires":{"@babel/types":"^7.0.0"}},"@babel/helper-hoist-variables":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz","integrity":"sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==","dev":true,"requires":{"@babel/types":"^7.0.0"}},"@babel/helper-member-expression-to-functions":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz","integrity":"sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==","dev":true,"requires":{"@babel/types":"^7.0.0"}},"@babel/helper-module-imports":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz","integrity":"sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==","dev":true,"requires":{"@babel/types":"^7.0.0"}},"@babel/helper-module-transforms":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz","integrity":"sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw==","dev":true,"requires":{"@babel/helper-module-imports":"^7.0.0","@babel/helper-simple-access":"^7.1.0","@babel/helper-split-export-declaration":"^7.0.0","@babel/template":"^7.1.0","@babel/types":"^7.0.0","lodash":"^4.17.10"}},"@babel/helper-optimise-call-expression":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz","integrity":"sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==","dev":true,"requires":{"@babel/types":"^7.0.0"}},"@babel/helper-plugin-utils":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz","integrity":"sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==","dev":true},"@babel/helper-regex":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz","integrity":"sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==","dev":true,"requires":{"lodash":"^4.17.10"}},"@babel/helper-remap-async-to-generator":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz","integrity":"sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==","dev":true,"requires":{"@babel/helper-annotate-as-pure":"^7.0.0","@babel/helper-wrap-function":"^7.1.0","@babel/template":"^7.1.0","@babel/traverse":"^7.1.0","@babel/types":"^7.0.0"}},"@babel/helper-replace-supers":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz","integrity":"sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ==","dev":true,"requires":{"@babel/helper-member-expression-to-functions":"^7.0.0","@babel/helper-optimise-call-expression":"^7.0.0","@babel/traverse":"^7.1.0","@babel/types":"^7.0.0"}},"@babel/helper-simple-access":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz","integrity":"sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==","dev":true,"requires":{"@babel/template":"^7.1.0","@babel/types":"^7.0.0"}},"@babel/helper-split-export-declaration":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz","integrity":"sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==","dev":true,"requires":{"@babel/types":"^7.0.0"}},"@babel/helper-wrap-function":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz","integrity":"sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA==","dev":true,"requires":{"@babel/helper-function-name":"^7.1.0","@babel/template":"^7.1.0","@babel/traverse":"^7.1.0","@babel/types":"^7.0.0"}},"@babel/helpers":{"version":"7.1.5","resolved":"https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.5.tgz","integrity":"sha512-2jkcdL02ywNBry1YNFAH/fViq4fXG0vdckHqeJk+75fpQ2OH+Az6076tX/M0835zA45E0Cqa6pV5Kiv9YOqjEg==","dev":true,"requires":{"@babel/template":"^7.1.2","@babel/traverse":"^7.1.5","@babel/types":"^7.1.5"}},"@babel/highlight":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz","integrity":"sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==","dev":true,"requires":{"chalk":"^2.0.0","esutils":"^2.0.2","js-tokens":"^4.0.0"}},"@babel/parser":{"version":"7.1.6","resolved":"https://registry.npmjs.org/@babel/parser/-/parser-7.1.6.tgz","integrity":"sha512-dWP6LJm9nKT6ALaa+bnL247GHHMWir3vSlZ2+IHgHgktZQx0L3Uvq2uAWcuzIe+fujRsYWBW2q622C5UvGK9iQ==","dev":true},"@babel/plugin-proposal-async-generator-functions":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz","integrity":"sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0","@babel/helper-remap-async-to-generator":"^7.1.0","@babel/plugin-syntax-async-generators":"^7.0.0"}},"@babel/plugin-proposal-json-strings":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz","integrity":"sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0","@babel/plugin-syntax-json-strings":"^7.0.0"}},"@babel/plugin-proposal-object-rest-spread":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz","integrity":"sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0","@babel/plugin-syntax-object-rest-spread":"^7.0.0"}},"@babel/plugin-proposal-optional-catch-binding":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0.tgz","integrity":"sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0","@babel/plugin-syntax-optional-catch-binding":"^7.0.0"}},"@babel/plugin-proposal-unicode-property-regex":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz","integrity":"sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0","@babel/helper-regex":"^7.0.0","regexpu-core":"^4.2.0"}},"@babel/plugin-syntax-async-generators":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0.tgz","integrity":"sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-syntax-json-strings":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz","integrity":"sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-syntax-object-rest-spread":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz","integrity":"sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-syntax-optional-catch-binding":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0.tgz","integrity":"sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-arrow-functions":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz","integrity":"sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-async-to-generator":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz","integrity":"sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g==","dev":true,"requires":{"@babel/helper-module-imports":"^7.0.0","@babel/helper-plugin-utils":"^7.0.0","@babel/helper-remap-async-to-generator":"^7.1.0"}},"@babel/plugin-transform-block-scoped-functions":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0.tgz","integrity":"sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-block-scoping":{"version":"7.1.5","resolved":"https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.1.5.tgz","integrity":"sha512-jlYcDrz+5ayWC7mxgpn1Wj8zj0mmjCT2w0mPIMSwO926eXBRxpEgoN/uQVRBfjtr8ayjcmS+xk2G1jaP8JjMJQ==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0","lodash":"^4.17.10"}},"@babel/plugin-transform-classes":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz","integrity":"sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==","dev":true,"requires":{"@babel/helper-annotate-as-pure":"^7.0.0","@babel/helper-define-map":"^7.1.0","@babel/helper-function-name":"^7.1.0","@babel/helper-optimise-call-expression":"^7.0.0","@babel/helper-plugin-utils":"^7.0.0","@babel/helper-replace-supers":"^7.1.0","@babel/helper-split-export-declaration":"^7.0.0","globals":"^11.1.0"}},"@babel/plugin-transform-computed-properties":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0.tgz","integrity":"sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-destructuring":{"version":"7.1.3","resolved":"https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.1.3.tgz","integrity":"sha512-Mb9M4DGIOspH1ExHOUnn2UUXFOyVTiX84fXCd+6B5iWrQg/QMeeRmSwpZ9lnjYLSXtZwiw80ytVMr3zue0ucYw==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-dotall-regex":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0.tgz","integrity":"sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0","@babel/helper-regex":"^7.0.0","regexpu-core":"^4.1.3"}},"@babel/plugin-transform-duplicate-keys":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0.tgz","integrity":"sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-exponentiation-operator":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.1.0.tgz","integrity":"sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ==","dev":true,"requires":{"@babel/helper-builder-binary-assignment-operator-visitor":"^7.1.0","@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-for-of":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz","integrity":"sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-function-name":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.1.0.tgz","integrity":"sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg==","dev":true,"requires":{"@babel/helper-function-name":"^7.1.0","@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-literals":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0.tgz","integrity":"sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-modules-amd":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.1.0.tgz","integrity":"sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A==","dev":true,"requires":{"@babel/helper-module-transforms":"^7.1.0","@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-modules-commonjs":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz","integrity":"sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA==","dev":true,"requires":{"@babel/helper-module-transforms":"^7.1.0","@babel/helper-plugin-utils":"^7.0.0","@babel/helper-simple-access":"^7.1.0"}},"@babel/plugin-transform-modules-systemjs":{"version":"7.1.3","resolved":"https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.1.3.tgz","integrity":"sha512-PvTxgjxQAq4pvVUZF3mD5gEtVDuId8NtWkJsZLEJZMZAW3TvgQl1pmydLLN1bM8huHFVVU43lf0uvjQj9FRkKw==","dev":true,"requires":{"@babel/helper-hoist-variables":"^7.0.0","@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-modules-umd":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.1.0.tgz","integrity":"sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig==","dev":true,"requires":{"@babel/helper-module-transforms":"^7.1.0","@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-new-target":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz","integrity":"sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-object-super":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.1.0.tgz","integrity":"sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0","@babel/helper-replace-supers":"^7.1.0"}},"@babel/plugin-transform-parameters":{"version":"7.1.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.1.0.tgz","integrity":"sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw==","dev":true,"requires":{"@babel/helper-call-delegate":"^7.1.0","@babel/helper-get-function-arity":"^7.0.0","@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-regenerator":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz","integrity":"sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==","dev":true,"requires":{"regenerator-transform":"^0.13.3"}},"@babel/plugin-transform-shorthand-properties":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz","integrity":"sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-spread":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0.tgz","integrity":"sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-sticky-regex":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0.tgz","integrity":"sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0","@babel/helper-regex":"^7.0.0"}},"@babel/plugin-transform-template-literals":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0.tgz","integrity":"sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg==","dev":true,"requires":{"@babel/helper-annotate-as-pure":"^7.0.0","@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-typeof-symbol":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0.tgz","integrity":"sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0"}},"@babel/plugin-transform-unicode-regex":{"version":"7.0.0","resolved":"https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz","integrity":"sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw==","dev":true,"requires":{"@babel/helper-plugin-utils":"^7.0.0","@babel/helper-regex":"^7.0.0","regexpu-core":"^4.1.3"}},"@babel/preset-env":{"version":"7.1.6","resolved":"https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.6.tgz","integrity":"sha512-YIBfpJNQMBkb6MCkjz/A9J76SNCSuGVamOVBgoUkLzpJD/z8ghHi9I42LQ4pulVX68N/MmImz6ZTixt7Azgexw==","dev":true,"requires":{"@babel/helper-module-imports":"^7.0.0","@babel/helper-plugin-utils":"^7.0.0","@babel/plugin-proposal-async-generator-functions":"^7.1.0","@babel/plugin-proposal-json-strings":"^7.0.0","@babel/plugin-proposal-object-rest-spread":"^7.0.0","@babel/plugin-proposal-optional-catch-binding":"^7.0.0","@babel/plugin-proposal-unicode-property-regex":"^7.0.0","@babel/plugin-syntax-async-generators":"^7.0.0","@babel/plugin-syntax-object-rest-spread":"^7.0.0","@babel/plugin-syntax-optional-catch-binding":"^7.0.0","@babel/plugin-transform-arrow-functions":"^7.0.0","@babel/plugin-transform-async-to-generator":"^7.1.0","@babel/plugin-transform-block-scoped-functions":"^7.0.0","@babel/plugin-transform-block-scoping":"^7.1.5","@babel/plugin-transform-classes":"^7.1.0","@babel/plugin-transform-computed-properties":"^7.0.0","@babel/plugin-transform-destructuring":"^7.0.0","@babel/plugin-transform-dotall-regex":"^7.0.0","@babel/plugin-transform-duplicate-keys":"^7.0.0","@babel/plugin-transform-exponentiation-operator":"^7.1.0","@babel/plugin-transform-for-of":"^7.0.0","@babel/plugin-transform-function-name":"^7.1.0","@babel/plugin-transform-literals":"^7.0.0","@babel/plugin-transform-modules-amd":"^7.1.0","@babel/plugin-transform-modules-commonjs":"^7.1.0","@babel/plugin-transform-modules-systemjs":"^7.0.0","@babel/plugin-transform-modules-umd":"^7.1.0","@babel/plugin-transform-new-target":"^7.0.0","@babel/plugin-transform-object-super":"^7.1.0","@babel/plugin-transform-parameters":"^7.1.0","@babel/plugin-transform-regenerator":"^7.0.0","@babel/plugin-transform-shorthand-properties":"^7.0.0","@babel/plugin-transform-spread":"^7.0.0","@babel/plugin-transform-sticky-regex":"^7.0.0","@babel/plugin-transform-template-literals":"^7.0.0","@babel/plugin-transform-typeof-symbol":"^7.0.0","@babel/plugin-transform-unicode-regex":"^7.0.0","browserslist":"^4.1.0","invariant":"^2.2.2","js-levenshtein":"^1.1.3","semver":"^5.3.0"}},"@babel/template":{"version":"7.1.2","resolved":"https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz","integrity":"sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag==","dev":true,"requires":{"@babel/code-frame":"^7.0.0","@babel/parser":"^7.1.2","@babel/types":"^7.1.2"}},"@babel/traverse":{"version":"7.1.6","resolved":"https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.6.tgz","integrity":"sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ==","dev":true,"requires":{"@babel/code-frame":"^7.0.0","@babel/generator":"^7.1.6","@babel/helper-function-name":"^7.1.0","@babel/helper-split-export-declaration":"^7.0.0","@babel/parser":"^7.1.6","@babel/types":"^7.1.6","debug":"^4.1.0","globals":"^11.1.0","lodash":"^4.17.10"}},"@babel/types":{"version":"7.1.6","resolved":"https://registry.npmjs.org/@babel/types/-/types-7.1.6.tgz","integrity":"sha512-DMiUzlY9DSjVsOylJssxLHSgj6tWM9PRFJOGW/RaOglVOK9nzTxoOMfTfRQXGUCUQ/HmlG2efwC+XqUEJ5ay4w==","dev":true,"requires":{"esutils":"^2.0.2","lodash":"^4.17.10","to-fast-properties":"^2.0.0"}},"@webassemblyjs/ast":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz","integrity":"sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA==","dev":true,"requires":{"@webassemblyjs/helper-module-context":"1.7.11","@webassemblyjs/helper-wasm-bytecode":"1.7.11","@webassemblyjs/wast-parser":"1.7.11"}},"@webassemblyjs/floating-point-hex-parser":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz","integrity":"sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg==","dev":true},"@webassemblyjs/helper-api-error":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz","integrity":"sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg==","dev":true},"@webassemblyjs/helper-buffer":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz","integrity":"sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w==","dev":true},"@webassemblyjs/helper-code-frame":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz","integrity":"sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw==","dev":true,"requires":{"@webassemblyjs/wast-printer":"1.7.11"}},"@webassemblyjs/helper-fsm":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz","integrity":"sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A==","dev":true},"@webassemblyjs/helper-module-context":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz","integrity":"sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg==","dev":true},"@webassemblyjs/helper-wasm-bytecode":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz","integrity":"sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ==","dev":true},"@webassemblyjs/helper-wasm-section":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz","integrity":"sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q==","dev":true,"requires":{"@webassemblyjs/ast":"1.7.11","@webassemblyjs/helper-buffer":"1.7.11","@webassemblyjs/helper-wasm-bytecode":"1.7.11","@webassemblyjs/wasm-gen":"1.7.11"}},"@webassemblyjs/ieee754":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz","integrity":"sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ==","dev":true,"requires":{"@xtuc/ieee754":"^1.2.0"}},"@webassemblyjs/leb128":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.7.11.tgz","integrity":"sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw==","dev":true,"requires":{"@xtuc/long":"4.2.1"}},"@webassemblyjs/utf8":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.7.11.tgz","integrity":"sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA==","dev":true},"@webassemblyjs/wasm-edit":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz","integrity":"sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg==","dev":true,"requires":{"@webassemblyjs/ast":"1.7.11","@webassemblyjs/helper-buffer":"1.7.11","@webassemblyjs/helper-wasm-bytecode":"1.7.11","@webassemblyjs/helper-wasm-section":"1.7.11","@webassemblyjs/wasm-gen":"1.7.11","@webassemblyjs/wasm-opt":"1.7.11","@webassemblyjs/wasm-parser":"1.7.11","@webassemblyjs/wast-printer":"1.7.11"}},"@webassemblyjs/wasm-gen":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz","integrity":"sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA==","dev":true,"requires":{"@webassemblyjs/ast":"1.7.11","@webassemblyjs/helper-wasm-bytecode":"1.7.11","@webassemblyjs/ieee754":"1.7.11","@webassemblyjs/leb128":"1.7.11","@webassemblyjs/utf8":"1.7.11"}},"@webassemblyjs/wasm-opt":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz","integrity":"sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg==","dev":true,"requires":{"@webassemblyjs/ast":"1.7.11","@webassemblyjs/helper-buffer":"1.7.11","@webassemblyjs/wasm-gen":"1.7.11","@webassemblyjs/wasm-parser":"1.7.11"}},"@webassemblyjs/wasm-parser":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz","integrity":"sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg==","dev":true,"requires":{"@webassemblyjs/ast":"1.7.11","@webassemblyjs/helper-api-error":"1.7.11","@webassemblyjs/helper-wasm-bytecode":"1.7.11","@webassemblyjs/ieee754":"1.7.11","@webassemblyjs/leb128":"1.7.11","@webassemblyjs/utf8":"1.7.11"}},"@webassemblyjs/wast-parser":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz","integrity":"sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ==","dev":true,"requires":{"@webassemblyjs/ast":"1.7.11","@webassemblyjs/floating-point-hex-parser":"1.7.11","@webassemblyjs/helper-api-error":"1.7.11","@webassemblyjs/helper-code-frame":"1.7.11","@webassemblyjs/helper-fsm":"1.7.11","@xtuc/long":"4.2.1"}},"@webassemblyjs/wast-printer":{"version":"1.7.11","resolved":"https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz","integrity":"sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg==","dev":true,"requires":{"@webassemblyjs/ast":"1.7.11","@webassemblyjs/wast-parser":"1.7.11","@xtuc/long":"4.2.1"}},"@xtuc/ieee754":{"version":"1.2.0","resolved":"https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz","integrity":"sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==","dev":true},"@xtuc/long":{"version":"4.2.1","resolved":"https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz","integrity":"sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==","dev":true},"abab":{"version":"1.0.4","resolved":"https://registry.npmjs.org/abab/-/abab-1.0.4.tgz","integrity":"sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=","dev":true},"acorn":{"version":"6.4.1","resolved":"https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz","integrity":"sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==","dev":true},"acorn-dynamic-import":{"version":"3.0.0","resolved":"https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz","integrity":"sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==","dev":true,"requires":{"acorn":"^5.0.0"},"dependencies":{"acorn":{"version":"5.7.4","resolved":"https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz","integrity":"sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==","dev":true}}},"acorn-globals":{"version":"4.3.0","resolved":"https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz","integrity":"sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==","dev":true,"requires":{"acorn":"^6.0.1","acorn-walk":"^6.0.1"}},"acorn-jsx":{"version":"5.0.1","resolved":"https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz","integrity":"sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==","dev":true},"acorn-walk":{"version":"6.1.1","resolved":"https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz","integrity":"sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==","dev":true},"ajv":{"version":"6.5.5","resolved":"https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz","integrity":"sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==","dev":true,"requires":{"fast-deep-equal":"^2.0.1","fast-json-stable-stringify":"^2.0.0","json-schema-traverse":"^0.4.1","uri-js":"^4.2.2"}},"ajv-errors":{"version":"1.0.0","resolved":"https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.0.tgz","integrity":"sha1-7PAh+hCP0X37Xms4Py3SM+Mf/Fk=","dev":true},"ajv-keywords":{"version":"3.2.0","resolved":"https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz","integrity":"sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=","dev":true},"ansi-escapes":{"version":"3.1.0","resolved":"http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz","integrity":"sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==","dev":true},"ansi-regex":{"version":"3.0.0","resolved":"https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz","integrity":"sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=","dev":true},"ansi-styles":{"version":"3.2.1","resolved":"https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz","integrity":"sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==","dev":true,"requires":{"color-convert":"^1.9.0"}},"anymatch":{"version":"2.0.0","resolved":"https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz","integrity":"sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==","dev":true,"requires":{"micromatch":"^3.1.4","normalize-path":"^2.1.1"}},"append-transform":{"version":"1.0.0","resolved":"https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz","integrity":"sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==","dev":true,"requires":{"default-require-extensions":"^2.0.0"}},"aproba":{"version":"1.2.0","resolved":"https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz","integrity":"sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==","dev":true},"archy":{"version":"1.0.0","resolved":"https://registry.npmjs.org/archy/-/archy-1.0.0.tgz","integrity":"sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=","dev":true},"argparse":{"version":"1.0.10","resolved":"https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz","integrity":"sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==","dev":true,"requires":{"sprintf-js":"~1.0.2"}},"arr-diff":{"version":"4.0.0","resolved":"https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz","integrity":"sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=","dev":true},"arr-flatten":{"version":"1.1.0","resolved":"https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz","integrity":"sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==","dev":true},"arr-union":{"version":"3.1.0","resolved":"https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz","integrity":"sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=","dev":true},"array-equal":{"version":"1.0.0","resolved":"http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz","integrity":"sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=","dev":true},"array-unique":{"version":"0.3.2","resolved":"https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz","integrity":"sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=","dev":true},"arrify":{"version":"1.0.1","resolved":"https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz","integrity":"sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=","dev":true},"asn1":{"version":"0.2.4","resolved":"https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz","integrity":"sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==","dev":true,"requires":{"safer-buffer":"~2.1.0"}},"asn1.js":{"version":"4.10.1","resolved":"https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz","integrity":"sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==","dev":true,"requires":{"bn.js":"^4.0.0","inherits":"^2.0.1","minimalistic-assert":"^1.0.0"}},"assert":{"version":"1.4.1","resolved":"https://registry.npmjs.org/assert/-/assert-1.4.1.tgz","integrity":"sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=","dev":true,"requires":{"util":"0.10.3"},"dependencies":{"inherits":{"version":"2.0.1","resolved":"https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz","integrity":"sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=","dev":true},"util":{"version":"0.10.3","resolved":"https://registry.npmjs.org/util/-/util-0.10.3.tgz","integrity":"sha1-evsa/lCAUkZInj23/g7TeTNqwPk=","dev":true,"requires":{"inherits":"2.0.1"}}}},"assert-plus":{"version":"1.0.0","resolved":"https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz","integrity":"sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=","dev":true},"assertion-error":{"version":"1.1.0","resolved":"https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz","integrity":"sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==","dev":true},"assign-symbols":{"version":"1.0.0","resolved":"https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz","integrity":"sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=","dev":true},"async":{"version":"1.5.2","resolved":"https://registry.npmjs.org/async/-/async-1.5.2.tgz","integrity":"sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=","dev":true},"async-each":{"version":"1.0.1","resolved":"https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz","integrity":"sha1-GdOGodntxufByF04iu28xW0zYC0=","dev":true},"async-limiter":{"version":"1.0.0","resolved":"https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz","integrity":"sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==","dev":true},"asynckit":{"version":"0.4.0","resolved":"https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz","integrity":"sha1-x57Zf380y48robyXkLzDZkdLS3k=","dev":true},"atob":{"version":"2.1.2","resolved":"https://registry.npmjs.org/atob/-/atob-2.1.2.tgz","integrity":"sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==","dev":true},"aws-sign2":{"version":"0.7.0","resolved":"https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz","integrity":"sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=","dev":true},"aws4":{"version":"1.8.0","resolved":"https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz","integrity":"sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==","dev":true},"babel-code-frame":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-7.0.0-beta.3.tgz","integrity":"sha512-flMsJ9eSpShupt2Gwpka84DoMePvE4HlDObzdEc+1iNkacv3+NHlsJ7dMKmbnVA/AT22UhcGEBHwbJLoXWBO6Q==","dev":true,"requires":{"chalk":"^2.0.0","esutils":"^2.0.2","js-tokens":"^3.0.0"},"dependencies":{"js-tokens":{"version":"3.0.2","resolved":"https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz","integrity":"sha1-mGbfOVECEw449/mWvOtlRDIJwls=","dev":true}}},"babel-core":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-beta.3.tgz","integrity":"sha512-zdng6WxI4cUjvstvFo/ke+hxohXCi/vxrMTM1S/bsAqnvKb+C+pHx78T3ZdJlWC3bGGxYqUnmM4p9VMzJ0uVVg==","dev":true,"requires":{"babel-code-frame":"7.0.0-beta.3","babel-generator":"7.0.0-beta.3","babel-helpers":"7.0.0-beta.3","babel-template":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3","babylon":"7.0.0-beta.27","convert-source-map":"^1.1.0","debug":"^3.0.1","json5":"^0.5.0","lodash":"^4.2.0","micromatch":"^2.3.11","resolve":"^1.3.2","source-map":"^0.5.0"},"dependencies":{"arr-diff":{"version":"2.0.0","resolved":"https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz","integrity":"sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=","dev":true,"requires":{"arr-flatten":"^1.0.1"}},"array-unique":{"version":"0.2.1","resolved":"https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz","integrity":"sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=","dev":true},"babylon":{"version":"7.0.0-beta.27","resolved":"https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.27.tgz","integrity":"sha512-ksRx+r8eFIfdt63MCgLc9VxGL7W3jcyveQvMpNMVHgW+eb9mq3Xbm45FLCNkw8h92RvoNp4uuiwzcCEwxjDBZg==","dev":true},"braces":{"version":"1.8.5","resolved":"https://registry.npmjs.org/braces/-/braces-1.8.5.tgz","integrity":"sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=","dev":true,"requires":{"expand-range":"^1.8.1","preserve":"^0.2.0","repeat-element":"^1.1.2"}},"debug":{"version":"3.2.6","resolved":"https://registry.npmjs.org/debug/-/debug-3.2.6.tgz","integrity":"sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==","dev":true,"requires":{"ms":"^2.1.1"}},"expand-brackets":{"version":"0.1.5","resolved":"https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz","integrity":"sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=","dev":true,"requires":{"is-posix-bracket":"^0.1.0"}},"extglob":{"version":"0.3.2","resolved":"https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz","integrity":"sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=","dev":true,"requires":{"is-extglob":"^1.0.0"}},"is-extglob":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz","integrity":"sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=","dev":true},"is-glob":{"version":"2.0.1","resolved":"https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz","integrity":"sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=","dev":true,"requires":{"is-extglob":"^1.0.0"}},"json5":{"version":"0.5.1","resolved":"https://registry.npmjs.org/json5/-/json5-0.5.1.tgz","integrity":"sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=","dev":true},"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}},"micromatch":{"version":"2.3.11","resolved":"https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz","integrity":"sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=","dev":true,"requires":{"arr-diff":"^2.0.0","array-unique":"^0.2.1","braces":"^1.8.2","expand-brackets":"^0.1.4","extglob":"^0.3.1","filename-regex":"^2.0.0","is-extglob":"^1.0.0","is-glob":"^2.0.1","kind-of":"^3.0.2","normalize-path":"^2.0.1","object.omit":"^2.0.0","parse-glob":"^3.0.4","regex-cache":"^0.4.2"}}}},"babel-eslint":{"version":"8.2.6","resolved":"https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz","integrity":"sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==","dev":true,"requires":{"@babel/code-frame":"7.0.0-beta.44","@babel/traverse":"7.0.0-beta.44","@babel/types":"7.0.0-beta.44","babylon":"7.0.0-beta.44","eslint-scope":"3.7.1","eslint-visitor-keys":"^1.0.0"},"dependencies":{"@babel/code-frame":{"version":"7.0.0-beta.44","resolved":"http://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz","integrity":"sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==","dev":true,"requires":{"@babel/highlight":"7.0.0-beta.44"}},"@babel/generator":{"version":"7.0.0-beta.44","resolved":"http://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz","integrity":"sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==","dev":true,"requires":{"@babel/types":"7.0.0-beta.44","jsesc":"^2.5.1","lodash":"^4.2.0","source-map":"^0.5.0","trim-right":"^1.0.1"}},"@babel/helper-function-name":{"version":"7.0.0-beta.44","resolved":"http://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz","integrity":"sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==","dev":true,"requires":{"@babel/helper-get-function-arity":"7.0.0-beta.44","@babel/template":"7.0.0-beta.44","@babel/types":"7.0.0-beta.44"}},"@babel/helper-get-function-arity":{"version":"7.0.0-beta.44","resolved":"http://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz","integrity":"sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==","dev":true,"requires":{"@babel/types":"7.0.0-beta.44"}},"@babel/helper-split-export-declaration":{"version":"7.0.0-beta.44","resolved":"http://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz","integrity":"sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==","dev":true,"requires":{"@babel/types":"7.0.0-beta.44"}},"@babel/highlight":{"version":"7.0.0-beta.44","resolved":"http://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz","integrity":"sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==","dev":true,"requires":{"chalk":"^2.0.0","esutils":"^2.0.2","js-tokens":"^3.0.0"}},"@babel/template":{"version":"7.0.0-beta.44","resolved":"http://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz","integrity":"sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==","dev":true,"requires":{"@babel/code-frame":"7.0.0-beta.44","@babel/types":"7.0.0-beta.44","babylon":"7.0.0-beta.44","lodash":"^4.2.0"}},"@babel/traverse":{"version":"7.0.0-beta.44","resolved":"http://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz","integrity":"sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==","dev":true,"requires":{"@babel/code-frame":"7.0.0-beta.44","@babel/generator":"7.0.0-beta.44","@babel/helper-function-name":"7.0.0-beta.44","@babel/helper-split-export-declaration":"7.0.0-beta.44","@babel/types":"7.0.0-beta.44","babylon":"7.0.0-beta.44","debug":"^3.1.0","globals":"^11.1.0","invariant":"^2.2.0","lodash":"^4.2.0"}},"@babel/types":{"version":"7.0.0-beta.44","resolved":"http://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz","integrity":"sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==","dev":true,"requires":{"esutils":"^2.0.2","lodash":"^4.2.0","to-fast-properties":"^2.0.0"}},"debug":{"version":"3.2.6","resolved":"https://registry.npmjs.org/debug/-/debug-3.2.6.tgz","integrity":"sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==","dev":true,"requires":{"ms":"^2.1.1"}},"js-tokens":{"version":"3.0.2","resolved":"https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz","integrity":"sha1-mGbfOVECEw449/mWvOtlRDIJwls=","dev":true}}},"babel-generator":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-generator/-/babel-generator-7.0.0-beta.3.tgz","integrity":"sha512-Bok77tKwQZUVaLBRnDGDEaMZ4xEeyvzsgnCRxlVgfKmgn+vPxuka//ug3nrMmmgZ8TAMVPoXzeaAcs47lExrPg==","dev":true,"requires":{"babel-types":"7.0.0-beta.3","jsesc":"^2.5.1","lodash":"^4.2.0","source-map":"^0.5.0","trim-right":"^1.0.1"}},"babel-helper-annotate-as-pure":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-annotate-as-pure/-/babel-helper-annotate-as-pure-7.0.0-beta.3.tgz","integrity":"sha512-C6uYc7RmuPDZmkwTaV/ya0BGuZJFyuU/mAyDDqSfyuUZavk04eKdEWxjaKRGd3UA/fpzLNKViYO4aQgY4TsxCQ==","dev":true,"requires":{"babel-types":"7.0.0-beta.3"}},"babel-helper-builder-binary-assignment-operator-visitor":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-7.0.0-beta.3.tgz","integrity":"sha512-faPNvJ2w/YLRN0pD3mX3Ro/Og+uBNMdwPXg2bq5xXERQCyuYWzAmVbKnjGNaI4CLPDEbAZiZpq+AlMO3cT0QQA==","dev":true,"requires":{"babel-helper-explode-assignable-expression":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-helper-call-delegate":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-7.0.0-beta.3.tgz","integrity":"sha512-omi9OEknlyt8LxZ46SRVMY/20EpwU2GMkXHcswcGNANNcaB3aiDcYQRAgtU0vrhjD/+fIGb9xl7+plpUnADKIw==","dev":true,"requires":{"babel-helper-hoist-variables":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-helper-define-map":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-7.0.0-beta.3.tgz","integrity":"sha512-F2DrZDfS4EIFi5HTK3eaL8ojJwM6jjEM26D/i7h1YAwlm6PytiOXlhcXNbOoSBv6767WesNWpLVDQoX68SjDrQ==","dev":true,"requires":{"babel-helper-function-name":"7.0.0-beta.3","babel-types":"7.0.0-beta.3","lodash":"^4.2.0"}},"babel-helper-explode-assignable-expression":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-7.0.0-beta.3.tgz","integrity":"sha512-MugrfM38GSj7+8I/yFYjQwOEPSGmCLsJFNrWz7KVH4HA5Ntim19cMmdMUWSls30rTeGYQpLECjHNFv+ITbA7wA==","dev":true,"requires":{"babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-helper-function-name":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-7.0.0-beta.3.tgz","integrity":"sha512-iMWYqwDarQOVlEGcK1MfbtK9vrFGs5Z4UQsdASJUHdhBp918EM5kndwriiIbhUX8gr2B/CEV/udJkFTrHsjdMQ==","dev":true,"requires":{"babel-helper-get-function-arity":"7.0.0-beta.3","babel-template":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-helper-get-function-arity":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-7.0.0-beta.3.tgz","integrity":"sha512-ZkYFRMWKx1c9fUW72YNM3eieBG701CMbLjmLLWmJTTPc0F0kddS9Fwok26EAmndUAgD6kFdh7ms3PH94MdGuGQ==","dev":true,"requires":{"babel-types":"7.0.0-beta.3"}},"babel-helper-hoist-variables":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-7.0.0-beta.3.tgz","integrity":"sha512-9XOLW0nN3154gYf0OrRpatRYpB5s5NkRAcFseGYn/sxf+450iURwq442O7USvg9dRl1WWBgH23fsQQ5+xjKsGw==","dev":true,"requires":{"babel-types":"7.0.0-beta.3"}},"babel-helper-module-imports":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-module-imports/-/babel-helper-module-imports-7.0.0-beta.3.tgz","integrity":"sha512-bdPrIXbUTYfREhRhjbN8SstwQaj0S4+rW4PKi1f2Wc5fizSh0hGYkfXUdiSSOgyTydm956tAyz4FrG61bqdQyw==","dev":true,"requires":{"babel-types":"7.0.0-beta.3","lodash":"^4.2.0"}},"babel-helper-module-transforms":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-module-transforms/-/babel-helper-module-transforms-7.0.0-beta.3.tgz","integrity":"sha512-mnCAqH2fpcYny6LMyCg/bMif/D8FxER/at9R3xNWvfAv2N5x5Yhai0g8tBQZuINqZkAxQ4Tl7x/8ImviwKBQSA==","dev":true,"requires":{"babel-helper-module-imports":"7.0.0-beta.3","babel-helper-simple-access":"7.0.0-beta.3","babel-template":"7.0.0-beta.3","babel-types":"7.0.0-beta.3","lodash":"^4.2.0"}},"babel-helper-optimise-call-expression":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-7.0.0-beta.3.tgz","integrity":"sha512-X614MCHT+to5dnH4uecU63VUmOs+4Hn8DfH6vT2090HHE9/swOuNFKpeNeI3hebt59eAYyoWb2iPGv7FTpIh3Q==","dev":true,"requires":{"babel-types":"7.0.0-beta.3"}},"babel-helper-regex":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-7.0.0-beta.3.tgz","integrity":"sha512-ZmM3LrVJec0WUzugRvEvoNkoGygkN7PGSB3ZS2XiACb39t2uQhFzaVuaucYTGupXNt3aZ71usE1vt55FlVEFqg==","dev":true,"requires":{"lodash":"^4.2.0"}},"babel-helper-remap-async-to-generator":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-7.0.0-beta.3.tgz","integrity":"sha512-zTuzSAn4FM7WlduV9o/GoY7iU1Rfm6WqO6edwZ3LwexnJ/eGEa/46DNUYSUA2ApvXjRX/J7Ox9TRJHv2U4xbhg==","dev":true,"requires":{"babel-helper-wrap-function":"7.0.0-beta.3","babel-template":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-helper-replace-supers":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-7.0.0-beta.3.tgz","integrity":"sha512-ZkTdE7XBDW0PUQkKTeax+m1JpZqzo9ze3zbqjRxyt+x328NeGLD3edmNCIxmFt86njxIo3AFfZ00PKd4g/7jqg==","dev":true,"requires":{"babel-helper-optimise-call-expression":"7.0.0-beta.3","babel-template":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-helper-simple-access":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-simple-access/-/babel-helper-simple-access-7.0.0-beta.3.tgz","integrity":"sha512-4gaS4Eej6+qY35EWuwtkDQ47oKTRIBmGEGMzTigyDVjRfNltAlhN8lZPhNsIcKxG3zJ/UTOhtx7j8dmn757PUw==","dev":true,"requires":{"babel-template":"7.0.0-beta.3","babel-types":"7.0.0-beta.3","lodash":"^4.2.0"}},"babel-helper-wrap-function":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helper-wrap-function/-/babel-helper-wrap-function-7.0.0-beta.3.tgz","integrity":"sha512-uje7ahcNwS0vn6/Uw+4zSycwOcasFIB/2ek5dMQ3K3OICsXPmeDn9cKaugot+q1TfsyN9wfU9qEAEIZvIllWNQ==","dev":true,"requires":{"babel-helper-function-name":"7.0.0-beta.3","babel-template":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-helpers":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-helpers/-/babel-helpers-7.0.0-beta.3.tgz","integrity":"sha512-zNX7FgdXT8645igxTyAVIArMbxUsFl1w3K+v+SKlGbDocIVjWMnRszRfgVwJflzI11yE0kY+fy6SNfulykW8CA==","dev":true,"requires":{"babel-template":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-loader":{"version":"8.0.4","resolved":"https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.4.tgz","integrity":"sha512-fhBhNkUToJcW9nV46v8w87AJOwAJDz84c1CL57n3Stj73FANM/b9TbCUK4YhdOwEyZ+OxhYpdeZDNzSI29Firw==","dev":true,"requires":{"find-cache-dir":"^1.0.0","loader-utils":"^1.0.2","mkdirp":"^0.5.1","util.promisify":"^1.0.0"}},"babel-plugin-add-module-exports":{"version":"0.2.1","resolved":"http://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz","integrity":"sha1-mumh9KjcZ/DN7E9K7aHkOl/2XiU=","dev":true},"babel-plugin-check-es2015-constants":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-7.0.0-beta.3.tgz","integrity":"sha512-cosavMPmT+fz17Bugk2sK60k/U+AkniFntFWx09aOkidkRSL9gRAJaE7zg6A8J6uBbWDi7XKdm+47T9iia5KYw==","dev":true},"babel-plugin-istanbul":{"version":"5.1.0","resolved":"https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.0.tgz","integrity":"sha512-CLoXPRSUWiR8yao8bShqZUIC6qLfZVVY3X1wj+QPNXu0wfmrRRfarh1LYy+dYMVI+bDj0ghy3tuqFFRFZmL1Nw==","dev":true,"requires":{"find-up":"^3.0.0","istanbul-lib-instrument":"^3.0.0","test-exclude":"^5.0.0"},"dependencies":{"find-up":{"version":"3.0.0","resolved":"https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz","integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"locate-path":{"version":"3.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz","integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"p-limit":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz","integrity":"sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz","integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz","integrity":"sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==","dev":true}}},"babel-plugin-syntax-async-functions":{"version":"7.0.0-beta.0","resolved":"https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-7.0.0-beta.0.tgz","integrity":"sha512-IKh5AA3LKrqluJVc3xVE0i4zD7OIW1Iyua4uZQ3PCwey5lv/pM668eYhIEQT3fj8SmdP3cXVquvKQ0IdMVgQxg==","dev":true},"babel-plugin-syntax-async-generators":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-7.0.0-beta.3.tgz","integrity":"sha512-isPmqPGxMKOoXF+bzIlA+MjwhbLRhLrqc2mA/7HWFuu7fGtTWG9XGlFVd9aR7pTkGMh+cVcFsUCLhvEaojC9xA==","dev":true},"babel-plugin-syntax-exponentiation-operator":{"version":"7.0.0-beta.0","resolved":"https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-7.0.0-beta.0.tgz","integrity":"sha512-qFH1aInJPJefgefIXekOtNkzyjlfC2TOIp+O27ya0jFhtuUAqfAmEgVTIjYSi0E5mCpT70IeCZ6J0Rz62F+uog==","dev":true},"babel-plugin-syntax-object-rest-spread":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-7.0.0-beta.3.tgz","integrity":"sha512-21/MnmUFduLr4JzxrKMm/MeF+Jjyi5UdZo38IqzrP0sLhmPbal5ZAUJ4HgWH4339SdjnYgENacbY5wfk/zxTGg==","dev":true},"babel-plugin-syntax-optional-catch-binding":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-syntax-optional-catch-binding/-/babel-plugin-syntax-optional-catch-binding-7.0.0-beta.3.tgz","integrity":"sha512-IDrRx+htXqZO0IvQ0Heru01LDfDvC2lIFeM19pVS0EHVLy4Bpj5Sg0o7joOjj1j8ewzgSJLC1FOXqj7zXVedkg==","dev":true},"babel-plugin-syntax-trailing-function-commas":{"version":"7.0.0-beta.0","resolved":"https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz","integrity":"sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==","dev":true},"babel-plugin-transform-async-generator-functions":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-7.0.0-beta.3.tgz","integrity":"sha512-sIVkKihVjq930ONro7sMo080kyIznrEDdMmq4JX1OYtDVV9OiiUF/yrHnc2tBrldOzTYyD3iPeIskTDuRVAnfA==","dev":true,"requires":{"babel-helper-remap-async-to-generator":"7.0.0-beta.3","babel-plugin-syntax-async-generators":"7.0.0-beta.3"}},"babel-plugin-transform-async-to-generator":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-7.0.0-beta.3.tgz","integrity":"sha512-LDOTVxH72pFNl9l9KQic0Pi0owwxvolcTg9IbA5QzdLo49Y9oe5GwYQxqHNGbVDOlm62iJ8cYbRA2+gLJpAzwQ==","dev":true,"requires":{"babel-helper-remap-async-to-generator":"7.0.0-beta.3","babel-plugin-syntax-async-functions":"7.0.0-beta.0"}},"babel-plugin-transform-es2015-arrow-functions":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-7.0.0-beta.3.tgz","integrity":"sha512-zrdLNzy22R6hzRrlSTPJWmN6N0Z11S0GPHE6R8SpSeAN4p9REgOOmNgfdHn5Nw3hDxWyvrPnBXdYug9HpBt8Yg==","dev":true},"babel-plugin-transform-es2015-block-scoped-functions":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-7.0.0-beta.3.tgz","integrity":"sha512-IzUjWeIa5670asiCA/xsyuH5lQYdsTJf3+yYssp/7/4KkUX7yWhP+L+VAihBGK9QtoyHE7dopIbRo/In07VWcQ==","dev":true},"babel-plugin-transform-es2015-block-scoping":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-7.0.0-beta.3.tgz","integrity":"sha512-Jm4ozOLdFkZpMCXhJLQ0y/+Nh920jV0b5ORrKhSu1jW3uaokhINi6tCLgJrQ/CwKPbVHlra+JwPVN+pITJjE7w==","dev":true,"requires":{"babel-template":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3","lodash":"^4.2.0"}},"babel-plugin-transform-es2015-classes":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-7.0.0-beta.3.tgz","integrity":"sha512-4vH3pzhx3oZ6rphe3EDCkxFfMsWlJoEMSk8pIHnfXm4dOL+goij5mrxqoTAh7W/DcMzpakZOdKkgsgg+iujg8Q==","dev":true,"requires":{"babel-helper-annotate-as-pure":"7.0.0-beta.3","babel-helper-define-map":"7.0.0-beta.3","babel-helper-function-name":"7.0.0-beta.3","babel-helper-optimise-call-expression":"7.0.0-beta.3","babel-helper-replace-supers":"7.0.0-beta.3","babel-template":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-computed-properties":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-7.0.0-beta.3.tgz","integrity":"sha512-HazW3EWODEav1LRA+FBPq3Oefpg0UOBN7yS1xV8HxNLwlWneg6g0dNnS2piVj8GJUk1N/wYa4SiMO0pOcgOcAA==","dev":true,"requires":{"babel-template":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-destructuring":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-7.0.0-beta.3.tgz","integrity":"sha512-BDjEuIS7SCI7mGEO8lfvo4f3UAVLwZYjHwt1WqRNklc1Y0mcY0/UZzM3NHoa+eBxkNPl5XApwyha/rxW3XyLUQ==","dev":true},"babel-plugin-transform-es2015-duplicate-keys":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-7.0.0-beta.3.tgz","integrity":"sha512-JLLlw+1XnYrgnVSMS56QN4idRyZJWBREQf0HmaaJQEw3Em+TwO84Tvjgvv7GBxCbXvX4wY+Teuncs2tJd6yqjg==","dev":true,"requires":{"babel-types":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-for-of":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-7.0.0-beta.3.tgz","integrity":"sha512-eaJ5ClU6XF9na+Fcle4sYfYEQtqBMy0CFg6H1dJbtmnWAkzYz4wnwR1unUe0vz5RPp5lA43ECWTTZE+1aH+e3A==","dev":true},"babel-plugin-transform-es2015-function-name":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-7.0.0-beta.3.tgz","integrity":"sha512-ioqyK/Y9/OlJ5L0pqYS9RosFh6PaIGFjT/zJdkoUKJgeK+H3ulEJ/YxqgLlSA0wuhPca0ztLD3xBEk5NR9Hwzw==","dev":true,"requires":{"babel-helper-function-name":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-literals":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-7.0.0-beta.3.tgz","integrity":"sha512-Zc+kpYJymHtHom+uw+NoNnnyPbxcbyFgeceMFVApavd49JtfdIj7pZS/XpRlxffjIAHSF2D/xDt+bRhq8zk69Q==","dev":true},"babel-plugin-transform-es2015-modules-amd":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-7.0.0-beta.3.tgz","integrity":"sha512-Fm1mLWiaDy4457O880czMMpu4IiYOdjr1Hy8gz39BvV722QPo5Y2mITo6vO4oNYtaBIc3L0XlwBWavXEDe8iRA==","dev":true,"requires":{"babel-helper-module-transforms":"7.0.0-beta.3","babel-template":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-modules-commonjs":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-7.0.0-beta.3.tgz","integrity":"sha512-RcRIKOAerrm2M5+w8ITVoadLynjU4inaw+VtZwq1G10VBNn2bbik7hfXWdgnTUdHE8h3TGAafHX9Iw0Zxxuhrg==","dev":true,"requires":{"babel-helper-module-transforms":"7.0.0-beta.3","babel-helper-simple-access":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-modules-systemjs":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-7.0.0-beta.3.tgz","integrity":"sha512-i621ym8MDfuG3gmgq22uS6JLj+bIJl0mMsZDI/s3457aAPKDl5HwyWGjxcVZHw6WpSKGf4ulqvospsgXOMQ4bA==","dev":true,"requires":{"babel-helper-hoist-variables":"7.0.0-beta.3","babel-template":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-modules-umd":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-7.0.0-beta.3.tgz","integrity":"sha512-sBn8Dtg2r8QCRmm8pT9kpNSn0qnOorN+gYy45gUwf9NBt6oGftncuecMlj1Mo3NCyRqHQ1WnwHLX4C3yDB5LPg==","dev":true,"requires":{"babel-helper-module-transforms":"7.0.0-beta.3","babel-template":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-object-super":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-7.0.0-beta.3.tgz","integrity":"sha512-yNMxez22uwWZ17nKH+PbZl4sIq7VCqjbOXF8B7pItq2cGRDH2wTbdpRCkWWfIJyxoXR9JYftSj4g95Ev+ris5g==","dev":true,"requires":{"babel-helper-replace-supers":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-parameters":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-7.0.0-beta.3.tgz","integrity":"sha512-0LdLhxyhIZz5y+1jfRSM7uBen5dCIft3KWwLbr/Wy3Amz9V4Mnfn1mr25BIBDL/RTNYpZGrJ2DWan7KD7DoHEA==","dev":true,"requires":{"babel-helper-call-delegate":"7.0.0-beta.3","babel-helper-get-function-arity":"7.0.0-beta.3","babel-template":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-shorthand-properties":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-7.0.0-beta.3.tgz","integrity":"sha512-PuyQlEurcTfp7pCf3qLEeaDUNJdnxWJ70DjjNQbSW7Q4U2oLYnXrgNcnNfyUumdwMkJQnA6xI20plRT42AEmVw==","dev":true,"requires":{"babel-types":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-spread":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-7.0.0-beta.3.tgz","integrity":"sha512-D6fi9kAvi+IMcdeOUxgJUFSRlfo0iG2Bn1ZiB43xbtgVgKrA/rerWwQxGuUHhp0lN5lbRSCEpV6tMx+vrYsp1w==","dev":true},"babel-plugin-transform-es2015-sticky-regex":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-7.0.0-beta.3.tgz","integrity":"sha512-ccZeHcyA0rs2L2OPbACECpHoYJa3nxLcAlNfabGfM/l8mPaZ+C/YDJMLRcGP/37eC3pTA+G9+jPK7i5wT/6QaA==","dev":true,"requires":{"babel-helper-regex":"7.0.0-beta.3","babel-types":"7.0.0-beta.3"}},"babel-plugin-transform-es2015-template-literals":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-7.0.0-beta.3.tgz","integrity":"sha512-7W++eDsz4JNm+V2T/KNfYXD5fjtUv4n1aqR1zl1jVoA7lbRWp3Y0ipWJqNHKhJg8Q5B9U/FOTPxJOBtHRp+HBQ==","dev":true},"babel-plugin-transform-es2015-typeof-symbol":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-7.0.0-beta.3.tgz","integrity":"sha512-tR3r8pdT4mW1lOMyoHDGbwp3wNlY1ks1K/fI0G/nZeZLQcRZm+XQEf8ia0DC17eUFCmrduJw/AyqC7Z6sCZb1A==","dev":true},"babel-plugin-transform-es2015-unicode-regex":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-7.0.0-beta.3.tgz","integrity":"sha512-Yov86wC/0ZcBEXzeFONacrDIkX/7cXQ/lJjH0ajP5scYOFzBji8DGAGW7mRn/OeY3c+/MBGkTNQhA+ojJsiFhA==","dev":true,"requires":{"babel-helper-regex":"7.0.0-beta.3","regexpu-core":"^4.1.3"}},"babel-plugin-transform-exponentiation-operator":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-7.0.0-beta.3.tgz","integrity":"sha512-5RaRPN5I+vyL6gyxriauB8wOncBUmDJbcUUGy0V8agBrnakCG5Fr2uiLuVPzKXAoac7CS3dtmTv+vObyvcxAMg==","dev":true,"requires":{"babel-helper-builder-binary-assignment-operator-visitor":"7.0.0-beta.3","babel-plugin-syntax-exponentiation-operator":"7.0.0-beta.0"}},"babel-plugin-transform-new-target":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-new-target/-/babel-plugin-transform-new-target-7.0.0-beta.3.tgz","integrity":"sha512-zoezg2Z3OIIwtk1PrVpn6zLNgw3/Kff2ZMWLWMDkPGHS0s7f2Gy2HCC8DZqITFUDGujOOopEE2acqKi8P7wx0g==","dev":true},"babel-plugin-transform-object-rest-spread":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-7.0.0-beta.3.tgz","integrity":"sha512-NOlhrq1CmxyuI94vNsqMhRPMuL5VG2EKUOIJQ0bwNiXBiwWRLdPoWyPT+Irrx5g4g0PkFgA46tnRj7Dc4ZGsxg==","dev":true,"requires":{"babel-plugin-syntax-object-rest-spread":"7.0.0-beta.3"}},"babel-plugin-transform-optional-catch-binding":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-optional-catch-binding/-/babel-plugin-transform-optional-catch-binding-7.0.0-beta.3.tgz","integrity":"sha512-Gx4L2A1rXCboKxqdrwXq8HKU/e1xJkBYZJZ2b7ISE0KOp4CNQeX1+1MSWjC3e0habFIMRAATJ3UiKmqty3oOzA==","dev":true,"requires":{"babel-plugin-syntax-optional-catch-binding":"7.0.0-beta.3"}},"babel-plugin-transform-regenerator":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-7.0.0-beta.3.tgz","integrity":"sha512-25qxAISuEL+MtISK0cShFQ3T8MUh3rbWAVqqFORTezcxBaxr28SNQR75ZdwkiNINEDZ/r7klLcxjNDQgJ67+MA==","dev":true,"requires":{"regenerator-transform":"^0.11.0"},"dependencies":{"regenerator-transform":{"version":"0.11.1","resolved":"https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.11.1.tgz","integrity":"sha512-q8SAPMEyARQHzyXNWNrlz5oNnI6k4yo8ncEcvH1aXjUCqyVQ7TeV/AttqBLcySCReXVk/+fUydo/RaEIAOnRfA==","dev":true,"requires":{"babel-types":"7.0.0-beta.3","private":"^0.1.6"}}}},"babel-plugin-transform-unicode-property-regex":{"version":"2.0.5","resolved":"https://registry.npmjs.org/babel-plugin-transform-unicode-property-regex/-/babel-plugin-transform-unicode-property-regex-2.0.5.tgz","integrity":"sha512-Q3L4R7tGc5z7FIGNt9TqzIChsiMK3xn+4qkmluQtnWyUSwQyzzYmXKDOdOHVaCRAM/fDnZsG+TT5GxaVGACxiQ==","dev":true,"requires":{"babel-helper-regex":"^6.26.0","regexpu-core":"^4.1.3"},"dependencies":{"babel-helper-regex":{"version":"6.26.0","resolved":"https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz","integrity":"sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=","dev":true,"requires":{"babel-runtime":"^6.26.0","babel-types":"^6.26.0","lodash":"^4.17.4"}},"babel-types":{"version":"6.26.0","resolved":"https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz","integrity":"sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=","dev":true,"requires":{"babel-runtime":"^6.26.0","esutils":"^2.0.2","lodash":"^4.17.4","to-fast-properties":"^1.0.3"}},"to-fast-properties":{"version":"1.0.3","resolved":"https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz","integrity":"sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=","dev":true}}},"babel-preset-env":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-7.0.0-beta.3.tgz","integrity":"sha512-i7XlRdAxUyPeeaGzf2RxkHODE/N646ydnZ7sQe54rTlUjIdg7wEE/5t40Gf/by3er8fg3kEr8YBJo0f+A3v9qA==","dev":true,"requires":{"babel-plugin-check-es2015-constants":"7.0.0-beta.3","babel-plugin-syntax-async-generators":"7.0.0-beta.3","babel-plugin-syntax-object-rest-spread":"7.0.0-beta.3","babel-plugin-syntax-optional-catch-binding":"7.0.0-beta.3","babel-plugin-syntax-trailing-function-commas":"7.0.0-beta.0","babel-plugin-transform-async-generator-functions":"7.0.0-beta.3","babel-plugin-transform-async-to-generator":"7.0.0-beta.3","babel-plugin-transform-es2015-arrow-functions":"7.0.0-beta.3","babel-plugin-transform-es2015-block-scoped-functions":"7.0.0-beta.3","babel-plugin-transform-es2015-block-scoping":"7.0.0-beta.3","babel-plugin-transform-es2015-classes":"7.0.0-beta.3","babel-plugin-transform-es2015-computed-properties":"7.0.0-beta.3","babel-plugin-transform-es2015-destructuring":"7.0.0-beta.3","babel-plugin-transform-es2015-duplicate-keys":"7.0.0-beta.3","babel-plugin-transform-es2015-for-of":"7.0.0-beta.3","babel-plugin-transform-es2015-function-name":"7.0.0-beta.3","babel-plugin-transform-es2015-literals":"7.0.0-beta.3","babel-plugin-transform-es2015-modules-amd":"7.0.0-beta.3","babel-plugin-transform-es2015-modules-commonjs":"7.0.0-beta.3","babel-plugin-transform-es2015-modules-systemjs":"7.0.0-beta.3","babel-plugin-transform-es2015-modules-umd":"7.0.0-beta.3","babel-plugin-transform-es2015-object-super":"7.0.0-beta.3","babel-plugin-transform-es2015-parameters":"7.0.0-beta.3","babel-plugin-transform-es2015-shorthand-properties":"7.0.0-beta.3","babel-plugin-transform-es2015-spread":"7.0.0-beta.3","babel-plugin-transform-es2015-sticky-regex":"7.0.0-beta.3","babel-plugin-transform-es2015-template-literals":"7.0.0-beta.3","babel-plugin-transform-es2015-typeof-symbol":"7.0.0-beta.3","babel-plugin-transform-es2015-unicode-regex":"7.0.0-beta.3","babel-plugin-transform-exponentiation-operator":"7.0.0-beta.3","babel-plugin-transform-new-target":"7.0.0-beta.3","babel-plugin-transform-object-rest-spread":"7.0.0-beta.3","babel-plugin-transform-optional-catch-binding":"7.0.0-beta.3","babel-plugin-transform-regenerator":"7.0.0-beta.3","babel-plugin-transform-unicode-property-regex":"^2.0.5","browserslist":"^2.4.0","invariant":"^2.2.2","semver":"^5.3.0"},"dependencies":{"browserslist":{"version":"2.11.3","resolved":"https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz","integrity":"sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==","dev":true,"requires":{"caniuse-lite":"^1.0.30000792","electron-to-chromium":"^1.3.30"}}}},"babel-register":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-register/-/babel-register-7.0.0-beta.3.tgz","integrity":"sha512-9H/TMXFuG7iDGEs/wakN9lFLmfpqNGg8YHzZ5Tah5UER7veLIPEspAwxKsGNA/4+X4z30tyBNoBhW6JkC9AKFQ==","dev":true,"requires":{"babel-core":"7.0.0-beta.3","core-js":"^2.4.0","find-cache-dir":"^1.0.0","home-or-tmp":"^3.0.0","lodash":"^4.2.0","mkdirp":"^0.5.1","pirates":"^3.0.1","source-map-support":"^0.4.2"}},"babel-runtime":{"version":"6.26.0","resolved":"https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz","integrity":"sha1-llxwWGaOgrVde/4E/yM3vItWR/4=","dev":true,"requires":{"core-js":"^2.4.0","regenerator-runtime":"^0.11.0"}},"babel-template":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-template/-/babel-template-7.0.0-beta.3.tgz","integrity":"sha512-urJduLja89kSDGqY8ryw8iIwQnMl30IvhMtMNmDD7vBX0l0oylaLgK+7df/9ODX9vR/PhXuif6HYl5HlzAKXMg==","dev":true,"requires":{"babel-code-frame":"7.0.0-beta.3","babel-traverse":"7.0.0-beta.3","babel-types":"7.0.0-beta.3","babylon":"7.0.0-beta.27","lodash":"^4.2.0"},"dependencies":{"babylon":{"version":"7.0.0-beta.27","resolved":"https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.27.tgz","integrity":"sha512-ksRx+r8eFIfdt63MCgLc9VxGL7W3jcyveQvMpNMVHgW+eb9mq3Xbm45FLCNkw8h92RvoNp4uuiwzcCEwxjDBZg==","dev":true}}},"babel-traverse":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-traverse/-/babel-traverse-7.0.0-beta.3.tgz","integrity":"sha512-xyh/aPYuedMAfQlSj2kjHjsEmY5/Dpxs576L05DySAVMrV+ADX6l4mTOLysAEGwJfkePJlDLhFuS6SKaxv1V7w==","dev":true,"requires":{"babel-code-frame":"7.0.0-beta.3","babel-helper-function-name":"7.0.0-beta.3","babel-types":"7.0.0-beta.3","babylon":"7.0.0-beta.27","debug":"^3.0.1","globals":"^10.0.0","invariant":"^2.2.0","lodash":"^4.2.0"},"dependencies":{"babylon":{"version":"7.0.0-beta.27","resolved":"https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.27.tgz","integrity":"sha512-ksRx+r8eFIfdt63MCgLc9VxGL7W3jcyveQvMpNMVHgW+eb9mq3Xbm45FLCNkw8h92RvoNp4uuiwzcCEwxjDBZg==","dev":true},"debug":{"version":"3.2.6","resolved":"https://registry.npmjs.org/debug/-/debug-3.2.6.tgz","integrity":"sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==","dev":true,"requires":{"ms":"^2.1.1"}},"globals":{"version":"10.4.0","resolved":"https://registry.npmjs.org/globals/-/globals-10.4.0.tgz","integrity":"sha512-uNUtxIZpGyuaq+5BqGGQHsL4wUlJAXRqOm6g3Y48/CWNGTLONgBibI0lh6lGxjR2HljFYUfszb+mk4WkgMntsA==","dev":true}}},"babel-types":{"version":"7.0.0-beta.3","resolved":"https://registry.npmjs.org/babel-types/-/babel-types-7.0.0-beta.3.tgz","integrity":"sha512-36k8J+byAe181OmCMawGhw+DtKO7AwexPVtsPXoMfAkjtZgoCX3bEuHWfdE5sYxRM8dojvtG/+O08M0Z/YDC6w==","dev":true,"requires":{"esutils":"^2.0.2","lodash":"^4.2.0","to-fast-properties":"^2.0.0"}},"babylon":{"version":"7.0.0-beta.44","resolved":"https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz","integrity":"sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==","dev":true},"balanced-match":{"version":"1.0.0","resolved":"https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz","integrity":"sha1-ibTRmasr7kneFk6gK4nORi1xt2c=","dev":true},"base":{"version":"0.11.2","resolved":"https://registry.npmjs.org/base/-/base-0.11.2.tgz","integrity":"sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==","dev":true,"requires":{"cache-base":"^1.0.1","class-utils":"^0.3.5","component-emitter":"^1.2.1","define-property":"^1.0.0","isobject":"^3.0.1","mixin-deep":"^1.2.0","pascalcase":"^0.1.1"},"dependencies":{"define-property":{"version":"1.0.0","resolved":"https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz","integrity":"sha1-dp66rz9KY6rTr56NMEybvnm/sOY=","dev":true,"requires":{"is-descriptor":"^1.0.0"}},"is-accessor-descriptor":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz","integrity":"sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==","dev":true,"requires":{"kind-of":"^6.0.0"}},"is-data-descriptor":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz","integrity":"sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==","dev":true,"requires":{"kind-of":"^6.0.0"}},"is-descriptor":{"version":"1.0.2","resolved":"https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz","integrity":"sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==","dev":true,"requires":{"is-accessor-descriptor":"^1.0.0","is-data-descriptor":"^1.0.0","kind-of":"^6.0.2"}}}},"base64-js":{"version":"1.3.0","resolved":"https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz","integrity":"sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==","dev":true},"bcrypt-pbkdf":{"version":"1.0.2","resolved":"https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz","integrity":"sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=","dev":true,"requires":{"tweetnacl":"^0.14.3"}},"big.js":{"version":"3.2.0","resolved":"https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz","integrity":"sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==","dev":true},"binary-extensions":{"version":"1.12.0","resolved":"https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz","integrity":"sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==","dev":true},"bluebird":{"version":"3.5.3","resolved":"https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz","integrity":"sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==","dev":true},"bn.js":{"version":"4.11.8","resolved":"https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz","integrity":"sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==","dev":true},"brace-expansion":{"version":"1.1.11","resolved":"https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz","integrity":"sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==","dev":true,"requires":{"balanced-match":"^1.0.0","concat-map":"0.0.1"}},"braces":{"version":"2.3.2","resolved":"https://registry.npmjs.org/braces/-/braces-2.3.2.tgz","integrity":"sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==","dev":true,"requires":{"arr-flatten":"^1.1.0","array-unique":"^0.3.2","extend-shallow":"^2.0.1","fill-range":"^4.0.0","isobject":"^3.0.1","repeat-element":"^1.1.2","snapdragon":"^0.8.1","snapdragon-node":"^2.0.1","split-string":"^3.0.2","to-regex":"^3.0.1"},"dependencies":{"extend-shallow":{"version":"2.0.1","resolved":"https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz","integrity":"sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=","dev":true,"requires":{"is-extendable":"^0.1.0"}}}},"brorand":{"version":"1.1.0","resolved":"https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz","integrity":"sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=","dev":true},"browser-process-hrtime":{"version":"0.1.3","resolved":"https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz","integrity":"sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==","dev":true},"browser-stdout":{"version":"1.3.0","resolved":"https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz","integrity":"sha1-81HTKWnTL6XXpVZxVCY9korjvR8=","dev":true},"browserify-aes":{"version":"1.2.0","resolved":"http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz","integrity":"sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==","dev":true,"requires":{"buffer-xor":"^1.0.3","cipher-base":"^1.0.0","create-hash":"^1.1.0","evp_bytestokey":"^1.0.3","inherits":"^2.0.1","safe-buffer":"^5.0.1"}},"browserify-cipher":{"version":"1.0.1","resolved":"https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz","integrity":"sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==","dev":true,"requires":{"browserify-aes":"^1.0.4","browserify-des":"^1.0.0","evp_bytestokey":"^1.0.0"}},"browserify-des":{"version":"1.0.2","resolved":"https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz","integrity":"sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==","dev":true,"requires":{"cipher-base":"^1.0.1","des.js":"^1.0.0","inherits":"^2.0.1","safe-buffer":"^5.1.2"}},"browserify-rsa":{"version":"4.0.1","resolved":"http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz","integrity":"sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=","dev":true,"requires":{"bn.js":"^4.1.0","randombytes":"^2.0.1"}},"browserify-sign":{"version":"4.0.4","resolved":"https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz","integrity":"sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=","dev":true,"requires":{"bn.js":"^4.1.1","browserify-rsa":"^4.0.0","create-hash":"^1.1.0","create-hmac":"^1.1.2","elliptic":"^6.0.0","inherits":"^2.0.1","parse-asn1":"^5.0.0"}},"browserify-zlib":{"version":"0.2.0","resolved":"https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz","integrity":"sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==","dev":true,"requires":{"pako":"~1.0.5"}},"browserslist":{"version":"4.3.4","resolved":"https://registry.npmjs.org/browserslist/-/browserslist-4.3.4.tgz","integrity":"sha512-u5iz+ijIMUlmV8blX82VGFrB9ecnUg5qEt55CMZ/YJEhha+d8qpBfOFuutJ6F/VKRXjZoD33b6uvarpPxcl3RA==","dev":true,"requires":{"caniuse-lite":"^1.0.30000899","electron-to-chromium":"^1.3.82","node-releases":"^1.0.1"}},"buffer":{"version":"4.9.1","resolved":"http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz","integrity":"sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=","dev":true,"requires":{"base64-js":"^1.0.2","ieee754":"^1.1.4","isarray":"^1.0.0"}},"buffer-from":{"version":"1.1.1","resolved":"https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz","integrity":"sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==","dev":true},"buffer-xor":{"version":"1.0.3","resolved":"https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz","integrity":"sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=","dev":true},"builtin-modules":{"version":"1.1.1","resolved":"https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz","integrity":"sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=","dev":true},"builtin-status-codes":{"version":"3.0.0","resolved":"https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz","integrity":"sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=","dev":true},"cacache":{"version":"10.0.4","resolved":"https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz","integrity":"sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==","dev":true,"requires":{"bluebird":"^3.5.1","chownr":"^1.0.1","glob":"^7.1.2","graceful-fs":"^4.1.11","lru-cache":"^4.1.1","mississippi":"^2.0.0","mkdirp":"^0.5.1","move-concurrently":"^1.0.1","promise-inflight":"^1.0.1","rimraf":"^2.6.2","ssri":"^5.2.4","unique-filename":"^1.1.0","y18n":"^4.0.0"}},"cache-base":{"version":"1.0.1","resolved":"https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz","integrity":"sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==","dev":true,"requires":{"collection-visit":"^1.0.0","component-emitter":"^1.2.1","get-value":"^2.0.6","has-value":"^1.0.0","isobject":"^3.0.1","set-value":"^2.0.0","to-object-path":"^0.3.0","union-value":"^1.0.0","unset-value":"^1.0.0"}},"caching-transform":{"version":"3.0.2","resolved":"https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz","integrity":"sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==","dev":true,"requires":{"hasha":"^3.0.0","make-dir":"^2.0.0","package-hash":"^3.0.0","write-file-atomic":"^2.4.2"},"dependencies":{"make-dir":{"version":"2.1.0","resolved":"https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz","integrity":"sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==","dev":true,"requires":{"pify":"^4.0.1","semver":"^5.6.0"}},"pify":{"version":"4.0.1","resolved":"https://registry.npmjs.org/pify/-/pify-4.0.1.tgz","integrity":"sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==","dev":true}}},"caller-path":{"version":"0.1.0","resolved":"https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz","integrity":"sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=","dev":true,"requires":{"callsites":"^0.2.0"}},"callsites":{"version":"0.2.0","resolved":"http://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz","integrity":"sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=","dev":true},"camelcase":{"version":"5.0.0","resolved":"https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz","integrity":"sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==","dev":true},"caniuse-lite":{"version":"1.0.30000910","resolved":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000910.tgz","integrity":"sha512-u/nxtHGAzCGZzIxt3dA/tpSPOcirBZFWKwz1EPz4aaupnBI2XR0Rbr74g0zc6Hzy41OEM4uMoZ38k56TpYAWjQ==","dev":true},"caseless":{"version":"0.12.0","resolved":"https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz","integrity":"sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=","dev":true},"chai":{"version":"4.2.0","resolved":"https://registry.npmjs.org/chai/-/chai-4.2.0.tgz","integrity":"sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==","dev":true,"requires":{"assertion-error":"^1.1.0","check-error":"^1.0.2","deep-eql":"^3.0.1","get-func-name":"^2.0.0","pathval":"^1.1.0","type-detect":"^4.0.5"}},"chai-dom":{"version":"1.8.1","resolved":"https://registry.npmjs.org/chai-dom/-/chai-dom-1.8.1.tgz","integrity":"sha512-ysWinPU3fc+Bp+xMn/u2/PQyk65jnnCZl0alWupUuFFMGaG+KxrUnsoYOgjMDhSKPkm3WqE/5RTnOowIb7asMg==","dev":true},"chalk":{"version":"2.4.1","resolved":"https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz","integrity":"sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==","dev":true,"requires":{"ansi-styles":"^3.2.1","escape-string-regexp":"^1.0.5","supports-color":"^5.3.0"}},"chardet":{"version":"0.7.0","resolved":"https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz","integrity":"sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==","dev":true},"check-error":{"version":"1.0.2","resolved":"https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz","integrity":"sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=","dev":true},"chokidar":{"version":"2.0.4","resolved":"https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz","integrity":"sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==","dev":true,"requires":{"anymatch":"^2.0.0","async-each":"^1.0.0","braces":"^2.3.0","fsevents":"^1.2.2","glob-parent":"^3.1.0","inherits":"^2.0.1","is-binary-path":"^1.0.0","is-glob":"^4.0.0","lodash.debounce":"^4.0.8","normalize-path":"^2.1.1","path-is-absolute":"^1.0.0","readdirp":"^2.0.0","upath":"^1.0.5"}},"chownr":{"version":"1.1.1","resolved":"https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz","integrity":"sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==","dev":true},"chrome-trace-event":{"version":"1.0.0","resolved":"https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz","integrity":"sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==","dev":true,"requires":{"tslib":"^1.9.0"}},"cipher-base":{"version":"1.0.4","resolved":"https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz","integrity":"sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==","dev":true,"requires":{"inherits":"^2.0.1","safe-buffer":"^5.0.1"}},"circular-json":{"version":"0.3.3","resolved":"https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz","integrity":"sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==","dev":true},"class-utils":{"version":"0.3.6","resolved":"https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz","integrity":"sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==","dev":true,"requires":{"arr-union":"^3.1.0","define-property":"^0.2.5","isobject":"^3.0.0","static-extend":"^0.1.1"},"dependencies":{"define-property":{"version":"0.2.5","resolved":"https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz","integrity":"sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=","dev":true,"requires":{"is-descriptor":"^0.1.0"}}}},"cli-cursor":{"version":"2.1.0","resolved":"https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz","integrity":"sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=","dev":true,"requires":{"restore-cursor":"^2.0.0"}},"cli-width":{"version":"2.2.0","resolved":"https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz","integrity":"sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=","dev":true},"cliui":{"version":"4.1.0","resolved":"https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz","integrity":"sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==","dev":true,"requires":{"string-width":"^2.1.1","strip-ansi":"^4.0.0","wrap-ansi":"^2.0.0"}},"code-point-at":{"version":"1.1.0","resolved":"https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz","integrity":"sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=","dev":true},"collection-visit":{"version":"1.0.0","resolved":"https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz","integrity":"sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=","dev":true,"requires":{"map-visit":"^1.0.0","object-visit":"^1.0.0"}},"color-convert":{"version":"1.9.3","resolved":"https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz","integrity":"sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==","dev":true,"requires":{"color-name":"1.1.3"}},"color-name":{"version":"1.1.3","resolved":"https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz","integrity":"sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=","dev":true},"colors":{"version":"1.0.3","resolved":"https://registry.npmjs.org/colors/-/colors-1.0.3.tgz","integrity":"sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=","dev":true},"combined-stream":{"version":"1.0.7","resolved":"https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz","integrity":"sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==","dev":true,"requires":{"delayed-stream":"~1.0.0"}},"commander":{"version":"2.19.0","resolved":"https://registry.npmjs.org/commander/-/commander-2.19.0.tgz","integrity":"sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==","dev":true},"commondir":{"version":"1.0.1","resolved":"https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz","integrity":"sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=","dev":true},"component-emitter":{"version":"1.2.1","resolved":"https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz","integrity":"sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=","dev":true},"concat-map":{"version":"0.0.1","resolved":"https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz","integrity":"sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=","dev":true},"concat-stream":{"version":"1.6.2","resolved":"https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz","integrity":"sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==","dev":true,"requires":{"buffer-from":"^1.0.0","inherits":"^2.0.3","readable-stream":"^2.2.2","typedarray":"^0.0.6"}},"console-browserify":{"version":"1.1.0","resolved":"https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz","integrity":"sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=","dev":true,"requires":{"date-now":"^0.1.4"}},"constants-browserify":{"version":"1.0.0","resolved":"https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz","integrity":"sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=","dev":true},"convert-source-map":{"version":"1.6.0","resolved":"https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz","integrity":"sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==","dev":true,"requires":{"safe-buffer":"~5.1.1"}},"copy-concurrently":{"version":"1.0.5","resolved":"https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz","integrity":"sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==","dev":true,"requires":{"aproba":"^1.1.1","fs-write-stream-atomic":"^1.0.8","iferr":"^0.1.5","mkdirp":"^0.5.1","rimraf":"^2.5.4","run-queue":"^1.0.0"}},"copy-descriptor":{"version":"0.1.1","resolved":"https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz","integrity":"sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=","dev":true},"core-js":{"version":"2.5.7","resolved":"https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz","integrity":"sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==","dev":true},"core-util-is":{"version":"1.0.2","resolved":"https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz","integrity":"sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=","dev":true},"corser":{"version":"2.0.1","resolved":"https://registry.npmjs.org/corser/-/corser-2.0.1.tgz","integrity":"sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=","dev":true},"cp-file":{"version":"6.2.0","resolved":"https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz","integrity":"sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==","dev":true,"requires":{"graceful-fs":"^4.1.2","make-dir":"^2.0.0","nested-error-stacks":"^2.0.0","pify":"^4.0.1","safe-buffer":"^5.0.1"},"dependencies":{"make-dir":{"version":"2.1.0","resolved":"https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz","integrity":"sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==","dev":true,"requires":{"pify":"^4.0.1","semver":"^5.6.0"}},"pify":{"version":"4.0.1","resolved":"https://registry.npmjs.org/pify/-/pify-4.0.1.tgz","integrity":"sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==","dev":true}}},"create-ecdh":{"version":"4.0.3","resolved":"https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz","integrity":"sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==","dev":true,"requires":{"bn.js":"^4.1.0","elliptic":"^6.0.0"}},"create-hash":{"version":"1.2.0","resolved":"http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz","integrity":"sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==","dev":true,"requires":{"cipher-base":"^1.0.1","inherits":"^2.0.1","md5.js":"^1.3.4","ripemd160":"^2.0.1","sha.js":"^2.4.0"}},"create-hmac":{"version":"1.1.7","resolved":"http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz","integrity":"sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==","dev":true,"requires":{"cipher-base":"^1.0.3","create-hash":"^1.1.0","inherits":"^2.0.1","ripemd160":"^2.0.0","safe-buffer":"^5.0.1","sha.js":"^2.4.8"}},"cross-env":{"version":"5.2.0","resolved":"https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz","integrity":"sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==","dev":true,"requires":{"cross-spawn":"^6.0.5","is-windows":"^1.0.0"}},"cross-spawn":{"version":"6.0.5","resolved":"https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz","integrity":"sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==","dev":true,"requires":{"nice-try":"^1.0.4","path-key":"^2.0.1","semver":"^5.5.0","shebang-command":"^1.2.0","which":"^1.2.9"}},"crypto-browserify":{"version":"3.12.0","resolved":"https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz","integrity":"sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==","dev":true,"requires":{"browserify-cipher":"^1.0.0","browserify-sign":"^4.0.0","create-ecdh":"^4.0.0","create-hash":"^1.1.0","create-hmac":"^1.1.0","diffie-hellman":"^5.0.0","inherits":"^2.0.1","pbkdf2":"^3.0.3","public-encrypt":"^4.0.0","randombytes":"^2.0.0","randomfill":"^1.0.3"}},"cssom":{"version":"0.3.4","resolved":"https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz","integrity":"sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==","dev":true},"cssstyle":{"version":"0.3.1","resolved":"https://registry.npmjs.org/cssstyle/-/cssstyle-0.3.1.tgz","integrity":"sha512-tNvaxM5blOnxanyxI6panOsnfiyLRj3HV4qjqqS45WPNS1usdYWRUQjqTEEELK73lpeP/1KoIGYUwrBn/VcECA==","dev":true,"requires":{"cssom":"0.3.x"}},"cyclist":{"version":"0.2.2","resolved":"https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz","integrity":"sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=","dev":true},"dashdash":{"version":"1.14.1","resolved":"https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz","integrity":"sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=","dev":true,"requires":{"assert-plus":"^1.0.0"}},"data-urls":{"version":"1.1.0","resolved":"https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz","integrity":"sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==","dev":true,"requires":{"abab":"^2.0.0","whatwg-mimetype":"^2.2.0","whatwg-url":"^7.0.0"},"dependencies":{"abab":{"version":"2.0.0","resolved":"https://registry.npmjs.org/abab/-/abab-2.0.0.tgz","integrity":"sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==","dev":true},"whatwg-url":{"version":"7.0.0","resolved":"https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz","integrity":"sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==","dev":true,"requires":{"lodash.sortby":"^4.7.0","tr46":"^1.0.1","webidl-conversions":"^4.0.2"}}}},"date-now":{"version":"0.1.4","resolved":"https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz","integrity":"sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=","dev":true},"debug":{"version":"4.1.0","resolved":"https://registry.npmjs.org/debug/-/debug-4.1.0.tgz","integrity":"sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==","dev":true,"requires":{"ms":"^2.1.1"}},"decamelize":{"version":"1.2.0","resolved":"https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz","integrity":"sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=","dev":true},"decode-uri-component":{"version":"0.2.0","resolved":"https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz","integrity":"sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=","dev":true},"deep-eql":{"version":"3.0.1","resolved":"https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz","integrity":"sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==","dev":true,"requires":{"type-detect":"^4.0.0"}},"deep-is":{"version":"0.1.3","resolved":"https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz","integrity":"sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=","dev":true},"default-require-extensions":{"version":"2.0.0","resolved":"https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz","integrity":"sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=","dev":true,"requires":{"strip-bom":"^3.0.0"}},"define-properties":{"version":"1.1.3","resolved":"https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz","integrity":"sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==","dev":true,"requires":{"object-keys":"^1.0.12"}},"define-property":{"version":"2.0.2","resolved":"https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz","integrity":"sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==","dev":true,"requires":{"is-descriptor":"^1.0.2","isobject":"^3.0.1"},"dependencies":{"is-accessor-descriptor":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz","integrity":"sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==","dev":true,"requires":{"kind-of":"^6.0.0"}},"is-data-descriptor":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz","integrity":"sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==","dev":true,"requires":{"kind-of":"^6.0.0"}},"is-descriptor":{"version":"1.0.2","resolved":"https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz","integrity":"sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==","dev":true,"requires":{"is-accessor-descriptor":"^1.0.0","is-data-descriptor":"^1.0.0","kind-of":"^6.0.2"}}}},"delayed-stream":{"version":"1.0.0","resolved":"https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz","integrity":"sha1-3zrhmayt+31ECqrgsp4icrJOxhk=","dev":true},"des.js":{"version":"1.0.0","resolved":"https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz","integrity":"sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=","dev":true,"requires":{"inherits":"^2.0.1","minimalistic-assert":"^1.0.0"}},"diff":{"version":"3.3.1","resolved":"https://registry.npmjs.org/diff/-/diff-3.3.1.tgz","integrity":"sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==","dev":true},"diffie-hellman":{"version":"5.0.3","resolved":"http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz","integrity":"sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==","dev":true,"requires":{"bn.js":"^4.1.0","miller-rabin":"^4.0.0","randombytes":"^2.0.0"}},"doctrine":{"version":"2.1.0","resolved":"https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz","integrity":"sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==","dev":true,"requires":{"esutils":"^2.0.2"}},"domain-browser":{"version":"1.2.0","resolved":"https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz","integrity":"sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==","dev":true},"domexception":{"version":"1.0.1","resolved":"https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz","integrity":"sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==","dev":true,"requires":{"webidl-conversions":"^4.0.2"}},"duplexify":{"version":"3.6.1","resolved":"https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz","integrity":"sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==","dev":true,"requires":{"end-of-stream":"^1.0.0","inherits":"^2.0.1","readable-stream":"^2.0.0","stream-shift":"^1.0.0"}},"ecc-jsbn":{"version":"0.1.2","resolved":"https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz","integrity":"sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=","dev":true,"requires":{"jsbn":"~0.1.0","safer-buffer":"^2.1.0"}},"ecstatic":{"version":"3.3.2","resolved":"https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz","integrity":"sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==","dev":true,"requires":{"he":"^1.1.1","mime":"^1.6.0","minimist":"^1.1.0","url-join":"^2.0.5"},"dependencies":{"minimist":{"version":"1.2.0","resolved":"https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz","integrity":"sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=","dev":true}}},"electron-to-chromium":{"version":"1.3.84","resolved":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.84.tgz","integrity":"sha512-IYhbzJYOopiTaNWMBp7RjbecUBsbnbDneOP86f3qvS0G0xfzwNSvMJpTrvi5/Y1gU7tg2NAgeg8a8rCYvW9Whw==","dev":true},"elliptic":{"version":"6.4.1","resolved":"https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz","integrity":"sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==","dev":true,"requires":{"bn.js":"^4.4.0","brorand":"^1.0.1","hash.js":"^1.0.0","hmac-drbg":"^1.0.0","inherits":"^2.0.1","minimalistic-assert":"^1.0.0","minimalistic-crypto-utils":"^1.0.0"}},"emoji-regex":{"version":"7.0.3","resolved":"https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz","integrity":"sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==","dev":true},"emojis-list":{"version":"2.1.0","resolved":"https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz","integrity":"sha1-TapNnbAPmBmIDHn6RXrlsJof04k=","dev":true},"end-of-stream":{"version":"1.4.1","resolved":"https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz","integrity":"sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==","dev":true,"requires":{"once":"^1.4.0"}},"enhanced-resolve":{"version":"4.1.0","resolved":"https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz","integrity":"sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==","dev":true,"requires":{"graceful-fs":"^4.1.2","memory-fs":"^0.4.0","tapable":"^1.0.0"}},"errno":{"version":"0.1.7","resolved":"https://registry.npmjs.org/errno/-/errno-0.1.7.tgz","integrity":"sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==","dev":true,"requires":{"prr":"~1.0.1"}},"error-ex":{"version":"1.3.2","resolved":"https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz","integrity":"sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==","dev":true,"requires":{"is-arrayish":"^0.2.1"}},"es-abstract":{"version":"1.12.0","resolved":"https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz","integrity":"sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==","dev":true,"requires":{"es-to-primitive":"^1.1.1","function-bind":"^1.1.1","has":"^1.0.1","is-callable":"^1.1.3","is-regex":"^1.0.4"}},"es-to-primitive":{"version":"1.2.0","resolved":"https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz","integrity":"sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==","dev":true,"requires":{"is-callable":"^1.1.4","is-date-object":"^1.0.1","is-symbol":"^1.0.2"}},"es6-error":{"version":"4.1.1","resolved":"https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz","integrity":"sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==","dev":true},"escape-string-regexp":{"version":"1.0.5","resolved":"https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz","integrity":"sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=","dev":true},"escodegen":{"version":"1.11.0","resolved":"https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz","integrity":"sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==","dev":true,"requires":{"esprima":"^3.1.3","estraverse":"^4.2.0","esutils":"^2.0.2","optionator":"^0.8.1","source-map":"~0.6.1"},"dependencies":{"esprima":{"version":"3.1.3","resolved":"https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz","integrity":"sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=","dev":true},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true,"optional":true}}},"eslint":{"version":"5.9.0","resolved":"https://registry.npmjs.org/eslint/-/eslint-5.9.0.tgz","integrity":"sha512-g4KWpPdqN0nth+goDNICNXGfJF7nNnepthp46CAlJoJtC5K/cLu3NgCM3AHu1CkJ5Hzt9V0Y0PBAO6Ay/gGb+w==","dev":true,"requires":{"@babel/code-frame":"^7.0.0","ajv":"^6.5.3","chalk":"^2.1.0","cross-spawn":"^6.0.5","debug":"^4.0.1","doctrine":"^2.1.0","eslint-scope":"^4.0.0","eslint-utils":"^1.3.1","eslint-visitor-keys":"^1.0.0","espree":"^4.0.0","esquery":"^1.0.1","esutils":"^2.0.2","file-entry-cache":"^2.0.0","functional-red-black-tree":"^1.0.1","glob":"^7.1.2","globals":"^11.7.0","ignore":"^4.0.6","imurmurhash":"^0.1.4","inquirer":"^6.1.0","is-resolvable":"^1.1.0","js-yaml":"^3.12.0","json-stable-stringify-without-jsonify":"^1.0.1","levn":"^0.3.0","lodash":"^4.17.5","minimatch":"^3.0.4","mkdirp":"^0.5.1","natural-compare":"^1.4.0","optionator":"^0.8.2","path-is-inside":"^1.0.2","pluralize":"^7.0.0","progress":"^2.0.0","regexpp":"^2.0.1","require-uncached":"^1.0.3","semver":"^5.5.1","strip-ansi":"^4.0.0","strip-json-comments":"^2.0.1","table":"^5.0.2","text-table":"^0.2.0"},"dependencies":{"eslint-scope":{"version":"4.0.0","resolved":"https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz","integrity":"sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==","dev":true,"requires":{"esrecurse":"^4.1.0","estraverse":"^4.1.1"}}}},"eslint-loader":{"version":"2.1.1","resolved":"https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.1.1.tgz","integrity":"sha512-1GrJFfSevQdYpoDzx8mEE2TDWsb/zmFuY09l6hURg1AeFIKQOvZ+vH0UPjzmd1CZIbfTV5HUkMeBmFiDBkgIsQ==","dev":true,"requires":{"loader-fs-cache":"^1.0.0","loader-utils":"^1.0.2","object-assign":"^4.0.1","object-hash":"^1.1.4","rimraf":"^2.6.1"}},"eslint-scope":{"version":"3.7.1","resolved":"https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz","integrity":"sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=","dev":true,"requires":{"esrecurse":"^4.1.0","estraverse":"^4.1.1"}},"eslint-utils":{"version":"1.4.2","resolved":"https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz","integrity":"sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==","dev":true,"requires":{"eslint-visitor-keys":"^1.0.0"}},"eslint-visitor-keys":{"version":"1.0.0","resolved":"https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz","integrity":"sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==","dev":true},"espree":{"version":"4.1.0","resolved":"https://registry.npmjs.org/espree/-/espree-4.1.0.tgz","integrity":"sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==","dev":true,"requires":{"acorn":"^6.0.2","acorn-jsx":"^5.0.0","eslint-visitor-keys":"^1.0.0"}},"esprima":{"version":"4.0.1","resolved":"https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz","integrity":"sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==","dev":true},"esquery":{"version":"1.0.1","resolved":"https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz","integrity":"sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==","dev":true,"requires":{"estraverse":"^4.0.0"}},"esrecurse":{"version":"4.2.1","resolved":"https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz","integrity":"sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==","dev":true,"requires":{"estraverse":"^4.1.0"}},"estraverse":{"version":"4.2.0","resolved":"https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz","integrity":"sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=","dev":true},"esutils":{"version":"2.0.2","resolved":"https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz","integrity":"sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=","dev":true},"eventemitter3":{"version":"3.1.2","resolved":"https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz","integrity":"sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==","dev":true},"events":{"version":"1.1.1","resolved":"http://registry.npmjs.org/events/-/events-1.1.1.tgz","integrity":"sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=","dev":true},"evp_bytestokey":{"version":"1.0.3","resolved":"https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz","integrity":"sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==","dev":true,"requires":{"md5.js":"^1.3.4","safe-buffer":"^5.1.1"}},"execa":{"version":"0.10.0","resolved":"https://registry.npmjs.org/execa/-/execa-0.10.0.tgz","integrity":"sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==","dev":true,"requires":{"cross-spawn":"^6.0.0","get-stream":"^3.0.0","is-stream":"^1.1.0","npm-run-path":"^2.0.0","p-finally":"^1.0.0","signal-exit":"^3.0.0","strip-eof":"^1.0.0"}},"expand-brackets":{"version":"2.1.4","resolved":"https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz","integrity":"sha1-t3c14xXOMPa27/D4OwQVGiJEliI=","dev":true,"requires":{"debug":"^2.3.3","define-property":"^0.2.5","extend-shallow":"^2.0.1","posix-character-classes":"^0.1.0","regex-not":"^1.0.0","snapdragon":"^0.8.1","to-regex":"^3.0.1"},"dependencies":{"debug":{"version":"2.6.9","resolved":"https://registry.npmjs.org/debug/-/debug-2.6.9.tgz","integrity":"sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==","dev":true,"requires":{"ms":"2.0.0"}},"define-property":{"version":"0.2.5","resolved":"https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz","integrity":"sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=","dev":true,"requires":{"is-descriptor":"^0.1.0"}},"extend-shallow":{"version":"2.0.1","resolved":"https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz","integrity":"sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=","dev":true,"requires":{"is-extendable":"^0.1.0"}},"ms":{"version":"2.0.0","resolved":"https://registry.npmjs.org/ms/-/ms-2.0.0.tgz","integrity":"sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=","dev":true}}},"expand-range":{"version":"1.8.2","resolved":"https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz","integrity":"sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=","dev":true,"requires":{"fill-range":"^2.1.0"},"dependencies":{"fill-range":{"version":"2.2.4","resolved":"https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz","integrity":"sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==","dev":true,"requires":{"is-number":"^2.1.0","isobject":"^2.0.0","randomatic":"^3.0.0","repeat-element":"^1.1.2","repeat-string":"^1.5.2"}},"is-number":{"version":"2.1.0","resolved":"https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz","integrity":"sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=","dev":true,"requires":{"kind-of":"^3.0.2"}},"isobject":{"version":"2.1.0","resolved":"https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz","integrity":"sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=","dev":true,"requires":{"isarray":"1.0.0"}},"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"extend":{"version":"3.0.2","resolved":"https://registry.npmjs.org/extend/-/extend-3.0.2.tgz","integrity":"sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==","dev":true},"extend-shallow":{"version":"3.0.2","resolved":"https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz","integrity":"sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=","dev":true,"requires":{"assign-symbols":"^1.0.0","is-extendable":"^1.0.1"},"dependencies":{"is-extendable":{"version":"1.0.1","resolved":"https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz","integrity":"sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==","dev":true,"requires":{"is-plain-object":"^2.0.4"}}}},"external-editor":{"version":"3.0.3","resolved":"https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz","integrity":"sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==","dev":true,"requires":{"chardet":"^0.7.0","iconv-lite":"^0.4.24","tmp":"^0.0.33"}},"extglob":{"version":"2.0.4","resolved":"https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz","integrity":"sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==","dev":true,"requires":{"array-unique":"^0.3.2","define-property":"^1.0.0","expand-brackets":"^2.1.4","extend-shallow":"^2.0.1","fragment-cache":"^0.2.1","regex-not":"^1.0.0","snapdragon":"^0.8.1","to-regex":"^3.0.1"},"dependencies":{"define-property":{"version":"1.0.0","resolved":"https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz","integrity":"sha1-dp66rz9KY6rTr56NMEybvnm/sOY=","dev":true,"requires":{"is-descriptor":"^1.0.0"}},"extend-shallow":{"version":"2.0.1","resolved":"https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz","integrity":"sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=","dev":true,"requires":{"is-extendable":"^0.1.0"}},"is-accessor-descriptor":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz","integrity":"sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==","dev":true,"requires":{"kind-of":"^6.0.0"}},"is-data-descriptor":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz","integrity":"sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==","dev":true,"requires":{"kind-of":"^6.0.0"}},"is-descriptor":{"version":"1.0.2","resolved":"https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz","integrity":"sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==","dev":true,"requires":{"is-accessor-descriptor":"^1.0.0","is-data-descriptor":"^1.0.0","kind-of":"^6.0.2"}}}},"extsprintf":{"version":"1.3.0","resolved":"https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz","integrity":"sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=","dev":true},"fast-deep-equal":{"version":"2.0.1","resolved":"https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz","integrity":"sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=","dev":true},"fast-json-stable-stringify":{"version":"2.0.0","resolved":"https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz","integrity":"sha1-1RQsDK7msRifh9OnYREGT4bIu/I=","dev":true},"fast-levenshtein":{"version":"2.0.6","resolved":"https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz","integrity":"sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=","dev":true},"figgy-pudding":{"version":"3.5.1","resolved":"https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz","integrity":"sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==","dev":true},"figures":{"version":"2.0.0","resolved":"https://registry.npmjs.org/figures/-/figures-2.0.0.tgz","integrity":"sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=","dev":true,"requires":{"escape-string-regexp":"^1.0.5"}},"file-entry-cache":{"version":"2.0.0","resolved":"https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz","integrity":"sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=","dev":true,"requires":{"flat-cache":"^1.2.1","object-assign":"^4.0.1"}},"filename-regex":{"version":"2.0.1","resolved":"https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz","integrity":"sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=","dev":true},"fill-range":{"version":"4.0.0","resolved":"https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz","integrity":"sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=","dev":true,"requires":{"extend-shallow":"^2.0.1","is-number":"^3.0.0","repeat-string":"^1.6.1","to-regex-range":"^2.1.0"},"dependencies":{"extend-shallow":{"version":"2.0.1","resolved":"https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz","integrity":"sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=","dev":true,"requires":{"is-extendable":"^0.1.0"}}}},"find-cache-dir":{"version":"1.0.0","resolved":"https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz","integrity":"sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=","dev":true,"requires":{"commondir":"^1.0.1","make-dir":"^1.0.0","pkg-dir":"^2.0.0"}},"find-up":{"version":"2.1.0","resolved":"https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz","integrity":"sha1-RdG35QbHF93UgndaK3eSCjwMV6c=","dev":true,"requires":{"locate-path":"^2.0.0"}},"flat-cache":{"version":"1.3.4","resolved":"https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz","integrity":"sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==","dev":true,"requires":{"circular-json":"^0.3.1","graceful-fs":"^4.1.2","rimraf":"~2.6.2","write":"^0.2.1"}},"flush-write-stream":{"version":"1.0.3","resolved":"https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz","integrity":"sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==","dev":true,"requires":{"inherits":"^2.0.1","readable-stream":"^2.0.4"}},"follow-redirects":{"version":"1.7.0","resolved":"https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz","integrity":"sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==","dev":true,"requires":{"debug":"^3.2.6"},"dependencies":{"debug":{"version":"3.2.6","resolved":"https://registry.npmjs.org/debug/-/debug-3.2.6.tgz","integrity":"sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==","dev":true,"requires":{"ms":"^2.1.1"}}}},"for-in":{"version":"1.0.2","resolved":"https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz","integrity":"sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=","dev":true},"for-own":{"version":"0.1.5","resolved":"https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz","integrity":"sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=","dev":true,"requires":{"for-in":"^1.0.1"}},"foreground-child":{"version":"1.5.6","resolved":"https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz","integrity":"sha1-T9ca0t/elnibmApcCilZN8svXOk=","dev":true,"requires":{"cross-spawn":"^4","signal-exit":"^3.0.0"},"dependencies":{"cross-spawn":{"version":"4.0.2","resolved":"https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz","integrity":"sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=","dev":true,"requires":{"lru-cache":"^4.0.1","which":"^1.2.9"}}}},"forever-agent":{"version":"0.6.1","resolved":"https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz","integrity":"sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=","dev":true},"form-data":{"version":"2.3.3","resolved":"https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz","integrity":"sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==","dev":true,"requires":{"asynckit":"^0.4.0","combined-stream":"^1.0.6","mime-types":"^2.1.12"}},"fragment-cache":{"version":"0.2.1","resolved":"https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz","integrity":"sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=","dev":true,"requires":{"map-cache":"^0.2.2"}},"from2":{"version":"2.3.0","resolved":"https://registry.npmjs.org/from2/-/from2-2.3.0.tgz","integrity":"sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=","dev":true,"requires":{"inherits":"^2.0.1","readable-stream":"^2.0.0"}},"fs-readdir-recursive":{"version":"1.1.0","resolved":"https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz","integrity":"sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==","dev":true},"fs-write-stream-atomic":{"version":"1.0.10","resolved":"https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz","integrity":"sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=","dev":true,"requires":{"graceful-fs":"^4.1.2","iferr":"^0.1.5","imurmurhash":"^0.1.4","readable-stream":"1 || 2"}},"fs.realpath":{"version":"1.0.0","resolved":"https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz","integrity":"sha1-FQStJSMVjKpA20onh8sBQRmU6k8=","dev":true},"fsevents":{"version":"1.2.9","resolved":"https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz","integrity":"sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==","dev":true,"optional":true,"requires":{"nan":"^2.12.1","node-pre-gyp":"^0.12.0"},"dependencies":{"abbrev":{"version":"1.1.1","bundled":true,"dev":true,"optional":true},"ansi-regex":{"version":"2.1.1","bundled":true,"dev":true,"optional":true},"aproba":{"version":"1.2.0","bundled":true,"dev":true,"optional":true},"are-we-there-yet":{"version":"1.1.5","bundled":true,"dev":true,"optional":true,"requires":{"delegates":"^1.0.0","readable-stream":"^2.0.6"}},"balanced-match":{"version":"1.0.0","bundled":true,"dev":true,"optional":true},"brace-expansion":{"version":"1.1.11","bundled":true,"dev":true,"optional":true,"requires":{"balanced-match":"^1.0.0","concat-map":"0.0.1"}},"chownr":{"version":"1.1.1","bundled":true,"dev":true,"optional":true},"code-point-at":{"version":"1.1.0","bundled":true,"dev":true,"optional":true},"concat-map":{"version":"0.0.1","bundled":true,"dev":true,"optional":true},"console-control-strings":{"version":"1.1.0","bundled":true,"dev":true,"optional":true},"core-util-is":{"version":"1.0.2","bundled":true,"dev":true,"optional":true},"debug":{"version":"4.1.1","bundled":true,"dev":true,"optional":true,"requires":{"ms":"^2.1.1"}},"deep-extend":{"version":"0.6.0","bundled":true,"dev":true,"optional":true},"delegates":{"version":"1.0.0","bundled":true,"dev":true,"optional":true},"detect-libc":{"version":"1.0.3","bundled":true,"dev":true,"optional":true},"fs-minipass":{"version":"1.2.5","bundled":true,"dev":true,"optional":true,"requires":{"minipass":"^2.2.1"}},"fs.realpath":{"version":"1.0.0","bundled":true,"dev":true,"optional":true},"gauge":{"version":"2.7.4","bundled":true,"dev":true,"optional":true,"requires":{"aproba":"^1.0.3","console-control-strings":"^1.0.0","has-unicode":"^2.0.0","object-assign":"^4.1.0","signal-exit":"^3.0.0","string-width":"^1.0.1","strip-ansi":"^3.0.1","wide-align":"^1.1.0"}},"glob":{"version":"7.1.3","bundled":true,"dev":true,"optional":true,"requires":{"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"}},"has-unicode":{"version":"2.0.1","bundled":true,"dev":true,"optional":true},"iconv-lite":{"version":"0.4.24","bundled":true,"dev":true,"optional":true,"requires":{"safer-buffer":">= 2.1.2 < 3"}},"ignore-walk":{"version":"3.0.1","bundled":true,"dev":true,"optional":true,"requires":{"minimatch":"^3.0.4"}},"inflight":{"version":"1.0.6","bundled":true,"dev":true,"optional":true,"requires":{"once":"^1.3.0","wrappy":"1"}},"inherits":{"version":"2.0.3","bundled":true,"dev":true,"optional":true},"ini":{"version":"1.3.5","bundled":true,"dev":true,"optional":true},"is-fullwidth-code-point":{"version":"1.0.0","bundled":true,"dev":true,"optional":true,"requires":{"number-is-nan":"^1.0.0"}},"isarray":{"version":"1.0.0","bundled":true,"dev":true,"optional":true},"minimatch":{"version":"3.0.4","bundled":true,"dev":true,"optional":true,"requires":{"brace-expansion":"^1.1.7"}},"minimist":{"version":"0.0.8","bundled":true,"dev":true,"optional":true},"minipass":{"version":"2.3.5","bundled":true,"dev":true,"optional":true,"requires":{"safe-buffer":"^5.1.2","yallist":"^3.0.0"}},"minizlib":{"version":"1.2.1","bundled":true,"dev":true,"optional":true,"requires":{"minipass":"^2.2.1"}},"mkdirp":{"version":"0.5.1","bundled":true,"dev":true,"optional":true,"requires":{"minimist":"0.0.8"}},"ms":{"version":"2.1.1","bundled":true,"dev":true,"optional":true},"needle":{"version":"2.3.0","bundled":true,"dev":true,"optional":true,"requires":{"debug":"^4.1.0","iconv-lite":"^0.4.4","sax":"^1.2.4"}},"node-pre-gyp":{"version":"0.12.0","bundled":true,"dev":true,"optional":true,"requires":{"detect-libc":"^1.0.2","mkdirp":"^0.5.1","needle":"^2.2.1","nopt":"^4.0.1","npm-packlist":"^1.1.6","npmlog":"^4.0.2","rc":"^1.2.7","rimraf":"^2.6.1","semver":"^5.3.0","tar":"^4"}},"nopt":{"version":"4.0.1","bundled":true,"dev":true,"optional":true,"requires":{"abbrev":"1","osenv":"^0.1.4"}},"npm-bundled":{"version":"1.0.6","bundled":true,"dev":true,"optional":true},"npm-packlist":{"version":"1.4.1","bundled":true,"dev":true,"optional":true,"requires":{"ignore-walk":"^3.0.1","npm-bundled":"^1.0.1"}},"npmlog":{"version":"4.1.2","bundled":true,"dev":true,"optional":true,"requires":{"are-we-there-yet":"~1.1.2","console-control-strings":"~1.1.0","gauge":"~2.7.3","set-blocking":"~2.0.0"}},"number-is-nan":{"version":"1.0.1","bundled":true,"dev":true,"optional":true},"object-assign":{"version":"4.1.1","bundled":true,"dev":true,"optional":true},"once":{"version":"1.4.0","bundled":true,"dev":true,"optional":true,"requires":{"wrappy":"1"}},"os-homedir":{"version":"1.0.2","bundled":true,"dev":true,"optional":true},"os-tmpdir":{"version":"1.0.2","bundled":true,"dev":true,"optional":true},"osenv":{"version":"0.1.5","bundled":true,"dev":true,"optional":true,"requires":{"os-homedir":"^1.0.0","os-tmpdir":"^1.0.0"}},"path-is-absolute":{"version":"1.0.1","bundled":true,"dev":true,"optional":true},"process-nextick-args":{"version":"2.0.0","bundled":true,"dev":true,"optional":true},"rc":{"version":"1.2.8","bundled":true,"dev":true,"optional":true,"requires":{"deep-extend":"^0.6.0","ini":"~1.3.0","minimist":"^1.2.0","strip-json-comments":"~2.0.1"},"dependencies":{"minimist":{"version":"1.2.0","bundled":true,"dev":true,"optional":true}}},"readable-stream":{"version":"2.3.6","bundled":true,"dev":true,"optional":true,"requires":{"core-util-is":"~1.0.0","inherits":"~2.0.3","isarray":"~1.0.0","process-nextick-args":"~2.0.0","safe-buffer":"~5.1.1","string_decoder":"~1.1.1","util-deprecate":"~1.0.1"}},"rimraf":{"version":"2.6.3","bundled":true,"dev":true,"optional":true,"requires":{"glob":"^7.1.3"}},"safe-buffer":{"version":"5.1.2","bundled":true,"dev":true,"optional":true},"safer-buffer":{"version":"2.1.2","bundled":true,"dev":true,"optional":true},"sax":{"version":"1.2.4","bundled":true,"dev":true,"optional":true},"semver":{"version":"5.7.0","bundled":true,"dev":true,"optional":true},"set-blocking":{"version":"2.0.0","bundled":true,"dev":true,"optional":true},"signal-exit":{"version":"3.0.2","bundled":true,"dev":true,"optional":true},"string-width":{"version":"1.0.2","bundled":true,"dev":true,"optional":true,"requires":{"code-point-at":"^1.0.0","is-fullwidth-code-point":"^1.0.0","strip-ansi":"^3.0.0"}},"string_decoder":{"version":"1.1.1","bundled":true,"dev":true,"optional":true,"requires":{"safe-buffer":"~5.1.0"}},"strip-ansi":{"version":"3.0.1","bundled":true,"dev":true,"optional":true,"requires":{"ansi-regex":"^2.0.0"}},"strip-json-comments":{"version":"2.0.1","bundled":true,"dev":true,"optional":true},"tar":{"version":"4.4.8","bundled":true,"dev":true,"optional":true,"requires":{"chownr":"^1.1.1","fs-minipass":"^1.2.5","minipass":"^2.3.4","minizlib":"^1.1.1","mkdirp":"^0.5.0","safe-buffer":"^5.1.2","yallist":"^3.0.2"}},"util-deprecate":{"version":"1.0.2","bundled":true,"dev":true,"optional":true},"wide-align":{"version":"1.1.3","bundled":true,"dev":true,"optional":true,"requires":{"string-width":"^1.0.2 || 2"}},"wrappy":{"version":"1.0.2","bundled":true,"dev":true,"optional":true},"yallist":{"version":"3.0.3","bundled":true,"dev":true,"optional":true}}},"function-bind":{"version":"1.1.1","resolved":"https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz","integrity":"sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==","dev":true},"functional-red-black-tree":{"version":"1.0.1","resolved":"https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz","integrity":"sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=","dev":true},"get-caller-file":{"version":"1.0.3","resolved":"https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz","integrity":"sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==","dev":true},"get-func-name":{"version":"2.0.0","resolved":"https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz","integrity":"sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=","dev":true},"get-stream":{"version":"3.0.0","resolved":"https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz","integrity":"sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=","dev":true},"get-value":{"version":"2.0.6","resolved":"https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz","integrity":"sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=","dev":true},"getpass":{"version":"0.1.7","resolved":"https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz","integrity":"sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=","dev":true,"requires":{"assert-plus":"^1.0.0"}},"glob":{"version":"7.1.3","resolved":"https://registry.npmjs.org/glob/-/glob-7.1.3.tgz","integrity":"sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==","dev":true,"requires":{"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"}},"glob-base":{"version":"0.3.0","resolved":"https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz","integrity":"sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=","dev":true,"requires":{"glob-parent":"^2.0.0","is-glob":"^2.0.0"},"dependencies":{"glob-parent":{"version":"2.0.0","resolved":"https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz","integrity":"sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=","dev":true,"requires":{"is-glob":"^2.0.0"}},"is-extglob":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz","integrity":"sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=","dev":true},"is-glob":{"version":"2.0.1","resolved":"https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz","integrity":"sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=","dev":true,"requires":{"is-extglob":"^1.0.0"}}}},"glob-parent":{"version":"3.1.0","resolved":"https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz","integrity":"sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=","dev":true,"requires":{"is-glob":"^3.1.0","path-dirname":"^1.0.0"},"dependencies":{"is-glob":{"version":"3.1.0","resolved":"https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz","integrity":"sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=","dev":true,"requires":{"is-extglob":"^2.1.0"}}}},"global-modules-path":{"version":"2.3.0","resolved":"https://registry.npmjs.org/global-modules-path/-/global-modules-path-2.3.0.tgz","integrity":"sha512-HchvMJNYh9dGSCy8pOQ2O8u/hoXaL+0XhnrwH0RyLiSXMMTl9W3N6KUU73+JFOg5PGjtzl6VZzUQsnrpm7Szag==","dev":true},"globals":{"version":"11.9.0","resolved":"https://registry.npmjs.org/globals/-/globals-11.9.0.tgz","integrity":"sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==","dev":true},"graceful-fs":{"version":"4.1.15","resolved":"https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz","integrity":"sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==","dev":true},"growl":{"version":"1.10.3","resolved":"https://registry.npmjs.org/growl/-/growl-1.10.3.tgz","integrity":"sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==","dev":true},"handlebars":{"version":"4.4.0","resolved":"https://registry.npmjs.org/handlebars/-/handlebars-4.4.0.tgz","integrity":"sha512-xkRtOt3/3DzTKMOt3xahj2M/EqNhY988T+imYSlMgs5fVhLN2fmKVVj0LtEGmb+3UUYV5Qmm1052Mm3dIQxOvw==","dev":true,"requires":{"neo-async":"^2.6.0","optimist":"^0.6.1","source-map":"^0.6.1","uglify-js":"^3.1.4"},"dependencies":{"commander":{"version":"2.20.1","resolved":"https://registry.npmjs.org/commander/-/commander-2.20.1.tgz","integrity":"sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==","dev":true,"optional":true},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true},"uglify-js":{"version":"3.6.0","resolved":"https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz","integrity":"sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==","dev":true,"optional":true,"requires":{"commander":"~2.20.0","source-map":"~0.6.1"}}}},"har-schema":{"version":"2.0.0","resolved":"https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz","integrity":"sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=","dev":true},"har-validator":{"version":"5.1.3","resolved":"https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz","integrity":"sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==","dev":true,"requires":{"ajv":"^6.5.5","har-schema":"^2.0.0"}},"has":{"version":"1.0.3","resolved":"https://registry.npmjs.org/has/-/has-1.0.3.tgz","integrity":"sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==","dev":true,"requires":{"function-bind":"^1.1.1"}},"has-flag":{"version":"3.0.0","resolved":"https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz","integrity":"sha1-tdRU3CGZriJWmfNGfloH87lVuv0=","dev":true},"has-symbols":{"version":"1.0.0","resolved":"https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz","integrity":"sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=","dev":true},"has-value":{"version":"1.0.0","resolved":"https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz","integrity":"sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=","dev":true,"requires":{"get-value":"^2.0.6","has-values":"^1.0.0","isobject":"^3.0.0"}},"has-values":{"version":"1.0.0","resolved":"https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz","integrity":"sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=","dev":true,"requires":{"is-number":"^3.0.0","kind-of":"^4.0.0"},"dependencies":{"kind-of":{"version":"4.0.0","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz","integrity":"sha1-IIE989cSkosgc3hpGkUGb65y3Vc=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"hash-base":{"version":"3.0.4","resolved":"https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz","integrity":"sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=","dev":true,"requires":{"inherits":"^2.0.1","safe-buffer":"^5.0.1"}},"hash.js":{"version":"1.1.5","resolved":"https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz","integrity":"sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==","dev":true,"requires":{"inherits":"^2.0.3","minimalistic-assert":"^1.0.1"}},"hasha":{"version":"3.0.0","resolved":"https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz","integrity":"sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=","dev":true,"requires":{"is-stream":"^1.0.1"}},"he":{"version":"1.1.1","resolved":"https://registry.npmjs.org/he/-/he-1.1.1.tgz","integrity":"sha1-k0EP0hsAlzUVH4howvJx80J+I/0=","dev":true},"hmac-drbg":{"version":"1.0.1","resolved":"https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz","integrity":"sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=","dev":true,"requires":{"hash.js":"^1.0.3","minimalistic-assert":"^1.0.0","minimalistic-crypto-utils":"^1.0.1"}},"home-or-tmp":{"version":"3.0.0","resolved":"https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-3.0.0.tgz","integrity":"sha1-V6j+JM8zzdUkhgoVgh3cJchmcfs=","dev":true},"hosted-git-info":{"version":"2.7.1","resolved":"https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz","integrity":"sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==","dev":true},"html-encoding-sniffer":{"version":"1.0.2","resolved":"https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz","integrity":"sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==","dev":true,"requires":{"whatwg-encoding":"^1.0.1"}},"http-proxy":{"version":"1.17.0","resolved":"https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz","integrity":"sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==","dev":true,"requires":{"eventemitter3":"^3.0.0","follow-redirects":"^1.0.0","requires-port":"^1.0.0"}},"http-server":{"version":"0.11.1","resolved":"https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz","integrity":"sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==","dev":true,"requires":{"colors":"1.0.3","corser":"~2.0.0","ecstatic":"^3.0.0","http-proxy":"^1.8.1","opener":"~1.4.0","optimist":"0.6.x","portfinder":"^1.0.13","union":"~0.4.3"}},"http-signature":{"version":"1.2.0","resolved":"https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz","integrity":"sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=","dev":true,"requires":{"assert-plus":"^1.0.0","jsprim":"^1.2.2","sshpk":"^1.7.0"}},"https-browserify":{"version":"1.0.0","resolved":"https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz","integrity":"sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=","dev":true},"iconv-lite":{"version":"0.4.24","resolved":"https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz","integrity":"sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==","dev":true,"requires":{"safer-buffer":">= 2.1.2 < 3"}},"ieee754":{"version":"1.1.12","resolved":"https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz","integrity":"sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==","dev":true},"iferr":{"version":"0.1.5","resolved":"https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz","integrity":"sha1-xg7taebY/bazEEofy8ocGS3FtQE=","dev":true},"ignore":{"version":"4.0.6","resolved":"https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz","integrity":"sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==","dev":true},"import-local":{"version":"2.0.0","resolved":"https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz","integrity":"sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==","dev":true,"requires":{"pkg-dir":"^3.0.0","resolve-cwd":"^2.0.0"},"dependencies":{"find-up":{"version":"3.0.0","resolved":"https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz","integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"locate-path":{"version":"3.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz","integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"p-limit":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz","integrity":"sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz","integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz","integrity":"sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==","dev":true},"pkg-dir":{"version":"3.0.0","resolved":"https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz","integrity":"sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==","dev":true,"requires":{"find-up":"^3.0.0"}}}},"imurmurhash":{"version":"0.1.4","resolved":"https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz","integrity":"sha1-khi5srkoojixPcT7a21XbyMUU+o=","dev":true},"indexof":{"version":"0.0.1","resolved":"https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz","integrity":"sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=","dev":true},"inflight":{"version":"1.0.6","resolved":"https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz","integrity":"sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=","dev":true,"requires":{"once":"^1.3.0","wrappy":"1"}},"inherits":{"version":"2.0.3","resolved":"https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz","integrity":"sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=","dev":true},"inquirer":{"version":"6.2.0","resolved":"https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz","integrity":"sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==","dev":true,"requires":{"ansi-escapes":"^3.0.0","chalk":"^2.0.0","cli-cursor":"^2.1.0","cli-width":"^2.0.0","external-editor":"^3.0.0","figures":"^2.0.0","lodash":"^4.17.10","mute-stream":"0.0.7","run-async":"^2.2.0","rxjs":"^6.1.0","string-width":"^2.1.0","strip-ansi":"^4.0.0","through":"^2.3.6"}},"interpret":{"version":"1.1.0","resolved":"https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz","integrity":"sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=","dev":true},"invariant":{"version":"2.2.4","resolved":"https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz","integrity":"sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==","dev":true,"requires":{"loose-envify":"^1.0.0"}},"invert-kv":{"version":"2.0.0","resolved":"https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz","integrity":"sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==","dev":true},"is-accessor-descriptor":{"version":"0.1.6","resolved":"https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz","integrity":"sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=","dev":true,"requires":{"kind-of":"^3.0.2"},"dependencies":{"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"is-arrayish":{"version":"0.2.1","resolved":"https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz","integrity":"sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=","dev":true},"is-binary-path":{"version":"1.0.1","resolved":"https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz","integrity":"sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=","dev":true,"requires":{"binary-extensions":"^1.0.0"}},"is-buffer":{"version":"1.1.6","resolved":"https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz","integrity":"sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==","dev":true},"is-builtin-module":{"version":"1.0.0","resolved":"http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz","integrity":"sha1-VAVy0096wxGfj3bDDLwbHgN6/74=","dev":true,"requires":{"builtin-modules":"^1.0.0"}},"is-callable":{"version":"1.1.4","resolved":"https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz","integrity":"sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==","dev":true},"is-data-descriptor":{"version":"0.1.4","resolved":"https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz","integrity":"sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=","dev":true,"requires":{"kind-of":"^3.0.2"},"dependencies":{"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"is-date-object":{"version":"1.0.1","resolved":"https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz","integrity":"sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=","dev":true},"is-descriptor":{"version":"0.1.6","resolved":"https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz","integrity":"sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==","dev":true,"requires":{"is-accessor-descriptor":"^0.1.6","is-data-descriptor":"^0.1.4","kind-of":"^5.0.0"},"dependencies":{"kind-of":{"version":"5.1.0","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz","integrity":"sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==","dev":true}}},"is-dotfile":{"version":"1.0.3","resolved":"https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz","integrity":"sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=","dev":true},"is-equal-shallow":{"version":"0.1.3","resolved":"https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz","integrity":"sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=","dev":true,"requires":{"is-primitive":"^2.0.0"}},"is-extendable":{"version":"0.1.1","resolved":"https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz","integrity":"sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=","dev":true},"is-extglob":{"version":"2.1.1","resolved":"https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz","integrity":"sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=","dev":true},"is-fullwidth-code-point":{"version":"2.0.0","resolved":"https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz","integrity":"sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=","dev":true},"is-glob":{"version":"4.0.0","resolved":"https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz","integrity":"sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=","dev":true,"requires":{"is-extglob":"^2.1.1"}},"is-number":{"version":"3.0.0","resolved":"https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz","integrity":"sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=","dev":true,"requires":{"kind-of":"^3.0.2"},"dependencies":{"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"is-plain-obj":{"version":"1.1.0","resolved":"https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz","integrity":"sha1-caUMhCnfync8kqOQpKA7OfzVHT4=","dev":true},"is-plain-object":{"version":"2.0.4","resolved":"https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz","integrity":"sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==","dev":true,"requires":{"isobject":"^3.0.1"}},"is-posix-bracket":{"version":"0.1.1","resolved":"https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz","integrity":"sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=","dev":true},"is-primitive":{"version":"2.0.0","resolved":"https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz","integrity":"sha1-IHurkWOEmcB7Kt8kCkGochADRXU=","dev":true},"is-promise":{"version":"2.1.0","resolved":"https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz","integrity":"sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=","dev":true},"is-regex":{"version":"1.0.4","resolved":"https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz","integrity":"sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=","dev":true,"requires":{"has":"^1.0.1"}},"is-resolvable":{"version":"1.1.0","resolved":"https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz","integrity":"sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==","dev":true},"is-stream":{"version":"1.1.0","resolved":"https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz","integrity":"sha1-EtSj3U5o4Lec6428hBc66A2RykQ=","dev":true},"is-symbol":{"version":"1.0.2","resolved":"https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz","integrity":"sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==","dev":true,"requires":{"has-symbols":"^1.0.0"}},"is-typedarray":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz","integrity":"sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=","dev":true},"is-windows":{"version":"1.0.2","resolved":"https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz","integrity":"sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==","dev":true},"isarray":{"version":"1.0.0","resolved":"https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz","integrity":"sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=","dev":true},"isexe":{"version":"2.0.0","resolved":"https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz","integrity":"sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=","dev":true},"isobject":{"version":"3.0.1","resolved":"https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz","integrity":"sha1-TkMekrEalzFjaqH5yNHMvP2reN8=","dev":true},"isstream":{"version":"0.1.2","resolved":"https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz","integrity":"sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=","dev":true},"istanbul-lib-coverage":{"version":"2.0.1","resolved":"https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz","integrity":"sha512-nPvSZsVlbG9aLhZYaC3Oi1gT/tpyo3Yt5fNyf6NmcKIayz4VV/txxJFFKAK/gU4dcNn8ehsanBbVHVl0+amOLA==","dev":true},"istanbul-lib-hook":{"version":"2.0.7","resolved":"https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz","integrity":"sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==","dev":true,"requires":{"append-transform":"^1.0.0"}},"istanbul-lib-instrument":{"version":"3.0.0","resolved":"https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.0.0.tgz","integrity":"sha512-eQY9vN9elYjdgN9Iv6NS/00bptm02EBBk70lRMaVjeA6QYocQgenVrSgC28TJurdnZa80AGO3ASdFN+w/njGiQ==","dev":true,"requires":{"@babel/generator":"^7.0.0","@babel/parser":"^7.0.0","@babel/template":"^7.0.0","@babel/traverse":"^7.0.0","@babel/types":"^7.0.0","istanbul-lib-coverage":"^2.0.1","semver":"^5.5.0"}},"istanbul-lib-report":{"version":"2.0.8","resolved":"https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz","integrity":"sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==","dev":true,"requires":{"istanbul-lib-coverage":"^2.0.5","make-dir":"^2.1.0","supports-color":"^6.1.0"},"dependencies":{"istanbul-lib-coverage":{"version":"2.0.5","resolved":"https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz","integrity":"sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==","dev":true},"make-dir":{"version":"2.1.0","resolved":"https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz","integrity":"sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==","dev":true,"requires":{"pify":"^4.0.1","semver":"^5.6.0"}},"pify":{"version":"4.0.1","resolved":"https://registry.npmjs.org/pify/-/pify-4.0.1.tgz","integrity":"sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==","dev":true},"supports-color":{"version":"6.1.0","resolved":"https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz","integrity":"sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==","dev":true,"requires":{"has-flag":"^3.0.0"}}}},"istanbul-lib-source-maps":{"version":"3.0.6","resolved":"https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz","integrity":"sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==","dev":true,"requires":{"debug":"^4.1.1","istanbul-lib-coverage":"^2.0.5","make-dir":"^2.1.0","rimraf":"^2.6.3","source-map":"^0.6.1"},"dependencies":{"debug":{"version":"4.1.1","resolved":"https://registry.npmjs.org/debug/-/debug-4.1.1.tgz","integrity":"sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==","dev":true,"requires":{"ms":"^2.1.1"}},"istanbul-lib-coverage":{"version":"2.0.5","resolved":"https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz","integrity":"sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==","dev":true},"make-dir":{"version":"2.1.0","resolved":"https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz","integrity":"sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==","dev":true,"requires":{"pify":"^4.0.1","semver":"^5.6.0"}},"pify":{"version":"4.0.1","resolved":"https://registry.npmjs.org/pify/-/pify-4.0.1.tgz","integrity":"sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==","dev":true},"rimraf":{"version":"2.6.3","resolved":"https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz","integrity":"sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==","dev":true,"requires":{"glob":"^7.1.3"}},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true}}},"istanbul-reports":{"version":"2.2.6","resolved":"https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz","integrity":"sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==","dev":true,"requires":{"handlebars":"^4.1.2"}},"js-levenshtein":{"version":"1.1.4","resolved":"https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz","integrity":"sha512-PxfGzSs0ztShKrUYPIn5r0MtyAhYcCwmndozzpz8YObbPnD1jFxzlBGbRnX2mIu6Z13xN6+PTu05TQFnZFlzow==","dev":true},"js-tokens":{"version":"4.0.0","resolved":"https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz","integrity":"sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==","dev":true},"js-yaml":{"version":"3.13.1","resolved":"https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz","integrity":"sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==","dev":true,"requires":{"argparse":"^1.0.7","esprima":"^4.0.0"}},"jsbn":{"version":"0.1.1","resolved":"https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz","integrity":"sha1-peZUwuWi3rXyAdls77yoDA7y9RM=","dev":true},"jsdom":{"version":"11.11.0","resolved":"https://registry.npmjs.org/jsdom/-/jsdom-11.11.0.tgz","integrity":"sha512-ou1VyfjwsSuWkudGxb03FotDajxAto6USAlmMZjE2lc0jCznt7sBWkhfRBRaWwbnmDqdMSTKTLT5d9sBFkkM7A==","dev":true,"requires":{"abab":"^1.0.4","acorn":"^5.3.0","acorn-globals":"^4.1.0","array-equal":"^1.0.0","cssom":">= 0.3.2 < 0.4.0","cssstyle":">= 0.3.1 < 0.4.0","data-urls":"^1.0.0","domexception":"^1.0.0","escodegen":"^1.9.0","html-encoding-sniffer":"^1.0.2","left-pad":"^1.2.0","nwsapi":"^2.0.0","parse5":"4.0.0","pn":"^1.1.0","request":"^2.83.0","request-promise-native":"^1.0.5","sax":"^1.2.4","symbol-tree":"^3.2.2","tough-cookie":"^2.3.3","w3c-hr-time":"^1.0.1","webidl-conversions":"^4.0.2","whatwg-encoding":"^1.0.3","whatwg-mimetype":"^2.1.0","whatwg-url":"^6.4.1","ws":"^4.0.0","xml-name-validator":"^3.0.0"},"dependencies":{"acorn":{"version":"5.7.4","resolved":"https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz","integrity":"sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==","dev":true}}},"jsdom-global":{"version":"3.0.2","resolved":"https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz","integrity":"sha1-a9KZwTsMRiay2iwDk81DhdYGrLk=","dev":true},"jsesc":{"version":"2.5.2","resolved":"https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz","integrity":"sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==","dev":true},"json-parse-better-errors":{"version":"1.0.2","resolved":"https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz","integrity":"sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==","dev":true},"json-schema":{"version":"0.2.3","resolved":"https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz","integrity":"sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=","dev":true},"json-schema-traverse":{"version":"0.4.1","resolved":"https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz","integrity":"sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==","dev":true},"json-stable-stringify-without-jsonify":{"version":"1.0.1","resolved":"https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz","integrity":"sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=","dev":true},"json-stringify-safe":{"version":"5.0.1","resolved":"https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz","integrity":"sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=","dev":true},"json5":{"version":"2.1.0","resolved":"https://registry.npmjs.org/json5/-/json5-2.1.0.tgz","integrity":"sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==","dev":true,"requires":{"minimist":"^1.2.0"},"dependencies":{"minimist":{"version":"1.2.0","resolved":"https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz","integrity":"sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=","dev":true}}},"jsprim":{"version":"1.4.1","resolved":"https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz","integrity":"sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=","dev":true,"requires":{"assert-plus":"1.0.0","extsprintf":"1.3.0","json-schema":"0.2.3","verror":"1.10.0"}},"kind-of":{"version":"6.0.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz","integrity":"sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==","dev":true},"lcid":{"version":"2.0.0","resolved":"https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz","integrity":"sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==","dev":true,"requires":{"invert-kv":"^2.0.0"}},"left-pad":{"version":"1.3.0","resolved":"https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz","integrity":"sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==","dev":true},"levn":{"version":"0.3.0","resolved":"https://registry.npmjs.org/levn/-/levn-0.3.0.tgz","integrity":"sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=","dev":true,"requires":{"prelude-ls":"~1.1.2","type-check":"~0.3.2"}},"load-json-file":{"version":"4.0.0","resolved":"https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz","integrity":"sha1-L19Fq5HjMhYjT9U62rZo607AmTs=","dev":true,"requires":{"graceful-fs":"^4.1.2","parse-json":"^4.0.0","pify":"^3.0.0","strip-bom":"^3.0.0"}},"loader-fs-cache":{"version":"1.0.1","resolved":"https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz","integrity":"sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw=","dev":true,"requires":{"find-cache-dir":"^0.1.1","mkdirp":"0.5.1"},"dependencies":{"find-cache-dir":{"version":"0.1.1","resolved":"https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz","integrity":"sha1-yN765XyKUqinhPnjHFfHQumToLk=","dev":true,"requires":{"commondir":"^1.0.1","mkdirp":"^0.5.1","pkg-dir":"^1.0.0"}},"find-up":{"version":"1.1.2","resolved":"https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz","integrity":"sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=","dev":true,"requires":{"path-exists":"^2.0.0","pinkie-promise":"^2.0.0"}},"path-exists":{"version":"2.1.0","resolved":"https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz","integrity":"sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=","dev":true,"requires":{"pinkie-promise":"^2.0.0"}},"pkg-dir":{"version":"1.0.0","resolved":"https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz","integrity":"sha1-ektQio1bstYp1EcFb/TpyTFM89Q=","dev":true,"requires":{"find-up":"^1.0.0"}}}},"loader-runner":{"version":"2.3.1","resolved":"https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.1.tgz","integrity":"sha512-By6ZFY7ETWOc9RFaAIb23IjJVcM4dvJC/N57nmdz9RSkMXvAXGI7SyVlAw3v8vjtDRlqThgVDVmTnr9fqMlxkw==","dev":true},"loader-utils":{"version":"1.1.0","resolved":"https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz","integrity":"sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=","dev":true,"requires":{"big.js":"^3.1.3","emojis-list":"^2.0.0","json5":"^0.5.0"},"dependencies":{"json5":{"version":"0.5.1","resolved":"https://registry.npmjs.org/json5/-/json5-0.5.1.tgz","integrity":"sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=","dev":true}}},"locate-path":{"version":"2.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz","integrity":"sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=","dev":true,"requires":{"p-locate":"^2.0.0","path-exists":"^3.0.0"}},"lodash":{"version":"4.17.14","resolved":"https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz","integrity":"sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==","dev":true},"lodash.debounce":{"version":"4.0.8","resolved":"https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz","integrity":"sha1-gteb/zCmfEAF/9XiUVMArZyk168=","dev":true},"lodash.flattendeep":{"version":"4.4.0","resolved":"https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz","integrity":"sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=","dev":true},"lodash.sortby":{"version":"4.7.0","resolved":"https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz","integrity":"sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=","dev":true},"loose-envify":{"version":"1.4.0","resolved":"https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz","integrity":"sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==","dev":true,"requires":{"js-tokens":"^3.0.0 || ^4.0.0"}},"lru-cache":{"version":"4.1.4","resolved":"https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.4.tgz","integrity":"sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==","dev":true,"requires":{"pseudomap":"^1.0.2","yallist":"^3.0.2"}},"make-dir":{"version":"1.3.0","resolved":"https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz","integrity":"sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==","dev":true,"requires":{"pify":"^3.0.0"}},"map-age-cleaner":{"version":"0.1.3","resolved":"https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz","integrity":"sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==","dev":true,"requires":{"p-defer":"^1.0.0"}},"map-cache":{"version":"0.2.2","resolved":"https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz","integrity":"sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=","dev":true},"map-visit":{"version":"1.0.0","resolved":"https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz","integrity":"sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=","dev":true,"requires":{"object-visit":"^1.0.0"}},"math-random":{"version":"1.0.1","resolved":"https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz","integrity":"sha1-izqsWIuKZuSXXjzepn97sylgH6w=","dev":true},"md5.js":{"version":"1.3.5","resolved":"https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz","integrity":"sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==","dev":true,"requires":{"hash-base":"^3.0.0","inherits":"^2.0.1","safe-buffer":"^5.1.2"}},"mem":{"version":"4.0.0","resolved":"https://registry.npmjs.org/mem/-/mem-4.0.0.tgz","integrity":"sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==","dev":true,"requires":{"map-age-cleaner":"^0.1.1","mimic-fn":"^1.0.0","p-is-promise":"^1.1.0"}},"memory-fs":{"version":"0.4.1","resolved":"https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz","integrity":"sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=","dev":true,"requires":{"errno":"^0.1.3","readable-stream":"^2.0.1"}},"merge-source-map":{"version":"1.1.0","resolved":"https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz","integrity":"sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==","dev":true,"requires":{"source-map":"^0.6.1"},"dependencies":{"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true}}},"micromatch":{"version":"3.1.10","resolved":"https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz","integrity":"sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==","dev":true,"requires":{"arr-diff":"^4.0.0","array-unique":"^0.3.2","braces":"^2.3.1","define-property":"^2.0.2","extend-shallow":"^3.0.2","extglob":"^2.0.4","fragment-cache":"^0.2.1","kind-of":"^6.0.2","nanomatch":"^1.2.9","object.pick":"^1.3.0","regex-not":"^1.0.0","snapdragon":"^0.8.1","to-regex":"^3.0.2"}},"miller-rabin":{"version":"4.0.1","resolved":"https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz","integrity":"sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==","dev":true,"requires":{"bn.js":"^4.0.0","brorand":"^1.0.1"}},"mime":{"version":"1.6.0","resolved":"https://registry.npmjs.org/mime/-/mime-1.6.0.tgz","integrity":"sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==","dev":true},"mime-db":{"version":"1.37.0","resolved":"https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz","integrity":"sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==","dev":true},"mime-types":{"version":"2.1.21","resolved":"https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz","integrity":"sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==","dev":true,"requires":{"mime-db":"~1.37.0"}},"mimic-fn":{"version":"1.2.0","resolved":"https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz","integrity":"sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==","dev":true},"minimalistic-assert":{"version":"1.0.1","resolved":"https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz","integrity":"sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==","dev":true},"minimalistic-crypto-utils":{"version":"1.0.1","resolved":"https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz","integrity":"sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=","dev":true},"minimatch":{"version":"3.0.4","resolved":"https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz","integrity":"sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==","dev":true,"requires":{"brace-expansion":"^1.1.7"}},"minimist":{"version":"0.0.8","resolved":"https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz","integrity":"sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=","dev":true},"mississippi":{"version":"2.0.0","resolved":"https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz","integrity":"sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==","dev":true,"requires":{"concat-stream":"^1.5.0","duplexify":"^3.4.2","end-of-stream":"^1.1.0","flush-write-stream":"^1.0.0","from2":"^2.1.0","parallel-transform":"^1.1.0","pump":"^2.0.1","pumpify":"^1.3.3","stream-each":"^1.1.0","through2":"^2.0.0"}},"mixin-deep":{"version":"1.3.2","resolved":"https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz","integrity":"sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==","dev":true,"requires":{"for-in":"^1.0.2","is-extendable":"^1.0.1"},"dependencies":{"is-extendable":{"version":"1.0.1","resolved":"https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz","integrity":"sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==","dev":true,"requires":{"is-plain-object":"^2.0.4"}}}},"mkdirp":{"version":"0.5.1","resolved":"http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz","integrity":"sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=","dev":true,"requires":{"minimist":"0.0.8"}},"mocha":{"version":"4.1.0","resolved":"https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz","integrity":"sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==","dev":true,"requires":{"browser-stdout":"1.3.0","commander":"2.11.0","debug":"3.1.0","diff":"3.3.1","escape-string-regexp":"1.0.5","glob":"7.1.2","growl":"1.10.3","he":"1.1.1","mkdirp":"0.5.1","supports-color":"4.4.0"},"dependencies":{"commander":{"version":"2.11.0","resolved":"https://registry.npmjs.org/commander/-/commander-2.11.0.tgz","integrity":"sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==","dev":true},"debug":{"version":"3.1.0","resolved":"https://registry.npmjs.org/debug/-/debug-3.1.0.tgz","integrity":"sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==","dev":true,"requires":{"ms":"2.0.0"}},"glob":{"version":"7.1.2","resolved":"https://registry.npmjs.org/glob/-/glob-7.1.2.tgz","integrity":"sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==","dev":true,"requires":{"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"}},"has-flag":{"version":"2.0.0","resolved":"https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz","integrity":"sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=","dev":true},"ms":{"version":"2.0.0","resolved":"https://registry.npmjs.org/ms/-/ms-2.0.0.tgz","integrity":"sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=","dev":true},"supports-color":{"version":"4.4.0","resolved":"https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz","integrity":"sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==","dev":true,"requires":{"has-flag":"^2.0.0"}}}},"move-concurrently":{"version":"1.0.1","resolved":"https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz","integrity":"sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=","dev":true,"requires":{"aproba":"^1.1.1","copy-concurrently":"^1.0.0","fs-write-stream-atomic":"^1.0.8","mkdirp":"^0.5.1","rimraf":"^2.5.4","run-queue":"^1.0.3"}},"ms":{"version":"2.1.1","resolved":"https://registry.npmjs.org/ms/-/ms-2.1.1.tgz","integrity":"sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==","dev":true},"mute-stream":{"version":"0.0.7","resolved":"https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz","integrity":"sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=","dev":true},"nan":{"version":"2.14.0","resolved":"https://registry.npmjs.org/nan/-/nan-2.14.0.tgz","integrity":"sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==","dev":true,"optional":true},"nanomatch":{"version":"1.2.13","resolved":"https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz","integrity":"sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==","dev":true,"requires":{"arr-diff":"^4.0.0","array-unique":"^0.3.2","define-property":"^2.0.2","extend-shallow":"^3.0.2","fragment-cache":"^0.2.1","is-windows":"^1.0.2","kind-of":"^6.0.2","object.pick":"^1.3.0","regex-not":"^1.0.0","snapdragon":"^0.8.1","to-regex":"^3.0.1"}},"natural-compare":{"version":"1.4.0","resolved":"https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz","integrity":"sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=","dev":true},"neo-async":{"version":"2.6.0","resolved":"https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz","integrity":"sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==","dev":true},"nested-error-stacks":{"version":"2.1.0","resolved":"https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz","integrity":"sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==","dev":true},"nice-try":{"version":"1.0.5","resolved":"https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz","integrity":"sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==","dev":true},"node-libs-browser":{"version":"2.1.0","resolved":"https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz","integrity":"sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==","dev":true,"requires":{"assert":"^1.1.1","browserify-zlib":"^0.2.0","buffer":"^4.3.0","console-browserify":"^1.1.0","constants-browserify":"^1.0.0","crypto-browserify":"^3.11.0","domain-browser":"^1.1.1","events":"^1.0.0","https-browserify":"^1.0.0","os-browserify":"^0.3.0","path-browserify":"0.0.0","process":"^0.11.10","punycode":"^1.2.4","querystring-es3":"^0.2.0","readable-stream":"^2.3.3","stream-browserify":"^2.0.1","stream-http":"^2.7.2","string_decoder":"^1.0.0","timers-browserify":"^2.0.4","tty-browserify":"0.0.0","url":"^0.11.0","util":"^0.10.3","vm-browserify":"0.0.4"},"dependencies":{"punycode":{"version":"1.4.1","resolved":"https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz","integrity":"sha1-wNWmOycYgArY4esPpSachN1BhF4=","dev":true}}},"node-modules-regexp":{"version":"1.0.0","resolved":"https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz","integrity":"sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=","dev":true},"node-releases":{"version":"1.0.4","resolved":"https://registry.npmjs.org/node-releases/-/node-releases-1.0.4.tgz","integrity":"sha512-GqRV9GcHw8JCRDaP/JoeNMNzEGzHAknMvIHqMb2VeTOmg1Cf9+ej8bkV12tHfzWHQMCkQ5zUFgwFUkfraynNCw==","dev":true,"requires":{"semver":"^5.3.0"}},"normalize-package-data":{"version":"2.4.0","resolved":"https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz","integrity":"sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==","dev":true,"requires":{"hosted-git-info":"^2.1.4","is-builtin-module":"^1.0.0","semver":"2 || 3 || 4 || 5","validate-npm-package-license":"^3.0.1"}},"normalize-path":{"version":"2.1.1","resolved":"https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz","integrity":"sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=","dev":true,"requires":{"remove-trailing-separator":"^1.0.1"}},"npm-run-path":{"version":"2.0.2","resolved":"https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz","integrity":"sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=","dev":true,"requires":{"path-key":"^2.0.0"}},"number-is-nan":{"version":"1.0.1","resolved":"https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz","integrity":"sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=","dev":true},"nwsapi":{"version":"2.0.9","resolved":"https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz","integrity":"sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==","dev":true},"nyc":{"version":"14.1.1","resolved":"https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz","integrity":"sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==","dev":true,"requires":{"archy":"^1.0.0","caching-transform":"^3.0.2","convert-source-map":"^1.6.0","cp-file":"^6.2.0","find-cache-dir":"^2.1.0","find-up":"^3.0.0","foreground-child":"^1.5.6","glob":"^7.1.3","istanbul-lib-coverage":"^2.0.5","istanbul-lib-hook":"^2.0.7","istanbul-lib-instrument":"^3.3.0","istanbul-lib-report":"^2.0.8","istanbul-lib-source-maps":"^3.0.6","istanbul-reports":"^2.2.4","js-yaml":"^3.13.1","make-dir":"^2.1.0","merge-source-map":"^1.1.0","resolve-from":"^4.0.0","rimraf":"^2.6.3","signal-exit":"^3.0.2","spawn-wrap":"^1.4.2","test-exclude":"^5.2.3","uuid":"^3.3.2","yargs":"^13.2.2","yargs-parser":"^13.0.0"},"dependencies":{"@babel/generator":{"version":"7.4.4","resolved":"https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz","integrity":"sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==","dev":true,"requires":{"@babel/types":"^7.4.4","jsesc":"^2.5.1","lodash":"^4.17.11","source-map":"^0.5.0","trim-right":"^1.0.1"}},"@babel/helper-split-export-declaration":{"version":"7.4.4","resolved":"https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz","integrity":"sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==","dev":true,"requires":{"@babel/types":"^7.4.4"}},"@babel/parser":{"version":"7.4.5","resolved":"https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz","integrity":"sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==","dev":true},"@babel/template":{"version":"7.4.4","resolved":"https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz","integrity":"sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==","dev":true,"requires":{"@babel/code-frame":"^7.0.0","@babel/parser":"^7.4.4","@babel/types":"^7.4.4"}},"@babel/traverse":{"version":"7.4.5","resolved":"https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz","integrity":"sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==","dev":true,"requires":{"@babel/code-frame":"^7.0.0","@babel/generator":"^7.4.4","@babel/helper-function-name":"^7.1.0","@babel/helper-split-export-declaration":"^7.4.4","@babel/parser":"^7.4.5","@babel/types":"^7.4.4","debug":"^4.1.0","globals":"^11.1.0","lodash":"^4.17.11"}},"@babel/types":{"version":"7.4.4","resolved":"https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz","integrity":"sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==","dev":true,"requires":{"esutils":"^2.0.2","lodash":"^4.17.11","to-fast-properties":"^2.0.0"}},"ansi-regex":{"version":"4.1.0","resolved":"https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz","integrity":"sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==","dev":true},"cliui":{"version":"5.0.0","resolved":"https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz","integrity":"sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==","dev":true,"requires":{"string-width":"^3.1.0","strip-ansi":"^5.2.0","wrap-ansi":"^5.1.0"}},"execa":{"version":"1.0.0","resolved":"https://registry.npmjs.org/execa/-/execa-1.0.0.tgz","integrity":"sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==","dev":true,"requires":{"cross-spawn":"^6.0.0","get-stream":"^4.0.0","is-stream":"^1.1.0","npm-run-path":"^2.0.0","p-finally":"^1.0.0","signal-exit":"^3.0.0","strip-eof":"^1.0.0"}},"find-cache-dir":{"version":"2.1.0","resolved":"https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz","integrity":"sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==","dev":true,"requires":{"commondir":"^1.0.1","make-dir":"^2.0.0","pkg-dir":"^3.0.0"}},"find-up":{"version":"3.0.0","resolved":false,"integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"get-caller-file":{"version":"2.0.5","resolved":"https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz","integrity":"sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==","dev":true},"get-stream":{"version":"4.1.0","resolved":"https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz","integrity":"sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==","dev":true,"requires":{"pump":"^3.0.0"}},"istanbul-lib-coverage":{"version":"2.0.5","resolved":"https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz","integrity":"sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==","dev":true},"istanbul-lib-instrument":{"version":"3.3.0","resolved":"https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz","integrity":"sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==","dev":true,"requires":{"@babel/generator":"^7.4.0","@babel/parser":"^7.4.3","@babel/template":"^7.4.0","@babel/traverse":"^7.4.3","@babel/types":"^7.4.0","istanbul-lib-coverage":"^2.0.5","semver":"^6.0.0"},"dependencies":{"semver":{"version":"6.1.1","resolved":"https://registry.npmjs.org/semver/-/semver-6.1.1.tgz","integrity":"sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==","dev":true}}},"locate-path":{"version":"3.0.0","resolved":false,"integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"make-dir":{"version":"2.1.0","resolved":"https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz","integrity":"sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==","dev":true,"requires":{"pify":"^4.0.1","semver":"^5.6.0"}},"os-locale":{"version":"3.1.0","resolved":"https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz","integrity":"sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==","dev":true,"requires":{"execa":"^1.0.0","lcid":"^2.0.0","mem":"^4.0.0"}},"p-limit":{"version":"2.2.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz","integrity":"sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":false,"integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.2.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz","integrity":"sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==","dev":true},"pify":{"version":"4.0.1","resolved":"https://registry.npmjs.org/pify/-/pify-4.0.1.tgz","integrity":"sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==","dev":true},"pkg-dir":{"version":"3.0.0","resolved":false,"integrity":"sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==","dev":true,"requires":{"find-up":"^3.0.0"}},"pump":{"version":"3.0.0","resolved":"https://registry.npmjs.org/pump/-/pump-3.0.0.tgz","integrity":"sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==","dev":true,"requires":{"end-of-stream":"^1.1.0","once":"^1.3.1"}},"require-main-filename":{"version":"2.0.0","resolved":"https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz","integrity":"sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==","dev":true},"resolve-from":{"version":"4.0.0","resolved":false,"integrity":"sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==","dev":true},"rimraf":{"version":"2.6.3","resolved":"https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz","integrity":"sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==","dev":true,"requires":{"glob":"^7.1.3"}},"string-width":{"version":"3.1.0","resolved":"https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz","integrity":"sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==","dev":true,"requires":{"emoji-regex":"^7.0.1","is-fullwidth-code-point":"^2.0.0","strip-ansi":"^5.1.0"}},"strip-ansi":{"version":"5.2.0","resolved":"https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz","integrity":"sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==","dev":true,"requires":{"ansi-regex":"^4.1.0"}},"test-exclude":{"version":"5.2.3","resolved":"https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz","integrity":"sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==","dev":true,"requires":{"glob":"^7.1.3","minimatch":"^3.0.4","read-pkg-up":"^4.0.0","require-main-filename":"^2.0.0"}},"wrap-ansi":{"version":"5.1.0","resolved":"https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz","integrity":"sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==","dev":true,"requires":{"ansi-styles":"^3.2.0","string-width":"^3.0.0","strip-ansi":"^5.0.0"}},"yargs":{"version":"13.2.4","resolved":"https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz","integrity":"sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==","dev":true,"requires":{"cliui":"^5.0.0","find-up":"^3.0.0","get-caller-file":"^2.0.1","os-locale":"^3.1.0","require-directory":"^2.1.1","require-main-filename":"^2.0.0","set-blocking":"^2.0.0","string-width":"^3.0.0","which-module":"^2.0.0","y18n":"^4.0.0","yargs-parser":"^13.1.0"}},"yargs-parser":{"version":"13.1.1","resolved":"https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz","integrity":"sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==","dev":true,"requires":{"camelcase":"^5.0.0","decamelize":"^1.2.0"}}}},"oauth-sign":{"version":"0.9.0","resolved":"https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz","integrity":"sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==","dev":true},"object-assign":{"version":"4.1.1","resolved":"https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz","integrity":"sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=","dev":true},"object-copy":{"version":"0.1.0","resolved":"https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz","integrity":"sha1-fn2Fi3gb18mRpBupde04EnVOmYw=","dev":true,"requires":{"copy-descriptor":"^0.1.0","define-property":"^0.2.5","kind-of":"^3.0.3"},"dependencies":{"define-property":{"version":"0.2.5","resolved":"https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz","integrity":"sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=","dev":true,"requires":{"is-descriptor":"^0.1.0"}},"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"object-hash":{"version":"1.3.1","resolved":"https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz","integrity":"sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==","dev":true},"object-keys":{"version":"1.0.12","resolved":"https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz","integrity":"sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==","dev":true},"object-visit":{"version":"1.0.1","resolved":"https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz","integrity":"sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=","dev":true,"requires":{"isobject":"^3.0.0"}},"object.getownpropertydescriptors":{"version":"2.0.3","resolved":"https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz","integrity":"sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=","dev":true,"requires":{"define-properties":"^1.1.2","es-abstract":"^1.5.1"}},"object.omit":{"version":"2.0.1","resolved":"https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz","integrity":"sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=","dev":true,"requires":{"for-own":"^0.1.4","is-extendable":"^0.1.1"}},"object.pick":{"version":"1.3.0","resolved":"https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz","integrity":"sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=","dev":true,"requires":{"isobject":"^3.0.1"}},"once":{"version":"1.4.0","resolved":"https://registry.npmjs.org/once/-/once-1.4.0.tgz","integrity":"sha1-WDsap3WWHUsROsF9nFC6753Xa9E=","dev":true,"requires":{"wrappy":"1"}},"onetime":{"version":"2.0.1","resolved":"https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz","integrity":"sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=","dev":true,"requires":{"mimic-fn":"^1.0.0"}},"opener":{"version":"1.4.3","resolved":"https://registry.npmjs.org/opener/-/opener-1.4.3.tgz","integrity":"sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=","dev":true},"optimist":{"version":"0.6.1","resolved":"https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz","integrity":"sha1-2j6nRob6IaGaERwybpDrFaAZZoY=","dev":true,"requires":{"minimist":"~0.0.1","wordwrap":"~0.0.2"},"dependencies":{"wordwrap":{"version":"0.0.3","resolved":"https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz","integrity":"sha1-o9XabNXAvAAI03I0u68b7WMFkQc=","dev":true}}},"optionator":{"version":"0.8.2","resolved":"https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz","integrity":"sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=","dev":true,"requires":{"deep-is":"~0.1.3","fast-levenshtein":"~2.0.4","levn":"~0.3.0","prelude-ls":"~1.1.2","type-check":"~0.3.2","wordwrap":"~1.0.0"}},"os-browserify":{"version":"0.3.0","resolved":"https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz","integrity":"sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=","dev":true},"os-homedir":{"version":"1.0.2","resolved":"https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz","integrity":"sha1-/7xJiDNuDoM94MFox+8VISGqf7M=","dev":true},"os-locale":{"version":"3.0.1","resolved":"https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz","integrity":"sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==","dev":true,"requires":{"execa":"^0.10.0","lcid":"^2.0.0","mem":"^4.0.0"}},"os-tmpdir":{"version":"1.0.2","resolved":"http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz","integrity":"sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=","dev":true},"output-file-sync":{"version":"2.0.1","resolved":"https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz","integrity":"sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ==","dev":true,"requires":{"graceful-fs":"^4.1.11","is-plain-obj":"^1.1.0","mkdirp":"^0.5.1"}},"p-defer":{"version":"1.0.0","resolved":"https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz","integrity":"sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=","dev":true},"p-finally":{"version":"1.0.0","resolved":"https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz","integrity":"sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=","dev":true},"p-is-promise":{"version":"1.1.0","resolved":"http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz","integrity":"sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=","dev":true},"p-limit":{"version":"1.3.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz","integrity":"sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==","dev":true,"requires":{"p-try":"^1.0.0"}},"p-locate":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz","integrity":"sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=","dev":true,"requires":{"p-limit":"^1.1.0"}},"p-try":{"version":"1.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz","integrity":"sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=","dev":true},"package-hash":{"version":"3.0.0","resolved":"https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz","integrity":"sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==","dev":true,"requires":{"graceful-fs":"^4.1.15","hasha":"^3.0.0","lodash.flattendeep":"^4.4.0","release-zalgo":"^1.0.0"}},"pako":{"version":"1.0.6","resolved":"https://registry.npmjs.org/pako/-/pako-1.0.6.tgz","integrity":"sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==","dev":true},"parallel-transform":{"version":"1.1.0","resolved":"https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz","integrity":"sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=","dev":true,"requires":{"cyclist":"~0.2.2","inherits":"^2.0.3","readable-stream":"^2.1.5"}},"parse-asn1":{"version":"5.1.1","resolved":"http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz","integrity":"sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==","dev":true,"requires":{"asn1.js":"^4.0.0","browserify-aes":"^1.0.0","create-hash":"^1.1.0","evp_bytestokey":"^1.0.0","pbkdf2":"^3.0.3"}},"parse-glob":{"version":"3.0.4","resolved":"https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz","integrity":"sha1-ssN2z7EfNVE7rdFz7wu246OIORw=","dev":true,"requires":{"glob-base":"^0.3.0","is-dotfile":"^1.0.0","is-extglob":"^1.0.0","is-glob":"^2.0.0"},"dependencies":{"is-extglob":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz","integrity":"sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=","dev":true},"is-glob":{"version":"2.0.1","resolved":"https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz","integrity":"sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=","dev":true,"requires":{"is-extglob":"^1.0.0"}}}},"parse-json":{"version":"4.0.0","resolved":"https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz","integrity":"sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=","dev":true,"requires":{"error-ex":"^1.3.1","json-parse-better-errors":"^1.0.1"}},"parse5":{"version":"4.0.0","resolved":"https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz","integrity":"sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==","dev":true},"pascalcase":{"version":"0.1.1","resolved":"https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz","integrity":"sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=","dev":true},"path-browserify":{"version":"0.0.0","resolved":"https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz","integrity":"sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=","dev":true},"path-dirname":{"version":"1.0.2","resolved":"https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz","integrity":"sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=","dev":true},"path-exists":{"version":"3.0.0","resolved":"https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz","integrity":"sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=","dev":true},"path-is-absolute":{"version":"1.0.1","resolved":"http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz","integrity":"sha1-F0uSaHNVNP+8es5r9TpanhtcX18=","dev":true},"path-is-inside":{"version":"1.0.2","resolved":"https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz","integrity":"sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=","dev":true},"path-key":{"version":"2.0.1","resolved":"https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz","integrity":"sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=","dev":true},"path-parse":{"version":"1.0.6","resolved":"https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz","integrity":"sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==","dev":true},"path-type":{"version":"3.0.0","resolved":"https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz","integrity":"sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==","dev":true,"requires":{"pify":"^3.0.0"}},"pathval":{"version":"1.1.0","resolved":"https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz","integrity":"sha1-uULm1L3mUwBe9rcTYd74cn0GReA=","dev":true},"pbkdf2":{"version":"3.0.17","resolved":"https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz","integrity":"sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==","dev":true,"requires":{"create-hash":"^1.1.2","create-hmac":"^1.1.4","ripemd160":"^2.0.1","safe-buffer":"^5.0.1","sha.js":"^2.4.8"}},"performance-now":{"version":"2.1.0","resolved":"https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz","integrity":"sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=","dev":true},"pify":{"version":"3.0.0","resolved":"https://registry.npmjs.org/pify/-/pify-3.0.0.tgz","integrity":"sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=","dev":true},"pinkie":{"version":"2.0.4","resolved":"https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz","integrity":"sha1-clVrgM+g1IqXToDnckjoDtT3+HA=","dev":true},"pinkie-promise":{"version":"2.0.1","resolved":"https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz","integrity":"sha1-ITXW36ejWMBprJsXh3YogihFD/o=","dev":true,"requires":{"pinkie":"^2.0.0"}},"pirates":{"version":"3.0.2","resolved":"https://registry.npmjs.org/pirates/-/pirates-3.0.2.tgz","integrity":"sha512-c5CgUJq6H2k6MJz72Ak1F5sN9n9wlSlJyEnwvpm9/y3WB4E3pHBDT2c6PEiS1vyJvq2bUxUAIu0EGf8Cx4Ic7Q==","dev":true,"requires":{"node-modules-regexp":"^1.0.0"}},"pkg-dir":{"version":"2.0.0","resolved":"https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz","integrity":"sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=","dev":true,"requires":{"find-up":"^2.1.0"}},"pluralize":{"version":"7.0.0","resolved":"https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz","integrity":"sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==","dev":true},"pn":{"version":"1.1.0","resolved":"https://registry.npmjs.org/pn/-/pn-1.1.0.tgz","integrity":"sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==","dev":true},"portfinder":{"version":"1.0.20","resolved":"https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz","integrity":"sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==","dev":true,"requires":{"async":"^1.5.2","debug":"^2.2.0","mkdirp":"0.5.x"},"dependencies":{"debug":{"version":"2.6.9","resolved":"https://registry.npmjs.org/debug/-/debug-2.6.9.tgz","integrity":"sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==","dev":true,"requires":{"ms":"2.0.0"}},"ms":{"version":"2.0.0","resolved":"https://registry.npmjs.org/ms/-/ms-2.0.0.tgz","integrity":"sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=","dev":true}}},"posix-character-classes":{"version":"0.1.1","resolved":"https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz","integrity":"sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=","dev":true},"prelude-ls":{"version":"1.1.2","resolved":"https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz","integrity":"sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=","dev":true},"preserve":{"version":"0.2.0","resolved":"https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz","integrity":"sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=","dev":true},"private":{"version":"0.1.8","resolved":"https://registry.npmjs.org/private/-/private-0.1.8.tgz","integrity":"sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==","dev":true},"process":{"version":"0.11.10","resolved":"https://registry.npmjs.org/process/-/process-0.11.10.tgz","integrity":"sha1-czIwDoQBYb2j5podHZGn1LwW8YI=","dev":true},"process-nextick-args":{"version":"2.0.0","resolved":"https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz","integrity":"sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==","dev":true},"progress":{"version":"2.0.1","resolved":"https://registry.npmjs.org/progress/-/progress-2.0.1.tgz","integrity":"sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==","dev":true},"promise-inflight":{"version":"1.0.1","resolved":"https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz","integrity":"sha1-mEcocL8igTL8vdhoEputEsPAKeM=","dev":true},"prr":{"version":"1.0.1","resolved":"https://registry.npmjs.org/prr/-/prr-1.0.1.tgz","integrity":"sha1-0/wRS6BplaRexok/SEzrHXj19HY=","dev":true},"pseudomap":{"version":"1.0.2","resolved":"https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz","integrity":"sha1-8FKijacOYYkX7wqKw0wa5aaChrM=","dev":true},"psl":{"version":"1.1.29","resolved":"https://registry.npmjs.org/psl/-/psl-1.1.29.tgz","integrity":"sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==","dev":true},"public-encrypt":{"version":"4.0.3","resolved":"https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz","integrity":"sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==","dev":true,"requires":{"bn.js":"^4.1.0","browserify-rsa":"^4.0.0","create-hash":"^1.1.0","parse-asn1":"^5.0.0","randombytes":"^2.0.1","safe-buffer":"^5.1.2"}},"pump":{"version":"2.0.1","resolved":"https://registry.npmjs.org/pump/-/pump-2.0.1.tgz","integrity":"sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==","dev":true,"requires":{"end-of-stream":"^1.1.0","once":"^1.3.1"}},"pumpify":{"version":"1.5.1","resolved":"https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz","integrity":"sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==","dev":true,"requires":{"duplexify":"^3.6.0","inherits":"^2.0.3","pump":"^2.0.0"}},"punycode":{"version":"2.1.1","resolved":"https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz","integrity":"sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==","dev":true},"qs":{"version":"6.5.2","resolved":"https://registry.npmjs.org/qs/-/qs-6.5.2.tgz","integrity":"sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==","dev":true},"querystring":{"version":"0.2.0","resolved":"https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz","integrity":"sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=","dev":true},"querystring-es3":{"version":"0.2.1","resolved":"https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz","integrity":"sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=","dev":true},"randomatic":{"version":"3.1.1","resolved":"https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz","integrity":"sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==","dev":true,"requires":{"is-number":"^4.0.0","kind-of":"^6.0.0","math-random":"^1.0.1"},"dependencies":{"is-number":{"version":"4.0.0","resolved":"https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz","integrity":"sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==","dev":true}}},"randombytes":{"version":"2.0.6","resolved":"https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz","integrity":"sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==","dev":true,"requires":{"safe-buffer":"^5.1.0"}},"randomfill":{"version":"1.0.4","resolved":"https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz","integrity":"sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==","dev":true,"requires":{"randombytes":"^2.0.5","safe-buffer":"^5.1.0"}},"read-pkg":{"version":"3.0.0","resolved":"https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz","integrity":"sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=","dev":true,"requires":{"load-json-file":"^4.0.0","normalize-package-data":"^2.3.2","path-type":"^3.0.0"}},"read-pkg-up":{"version":"4.0.0","resolved":"https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz","integrity":"sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==","dev":true,"requires":{"find-up":"^3.0.0","read-pkg":"^3.0.0"},"dependencies":{"find-up":{"version":"3.0.0","resolved":"https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz","integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"locate-path":{"version":"3.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz","integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"p-limit":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz","integrity":"sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz","integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz","integrity":"sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==","dev":true}}},"readable-stream":{"version":"2.3.6","resolved":"http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz","integrity":"sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==","dev":true,"requires":{"core-util-is":"~1.0.0","inherits":"~2.0.3","isarray":"~1.0.0","process-nextick-args":"~2.0.0","safe-buffer":"~5.1.1","string_decoder":"~1.1.1","util-deprecate":"~1.0.1"}},"readdirp":{"version":"2.2.1","resolved":"https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz","integrity":"sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==","dev":true,"requires":{"graceful-fs":"^4.1.11","micromatch":"^3.1.10","readable-stream":"^2.0.2"}},"regenerate":{"version":"1.4.0","resolved":"https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz","integrity":"sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==","dev":true},"regenerate-unicode-properties":{"version":"7.0.0","resolved":"https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz","integrity":"sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==","dev":true,"requires":{"regenerate":"^1.4.0"}},"regenerator-runtime":{"version":"0.11.1","resolved":"https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz","integrity":"sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==","dev":true},"regenerator-transform":{"version":"0.13.3","resolved":"https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz","integrity":"sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==","dev":true,"requires":{"private":"^0.1.6"}},"regex-cache":{"version":"0.4.4","resolved":"https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz","integrity":"sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==","dev":true,"requires":{"is-equal-shallow":"^0.1.3"}},"regex-not":{"version":"1.0.2","resolved":"https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz","integrity":"sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==","dev":true,"requires":{"extend-shallow":"^3.0.2","safe-regex":"^1.1.0"}},"regexpp":{"version":"2.0.1","resolved":"https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz","integrity":"sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==","dev":true},"regexpu-core":{"version":"4.2.0","resolved":"https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz","integrity":"sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==","dev":true,"requires":{"regenerate":"^1.4.0","regenerate-unicode-properties":"^7.0.0","regjsgen":"^0.4.0","regjsparser":"^0.3.0","unicode-match-property-ecmascript":"^1.0.4","unicode-match-property-value-ecmascript":"^1.0.2"}},"regjsgen":{"version":"0.4.0","resolved":"https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz","integrity":"sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA==","dev":true},"regjsparser":{"version":"0.3.0","resolved":"https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz","integrity":"sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==","dev":true,"requires":{"jsesc":"~0.5.0"},"dependencies":{"jsesc":{"version":"0.5.0","resolved":"https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz","integrity":"sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=","dev":true}}},"release-zalgo":{"version":"1.0.0","resolved":"https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz","integrity":"sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=","dev":true,"requires":{"es6-error":"^4.0.1"}},"remove-trailing-separator":{"version":"1.1.0","resolved":"https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz","integrity":"sha1-wkvOKig62tW8P1jg1IJJuSN52O8=","dev":true},"repeat-element":{"version":"1.1.3","resolved":"https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz","integrity":"sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==","dev":true},"repeat-string":{"version":"1.6.1","resolved":"https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz","integrity":"sha1-jcrkcOHIirwtYA//Sndihtp15jc=","dev":true},"request":{"version":"2.88.0","resolved":"https://registry.npmjs.org/request/-/request-2.88.0.tgz","integrity":"sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==","dev":true,"requires":{"aws-sign2":"~0.7.0","aws4":"^1.8.0","caseless":"~0.12.0","combined-stream":"~1.0.6","extend":"~3.0.2","forever-agent":"~0.6.1","form-data":"~2.3.2","har-validator":"~5.1.0","http-signature":"~1.2.0","is-typedarray":"~1.0.0","isstream":"~0.1.2","json-stringify-safe":"~5.0.1","mime-types":"~2.1.19","oauth-sign":"~0.9.0","performance-now":"^2.1.0","qs":"~6.5.2","safe-buffer":"^5.1.2","tough-cookie":"~2.4.3","tunnel-agent":"^0.6.0","uuid":"^3.3.2"}},"request-promise-core":{"version":"1.1.1","resolved":"https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz","integrity":"sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=","dev":true,"requires":{"lodash":"^4.13.1"}},"request-promise-native":{"version":"1.0.5","resolved":"https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz","integrity":"sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=","dev":true,"requires":{"request-promise-core":"1.1.1","stealthy-require":"^1.1.0","tough-cookie":">=2.3.3"}},"require-directory":{"version":"2.1.1","resolved":"https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz","integrity":"sha1-jGStX9MNqxyXbiNE/+f3kqam30I=","dev":true},"require-main-filename":{"version":"1.0.1","resolved":"https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz","integrity":"sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=","dev":true},"require-uncached":{"version":"1.0.3","resolved":"http://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz","integrity":"sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=","dev":true,"requires":{"caller-path":"^0.1.0","resolve-from":"^1.0.0"}},"requires-port":{"version":"1.0.0","resolved":"https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz","integrity":"sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=","dev":true},"resolve":{"version":"1.8.1","resolved":"https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz","integrity":"sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==","dev":true,"requires":{"path-parse":"^1.0.5"}},"resolve-cwd":{"version":"2.0.0","resolved":"https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz","integrity":"sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=","dev":true,"requires":{"resolve-from":"^3.0.0"},"dependencies":{"resolve-from":{"version":"3.0.0","resolved":"https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz","integrity":"sha1-six699nWiBvItuZTM17rywoYh0g=","dev":true}}},"resolve-from":{"version":"1.0.1","resolved":"https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz","integrity":"sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=","dev":true},"resolve-url":{"version":"0.2.1","resolved":"https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz","integrity":"sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=","dev":true},"restore-cursor":{"version":"2.0.0","resolved":"https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz","integrity":"sha1-n37ih/gv0ybU/RYpI9YhKe7g368=","dev":true,"requires":{"onetime":"^2.0.0","signal-exit":"^3.0.2"}},"ret":{"version":"0.1.15","resolved":"https://registry.npmjs.org/ret/-/ret-0.1.15.tgz","integrity":"sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==","dev":true},"rimraf":{"version":"2.6.2","resolved":"https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz","integrity":"sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==","dev":true,"requires":{"glob":"^7.0.5"}},"ripemd160":{"version":"2.0.2","resolved":"https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz","integrity":"sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==","dev":true,"requires":{"hash-base":"^3.0.0","inherits":"^2.0.1"}},"run-async":{"version":"2.3.0","resolved":"https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz","integrity":"sha1-A3GrSuC91yDUFm19/aZP96RFpsA=","dev":true,"requires":{"is-promise":"^2.1.0"}},"run-queue":{"version":"1.0.3","resolved":"https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz","integrity":"sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=","dev":true,"requires":{"aproba":"^1.1.1"}},"rxjs":{"version":"6.3.3","resolved":"https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz","integrity":"sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==","dev":true,"requires":{"tslib":"^1.9.0"}},"safe-buffer":{"version":"5.1.2","resolved":"https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz","integrity":"sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==","dev":true},"safe-regex":{"version":"1.1.0","resolved":"http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz","integrity":"sha1-QKNmnzsHfR6UPURinhV91IAjvy4=","dev":true,"requires":{"ret":"~0.1.10"}},"safer-buffer":{"version":"2.1.2","resolved":"https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz","integrity":"sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==","dev":true},"sax":{"version":"1.2.4","resolved":"https://registry.npmjs.org/sax/-/sax-1.2.4.tgz","integrity":"sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==","dev":true},"schema-utils":{"version":"0.4.7","resolved":"https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz","integrity":"sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==","dev":true,"requires":{"ajv":"^6.1.0","ajv-keywords":"^3.1.0"}},"semver":{"version":"5.6.0","resolved":"https://registry.npmjs.org/semver/-/semver-5.6.0.tgz","integrity":"sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==","dev":true},"serialize-javascript":{"version":"1.5.0","resolved":"https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz","integrity":"sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==","dev":true},"set-blocking":{"version":"2.0.0","resolved":"https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz","integrity":"sha1-BF+XgtARrppoA93TgrJDkrPYkPc=","dev":true},"set-value":{"version":"2.0.1","resolved":"https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz","integrity":"sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==","dev":true,"requires":{"extend-shallow":"^2.0.1","is-extendable":"^0.1.1","is-plain-object":"^2.0.3","split-string":"^3.0.1"},"dependencies":{"extend-shallow":{"version":"2.0.1","resolved":"https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz","integrity":"sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=","dev":true,"requires":{"is-extendable":"^0.1.0"}}}},"setimmediate":{"version":"1.0.5","resolved":"https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz","integrity":"sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=","dev":true},"sha.js":{"version":"2.4.11","resolved":"http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz","integrity":"sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==","dev":true,"requires":{"inherits":"^2.0.1","safe-buffer":"^5.0.1"}},"shebang-command":{"version":"1.2.0","resolved":"https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz","integrity":"sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=","dev":true,"requires":{"shebang-regex":"^1.0.0"}},"shebang-regex":{"version":"1.0.0","resolved":"https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz","integrity":"sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=","dev":true},"signal-exit":{"version":"3.0.2","resolved":"https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz","integrity":"sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=","dev":true},"slash":{"version":"2.0.0","resolved":"https://registry.npmjs.org/slash/-/slash-2.0.0.tgz","integrity":"sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==","dev":true},"slice-ansi":{"version":"1.0.0","resolved":"https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz","integrity":"sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==","dev":true,"requires":{"is-fullwidth-code-point":"^2.0.0"}},"snapdragon":{"version":"0.8.2","resolved":"https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz","integrity":"sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==","dev":true,"requires":{"base":"^0.11.1","debug":"^2.2.0","define-property":"^0.2.5","extend-shallow":"^2.0.1","map-cache":"^0.2.2","source-map":"^0.5.6","source-map-resolve":"^0.5.0","use":"^3.1.0"},"dependencies":{"debug":{"version":"2.6.9","resolved":"https://registry.npmjs.org/debug/-/debug-2.6.9.tgz","integrity":"sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==","dev":true,"requires":{"ms":"2.0.0"}},"define-property":{"version":"0.2.5","resolved":"https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz","integrity":"sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=","dev":true,"requires":{"is-descriptor":"^0.1.0"}},"extend-shallow":{"version":"2.0.1","resolved":"https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz","integrity":"sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=","dev":true,"requires":{"is-extendable":"^0.1.0"}},"ms":{"version":"2.0.0","resolved":"https://registry.npmjs.org/ms/-/ms-2.0.0.tgz","integrity":"sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=","dev":true}}},"snapdragon-node":{"version":"2.1.1","resolved":"https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz","integrity":"sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==","dev":true,"requires":{"define-property":"^1.0.0","isobject":"^3.0.0","snapdragon-util":"^3.0.1"},"dependencies":{"define-property":{"version":"1.0.0","resolved":"https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz","integrity":"sha1-dp66rz9KY6rTr56NMEybvnm/sOY=","dev":true,"requires":{"is-descriptor":"^1.0.0"}},"is-accessor-descriptor":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz","integrity":"sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==","dev":true,"requires":{"kind-of":"^6.0.0"}},"is-data-descriptor":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz","integrity":"sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==","dev":true,"requires":{"kind-of":"^6.0.0"}},"is-descriptor":{"version":"1.0.2","resolved":"https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz","integrity":"sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==","dev":true,"requires":{"is-accessor-descriptor":"^1.0.0","is-data-descriptor":"^1.0.0","kind-of":"^6.0.2"}}}},"snapdragon-util":{"version":"3.0.1","resolved":"https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz","integrity":"sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==","dev":true,"requires":{"kind-of":"^3.2.0"},"dependencies":{"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"source-list-map":{"version":"2.0.1","resolved":"https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz","integrity":"sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==","dev":true},"source-map":{"version":"0.5.7","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz","integrity":"sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=","dev":true},"source-map-resolve":{"version":"0.5.2","resolved":"https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz","integrity":"sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==","dev":true,"requires":{"atob":"^2.1.1","decode-uri-component":"^0.2.0","resolve-url":"^0.2.1","source-map-url":"^0.4.0","urix":"^0.1.0"}},"source-map-support":{"version":"0.4.18","resolved":"https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz","integrity":"sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==","dev":true,"requires":{"source-map":"^0.5.6"}},"source-map-url":{"version":"0.4.0","resolved":"https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz","integrity":"sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=","dev":true},"spawn-wrap":{"version":"1.4.2","resolved":"https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz","integrity":"sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==","dev":true,"requires":{"foreground-child":"^1.5.6","mkdirp":"^0.5.0","os-homedir":"^1.0.1","rimraf":"^2.6.2","signal-exit":"^3.0.2","which":"^1.3.0"}},"spdx-correct":{"version":"3.0.2","resolved":"https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz","integrity":"sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==","dev":true,"requires":{"spdx-expression-parse":"^3.0.0","spdx-license-ids":"^3.0.0"}},"spdx-exceptions":{"version":"2.2.0","resolved":"https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz","integrity":"sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==","dev":true},"spdx-expression-parse":{"version":"3.0.0","resolved":"https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz","integrity":"sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==","dev":true,"requires":{"spdx-exceptions":"^2.1.0","spdx-license-ids":"^3.0.0"}},"spdx-license-ids":{"version":"3.0.2","resolved":"https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz","integrity":"sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==","dev":true},"split-string":{"version":"3.1.0","resolved":"https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz","integrity":"sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==","dev":true,"requires":{"extend-shallow":"^3.0.0"}},"sprintf-js":{"version":"1.0.3","resolved":"https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz","integrity":"sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=","dev":true},"sshpk":{"version":"1.15.2","resolved":"https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz","integrity":"sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==","dev":true,"requires":{"asn1":"~0.2.3","assert-plus":"^1.0.0","bcrypt-pbkdf":"^1.0.0","dashdash":"^1.12.0","ecc-jsbn":"~0.1.1","getpass":"^0.1.1","jsbn":"~0.1.0","safer-buffer":"^2.0.2","tweetnacl":"~0.14.0"}},"ssri":{"version":"5.3.0","resolved":"https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz","integrity":"sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==","dev":true,"requires":{"safe-buffer":"^5.1.1"}},"static-extend":{"version":"0.1.2","resolved":"https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz","integrity":"sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=","dev":true,"requires":{"define-property":"^0.2.5","object-copy":"^0.1.0"},"dependencies":{"define-property":{"version":"0.2.5","resolved":"https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz","integrity":"sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=","dev":true,"requires":{"is-descriptor":"^0.1.0"}}}},"stealthy-require":{"version":"1.1.1","resolved":"https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz","integrity":"sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=","dev":true},"stream-browserify":{"version":"2.0.1","resolved":"http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz","integrity":"sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=","dev":true,"requires":{"inherits":"~2.0.1","readable-stream":"^2.0.2"}},"stream-each":{"version":"1.2.3","resolved":"https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz","integrity":"sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==","dev":true,"requires":{"end-of-stream":"^1.1.0","stream-shift":"^1.0.0"}},"stream-http":{"version":"2.8.3","resolved":"https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz","integrity":"sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==","dev":true,"requires":{"builtin-status-codes":"^3.0.0","inherits":"^2.0.1","readable-stream":"^2.3.6","to-arraybuffer":"^1.0.0","xtend":"^4.0.0"}},"stream-shift":{"version":"1.0.0","resolved":"https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz","integrity":"sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=","dev":true},"string-width":{"version":"2.1.1","resolved":"https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz","integrity":"sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==","dev":true,"requires":{"is-fullwidth-code-point":"^2.0.0","strip-ansi":"^4.0.0"}},"string_decoder":{"version":"1.1.1","resolved":"https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz","integrity":"sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==","dev":true,"requires":{"safe-buffer":"~5.1.0"}},"strip-ansi":{"version":"4.0.0","resolved":"https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz","integrity":"sha1-qEeQIusaw2iocTibY1JixQXuNo8=","dev":true,"requires":{"ansi-regex":"^3.0.0"}},"strip-bom":{"version":"3.0.0","resolved":"https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz","integrity":"sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=","dev":true},"strip-eof":{"version":"1.0.0","resolved":"http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz","integrity":"sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=","dev":true},"strip-json-comments":{"version":"2.0.1","resolved":"https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz","integrity":"sha1-PFMZQukIwml8DsNEhYwobHygpgo=","dev":true},"supports-color":{"version":"5.5.0","resolved":"https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz","integrity":"sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==","dev":true,"requires":{"has-flag":"^3.0.0"}},"symbol-tree":{"version":"3.2.2","resolved":"https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz","integrity":"sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=","dev":true},"table":{"version":"5.1.0","resolved":"https://registry.npmjs.org/table/-/table-5.1.0.tgz","integrity":"sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==","dev":true,"requires":{"ajv":"^6.5.3","lodash":"^4.17.10","slice-ansi":"1.0.0","string-width":"^2.1.1"}},"tapable":{"version":"1.1.0","resolved":"https://registry.npmjs.org/tapable/-/tapable-1.1.0.tgz","integrity":"sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==","dev":true},"terser":{"version":"3.10.12","resolved":"https://registry.npmjs.org/terser/-/terser-3.10.12.tgz","integrity":"sha512-3ODPC1eVt25EVNb04s/PkHxOmzKBQUF6bwwuR6h2DbEF8/j265Y1UkwNtOk9am/pRxfJ5HPapOlUlO6c16mKQQ==","dev":true,"requires":{"commander":"~2.17.1","source-map":"~0.6.1","source-map-support":"~0.5.6"},"dependencies":{"commander":{"version":"2.17.1","resolved":"https://registry.npmjs.org/commander/-/commander-2.17.1.tgz","integrity":"sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==","dev":true},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true},"source-map-support":{"version":"0.5.9","resolved":"https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz","integrity":"sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==","dev":true,"requires":{"buffer-from":"^1.0.0","source-map":"^0.6.0"}}}},"terser-webpack-plugin":{"version":"1.1.0","resolved":"https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz","integrity":"sha512-61lV0DSxMAZ8AyZG7/A4a3UPlrbOBo8NIQ4tJzLPAdGOQ+yoNC7l5ijEow27lBAL2humer01KLS6bGIMYQxKoA==","dev":true,"requires":{"cacache":"^11.0.2","find-cache-dir":"^2.0.0","schema-utils":"^1.0.0","serialize-javascript":"^1.4.0","source-map":"^0.6.1","terser":"^3.8.1","webpack-sources":"^1.1.0","worker-farm":"^1.5.2"},"dependencies":{"cacache":{"version":"11.3.1","resolved":"https://registry.npmjs.org/cacache/-/cacache-11.3.1.tgz","integrity":"sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==","dev":true,"requires":{"bluebird":"^3.5.1","chownr":"^1.0.1","figgy-pudding":"^3.1.0","glob":"^7.1.2","graceful-fs":"^4.1.11","lru-cache":"^4.1.3","mississippi":"^3.0.0","mkdirp":"^0.5.1","move-concurrently":"^1.0.1","promise-inflight":"^1.0.1","rimraf":"^2.6.2","ssri":"^6.0.0","unique-filename":"^1.1.0","y18n":"^4.0.0"}},"find-cache-dir":{"version":"2.0.0","resolved":"https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz","integrity":"sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==","dev":true,"requires":{"commondir":"^1.0.1","make-dir":"^1.0.0","pkg-dir":"^3.0.0"}},"find-up":{"version":"3.0.0","resolved":"https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz","integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"locate-path":{"version":"3.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz","integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"mississippi":{"version":"3.0.0","resolved":"https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz","integrity":"sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==","dev":true,"requires":{"concat-stream":"^1.5.0","duplexify":"^3.4.2","end-of-stream":"^1.1.0","flush-write-stream":"^1.0.0","from2":"^2.1.0","parallel-transform":"^1.1.0","pump":"^3.0.0","pumpify":"^1.3.3","stream-each":"^1.1.0","through2":"^2.0.0"}},"p-limit":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz","integrity":"sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz","integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz","integrity":"sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==","dev":true},"pkg-dir":{"version":"3.0.0","resolved":"https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz","integrity":"sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==","dev":true,"requires":{"find-up":"^3.0.0"}},"pump":{"version":"3.0.0","resolved":"https://registry.npmjs.org/pump/-/pump-3.0.0.tgz","integrity":"sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==","dev":true,"requires":{"end-of-stream":"^1.1.0","once":"^1.3.1"}},"schema-utils":{"version":"1.0.0","resolved":"https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz","integrity":"sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==","dev":true,"requires":{"ajv":"^6.1.0","ajv-errors":"^1.0.0","ajv-keywords":"^3.1.0"}},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true},"ssri":{"version":"6.0.1","resolved":"https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz","integrity":"sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==","dev":true,"requires":{"figgy-pudding":"^3.5.1"}}}},"test-exclude":{"version":"5.0.0","resolved":"https://registry.npmjs.org/test-exclude/-/test-exclude-5.0.0.tgz","integrity":"sha512-bO3Lj5+qFa9YLfYW2ZcXMOV1pmQvw+KS/DpjqhyX6Y6UZ8zstpZJ+mA2ERkXfpOqhxsJlQiLeVXD3Smsrs6oLw==","dev":true,"requires":{"arrify":"^1.0.1","minimatch":"^3.0.4","read-pkg-up":"^4.0.0","require-main-filename":"^1.0.1"}},"text-table":{"version":"0.2.0","resolved":"https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz","integrity":"sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=","dev":true},"through":{"version":"2.3.8","resolved":"http://registry.npmjs.org/through/-/through-2.3.8.tgz","integrity":"sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=","dev":true},"through2":{"version":"2.0.5","resolved":"https://registry.npmjs.org/through2/-/through2-2.0.5.tgz","integrity":"sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==","dev":true,"requires":{"readable-stream":"~2.3.6","xtend":"~4.0.1"}},"timers-browserify":{"version":"2.0.10","resolved":"https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz","integrity":"sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==","dev":true,"requires":{"setimmediate":"^1.0.4"}},"tmp":{"version":"0.0.33","resolved":"https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz","integrity":"sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==","dev":true,"requires":{"os-tmpdir":"~1.0.2"}},"to-arraybuffer":{"version":"1.0.1","resolved":"https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz","integrity":"sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=","dev":true},"to-fast-properties":{"version":"2.0.0","resolved":"https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz","integrity":"sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=","dev":true},"to-object-path":{"version":"0.3.0","resolved":"https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz","integrity":"sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=","dev":true,"requires":{"kind-of":"^3.0.2"},"dependencies":{"kind-of":{"version":"3.2.2","resolved":"https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz","integrity":"sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=","dev":true,"requires":{"is-buffer":"^1.1.5"}}}},"to-regex":{"version":"3.0.2","resolved":"https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz","integrity":"sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==","dev":true,"requires":{"define-property":"^2.0.2","extend-shallow":"^3.0.2","regex-not":"^1.0.2","safe-regex":"^1.1.0"}},"to-regex-range":{"version":"2.1.1","resolved":"https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz","integrity":"sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=","dev":true,"requires":{"is-number":"^3.0.0","repeat-string":"^1.6.1"}},"tough-cookie":{"version":"2.4.3","resolved":"https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz","integrity":"sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==","dev":true,"requires":{"psl":"^1.1.24","punycode":"^1.4.1"},"dependencies":{"punycode":{"version":"1.4.1","resolved":"https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz","integrity":"sha1-wNWmOycYgArY4esPpSachN1BhF4=","dev":true}}},"tr46":{"version":"1.0.1","resolved":"https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz","integrity":"sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=","dev":true,"requires":{"punycode":"^2.1.0"}},"trim-right":{"version":"1.0.1","resolved":"https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz","integrity":"sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=","dev":true},"tslib":{"version":"1.9.3","resolved":"https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz","integrity":"sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==","dev":true},"tty-browserify":{"version":"0.0.0","resolved":"https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz","integrity":"sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=","dev":true},"tunnel-agent":{"version":"0.6.0","resolved":"https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz","integrity":"sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=","dev":true,"requires":{"safe-buffer":"^5.0.1"}},"tweetnacl":{"version":"0.14.5","resolved":"https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz","integrity":"sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=","dev":true},"type-check":{"version":"0.3.2","resolved":"https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz","integrity":"sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=","dev":true,"requires":{"prelude-ls":"~1.1.2"}},"type-detect":{"version":"4.0.8","resolved":"https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz","integrity":"sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==","dev":true},"typedarray":{"version":"0.0.6","resolved":"https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz","integrity":"sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=","dev":true},"uglify-es":{"version":"3.3.9","resolved":"https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz","integrity":"sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==","dev":true,"requires":{"commander":"~2.13.0","source-map":"~0.6.1"},"dependencies":{"commander":{"version":"2.13.0","resolved":"https://registry.npmjs.org/commander/-/commander-2.13.0.tgz","integrity":"sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==","dev":true},"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true}}},"uglifyjs-webpack-plugin":{"version":"1.3.0","resolved":"https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz","integrity":"sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==","dev":true,"requires":{"cacache":"^10.0.4","find-cache-dir":"^1.0.0","schema-utils":"^0.4.5","serialize-javascript":"^1.4.0","source-map":"^0.6.1","uglify-es":"^3.3.4","webpack-sources":"^1.1.0","worker-farm":"^1.5.2"},"dependencies":{"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true}}},"unicode-canonical-property-names-ecmascript":{"version":"1.0.4","resolved":"https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz","integrity":"sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==","dev":true},"unicode-match-property-ecmascript":{"version":"1.0.4","resolved":"https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz","integrity":"sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==","dev":true,"requires":{"unicode-canonical-property-names-ecmascript":"^1.0.4","unicode-property-aliases-ecmascript":"^1.0.4"}},"unicode-match-property-value-ecmascript":{"version":"1.0.2","resolved":"https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz","integrity":"sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ==","dev":true},"unicode-property-aliases-ecmascript":{"version":"1.0.4","resolved":"https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz","integrity":"sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg==","dev":true},"union":{"version":"0.4.6","resolved":"https://registry.npmjs.org/union/-/union-0.4.6.tgz","integrity":"sha1-GY+9rrolTniLDvy2MLwR8kopWeA=","dev":true,"requires":{"qs":"~2.3.3"},"dependencies":{"qs":{"version":"2.3.3","resolved":"https://registry.npmjs.org/qs/-/qs-2.3.3.tgz","integrity":"sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=","dev":true}}},"union-value":{"version":"1.0.1","resolved":"https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz","integrity":"sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==","dev":true,"requires":{"arr-union":"^3.1.0","get-value":"^2.0.6","is-extendable":"^0.1.1","set-value":"^2.0.1"}},"unique-filename":{"version":"1.1.1","resolved":"https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz","integrity":"sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==","dev":true,"requires":{"unique-slug":"^2.0.0"}},"unique-slug":{"version":"2.0.1","resolved":"https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz","integrity":"sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==","dev":true,"requires":{"imurmurhash":"^0.1.4"}},"unset-value":{"version":"1.0.0","resolved":"https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz","integrity":"sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=","dev":true,"requires":{"has-value":"^0.3.1","isobject":"^3.0.0"},"dependencies":{"has-value":{"version":"0.3.1","resolved":"https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz","integrity":"sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=","dev":true,"requires":{"get-value":"^2.0.3","has-values":"^0.1.4","isobject":"^2.0.0"},"dependencies":{"isobject":{"version":"2.1.0","resolved":"https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz","integrity":"sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=","dev":true,"requires":{"isarray":"1.0.0"}}}},"has-values":{"version":"0.1.4","resolved":"https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz","integrity":"sha1-bWHeldkd/Km5oCCJrThL/49it3E=","dev":true}}},"upath":{"version":"1.1.0","resolved":"https://registry.npmjs.org/upath/-/upath-1.1.0.tgz","integrity":"sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==","dev":true},"uri-js":{"version":"4.2.2","resolved":"https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz","integrity":"sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==","dev":true,"requires":{"punycode":"^2.1.0"}},"urix":{"version":"0.1.0","resolved":"https://registry.npmjs.org/urix/-/urix-0.1.0.tgz","integrity":"sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=","dev":true},"url":{"version":"0.11.0","resolved":"https://registry.npmjs.org/url/-/url-0.11.0.tgz","integrity":"sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=","dev":true,"requires":{"punycode":"1.3.2","querystring":"0.2.0"},"dependencies":{"punycode":{"version":"1.3.2","resolved":"https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz","integrity":"sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=","dev":true}}},"url-join":{"version":"2.0.5","resolved":"https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz","integrity":"sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=","dev":true},"use":{"version":"3.1.1","resolved":"https://registry.npmjs.org/use/-/use-3.1.1.tgz","integrity":"sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==","dev":true},"util":{"version":"0.10.4","resolved":"https://registry.npmjs.org/util/-/util-0.10.4.tgz","integrity":"sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==","dev":true,"requires":{"inherits":"2.0.3"}},"util-deprecate":{"version":"1.0.2","resolved":"https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz","integrity":"sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=","dev":true},"util.promisify":{"version":"1.0.0","resolved":"https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz","integrity":"sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==","dev":true,"requires":{"define-properties":"^1.1.2","object.getownpropertydescriptors":"^2.0.3"}},"uuid":{"version":"3.3.2","resolved":"https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz","integrity":"sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==","dev":true},"v8-compile-cache":{"version":"2.0.2","resolved":"https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz","integrity":"sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw==","dev":true},"validate-npm-package-license":{"version":"3.0.4","resolved":"https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz","integrity":"sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==","dev":true,"requires":{"spdx-correct":"^3.0.0","spdx-expression-parse":"^3.0.0"}},"verror":{"version":"1.10.0","resolved":"https://registry.npmjs.org/verror/-/verror-1.10.0.tgz","integrity":"sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=","dev":true,"requires":{"assert-plus":"^1.0.0","core-util-is":"1.0.2","extsprintf":"^1.2.0"}},"vm-browserify":{"version":"0.0.4","resolved":"https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz","integrity":"sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=","dev":true,"requires":{"indexof":"0.0.1"}},"w3c-hr-time":{"version":"1.0.1","resolved":"https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz","integrity":"sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=","dev":true,"requires":{"browser-process-hrtime":"^0.1.2"}},"watchpack":{"version":"1.6.0","resolved":"https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz","integrity":"sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==","dev":true,"requires":{"chokidar":"^2.0.2","graceful-fs":"^4.1.2","neo-async":"^2.5.0"}},"webidl-conversions":{"version":"4.0.2","resolved":"https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz","integrity":"sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==","dev":true},"webpack":{"version":"4.26.0","resolved":"https://registry.npmjs.org/webpack/-/webpack-4.26.0.tgz","integrity":"sha512-J/dP9SJIc5OtX2FZ/+U9ikQtd6H6Mcbqt0xeXtmPwYGDKf8nkbOQQA9KL2Y0rJOsN1Al9Pdn+/j63X58ub8gvQ==","dev":true,"requires":{"@webassemblyjs/ast":"1.7.11","@webassemblyjs/helper-module-context":"1.7.11","@webassemblyjs/wasm-edit":"1.7.11","@webassemblyjs/wasm-parser":"1.7.11","acorn":"^5.6.2","acorn-dynamic-import":"^3.0.0","ajv":"^6.1.0","ajv-keywords":"^3.1.0","chrome-trace-event":"^1.0.0","enhanced-resolve":"^4.1.0","eslint-scope":"^4.0.0","json-parse-better-errors":"^1.0.2","loader-runner":"^2.3.0","loader-utils":"^1.1.0","memory-fs":"~0.4.1","micromatch":"^3.1.8","mkdirp":"~0.5.0","neo-async":"^2.5.0","node-libs-browser":"^2.0.0","schema-utils":"^0.4.4","tapable":"^1.1.0","terser-webpack-plugin":"^1.1.0","watchpack":"^1.5.0","webpack-sources":"^1.3.0"},"dependencies":{"acorn":{"version":"5.7.4","resolved":"https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz","integrity":"sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==","dev":true},"eslint-scope":{"version":"4.0.0","resolved":"https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz","integrity":"sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==","dev":true,"requires":{"esrecurse":"^4.1.0","estraverse":"^4.1.1"}}}},"webpack-cli":{"version":"3.1.2","resolved":"https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.1.2.tgz","integrity":"sha512-Cnqo7CeqeSvC6PTdts+dywNi5CRlIPbLx1AoUPK2T6vC1YAugMG3IOoO9DmEscd+Dghw7uRlnzV1KwOe5IrtgQ==","dev":true,"requires":{"chalk":"^2.4.1","cross-spawn":"^6.0.5","enhanced-resolve":"^4.1.0","global-modules-path":"^2.3.0","import-local":"^2.0.0","interpret":"^1.1.0","loader-utils":"^1.1.0","supports-color":"^5.5.0","v8-compile-cache":"^2.0.2","yargs":"^12.0.2"},"dependencies":{"find-up":{"version":"3.0.0","resolved":"https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz","integrity":"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==","dev":true,"requires":{"locate-path":"^3.0.0"}},"locate-path":{"version":"3.0.0","resolved":"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz","integrity":"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==","dev":true,"requires":{"p-locate":"^3.0.0","path-exists":"^3.0.0"}},"p-limit":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz","integrity":"sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==","dev":true,"requires":{"p-try":"^2.0.0"}},"p-locate":{"version":"3.0.0","resolved":"https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz","integrity":"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==","dev":true,"requires":{"p-limit":"^2.0.0"}},"p-try":{"version":"2.0.0","resolved":"https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz","integrity":"sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==","dev":true},"yargs":{"version":"12.0.5","resolved":"https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz","integrity":"sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==","dev":true,"requires":{"cliui":"^4.0.0","decamelize":"^1.2.0","find-up":"^3.0.0","get-caller-file":"^1.0.1","os-locale":"^3.0.0","require-directory":"^2.1.1","require-main-filename":"^1.0.1","set-blocking":"^2.0.0","string-width":"^2.0.0","which-module":"^2.0.0","y18n":"^3.2.1 || ^4.0.0","yargs-parser":"^11.1.1"}}}},"webpack-sources":{"version":"1.3.0","resolved":"https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz","integrity":"sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==","dev":true,"requires":{"source-list-map":"^2.0.0","source-map":"~0.6.1"},"dependencies":{"source-map":{"version":"0.6.1","resolved":"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz","integrity":"sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==","dev":true}}},"whatwg-encoding":{"version":"1.0.5","resolved":"https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz","integrity":"sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==","dev":true,"requires":{"iconv-lite":"0.4.24"}},"whatwg-mimetype":{"version":"2.3.0","resolved":"https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz","integrity":"sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==","dev":true},"whatwg-url":{"version":"6.5.0","resolved":"https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz","integrity":"sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==","dev":true,"requires":{"lodash.sortby":"^4.7.0","tr46":"^1.0.1","webidl-conversions":"^4.0.2"}},"which":{"version":"1.3.1","resolved":"https://registry.npmjs.org/which/-/which-1.3.1.tgz","integrity":"sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==","dev":true,"requires":{"isexe":"^2.0.0"}},"which-module":{"version":"2.0.0","resolved":"https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz","integrity":"sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=","dev":true},"wordwrap":{"version":"1.0.0","resolved":"https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz","integrity":"sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=","dev":true},"worker-farm":{"version":"1.6.0","resolved":"https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz","integrity":"sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==","dev":true,"requires":{"errno":"~0.1.7"}},"wrap-ansi":{"version":"2.1.0","resolved":"https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz","integrity":"sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=","dev":true,"requires":{"string-width":"^1.0.1","strip-ansi":"^3.0.1"},"dependencies":{"ansi-regex":{"version":"2.1.1","resolved":"https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz","integrity":"sha1-w7M6te42DYbg5ijwRorn7yfWVN8=","dev":true},"is-fullwidth-code-point":{"version":"1.0.0","resolved":"https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz","integrity":"sha1-754xOG8DGn8NZDr4L95QxFfvAMs=","dev":true,"requires":{"number-is-nan":"^1.0.0"}},"string-width":{"version":"1.0.2","resolved":"https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz","integrity":"sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=","dev":true,"requires":{"code-point-at":"^1.0.0","is-fullwidth-code-point":"^1.0.0","strip-ansi":"^3.0.0"}},"strip-ansi":{"version":"3.0.1","resolved":"https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz","integrity":"sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=","dev":true,"requires":{"ansi-regex":"^2.0.0"}}}},"wrappy":{"version":"1.0.2","resolved":"https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz","integrity":"sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=","dev":true},"write":{"version":"0.2.1","resolved":"https://registry.npmjs.org/write/-/write-0.2.1.tgz","integrity":"sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=","dev":true,"requires":{"mkdirp":"^0.5.1"}},"write-file-atomic":{"version":"2.4.3","resolved":"https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz","integrity":"sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==","dev":true,"requires":{"graceful-fs":"^4.1.11","imurmurhash":"^0.1.4","signal-exit":"^3.0.2"}},"ws":{"version":"4.1.0","resolved":"http://registry.npmjs.org/ws/-/ws-4.1.0.tgz","integrity":"sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==","dev":true,"requires":{"async-limiter":"~1.0.0","safe-buffer":"~5.1.0"}},"xml-name-validator":{"version":"3.0.0","resolved":"https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz","integrity":"sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==","dev":true},"xtend":{"version":"4.0.1","resolved":"https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz","integrity":"sha1-pcbVMr5lbiPbgg77lDofBJmNY68=","dev":true},"y18n":{"version":"4.0.0","resolved":"https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz","integrity":"sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==","dev":true},"yallist":{"version":"3.0.3","resolved":"https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz","integrity":"sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==","dev":true},"yargs":{"version":"10.1.2","resolved":"https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz","integrity":"sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==","dev":true,"requires":{"cliui":"^4.0.0","decamelize":"^1.1.1","find-up":"^2.1.0","get-caller-file":"^1.0.1","os-locale":"^2.0.0","require-directory":"^2.1.1","require-main-filename":"^1.0.1","set-blocking":"^2.0.0","string-width":"^2.0.0","which-module":"^2.0.0","y18n":"^3.2.1","yargs-parser":"^8.1.0"},"dependencies":{"camelcase":{"version":"4.1.0","resolved":"https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz","integrity":"sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=","dev":true},"cross-spawn":{"version":"5.1.0","resolved":"https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz","integrity":"sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=","dev":true,"requires":{"lru-cache":"^4.0.1","shebang-command":"^1.2.0","which":"^1.2.9"}},"execa":{"version":"0.7.0","resolved":"https://registry.npmjs.org/execa/-/execa-0.7.0.tgz","integrity":"sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=","dev":true,"requires":{"cross-spawn":"^5.0.1","get-stream":"^3.0.0","is-stream":"^1.1.0","npm-run-path":"^2.0.0","p-finally":"^1.0.0","signal-exit":"^3.0.0","strip-eof":"^1.0.0"}},"invert-kv":{"version":"1.0.0","resolved":"https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz","integrity":"sha1-EEqOSqym09jNFXqO+L+rLXo//bY=","dev":true},"lcid":{"version":"1.0.0","resolved":"https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz","integrity":"sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=","dev":true,"requires":{"invert-kv":"^1.0.0"}},"mem":{"version":"1.1.0","resolved":"https://registry.npmjs.org/mem/-/mem-1.1.0.tgz","integrity":"sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=","dev":true,"requires":{"mimic-fn":"^1.0.0"}},"os-locale":{"version":"2.1.0","resolved":"https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz","integrity":"sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==","dev":true,"requires":{"execa":"^0.7.0","lcid":"^1.0.0","mem":"^1.1.0"}},"y18n":{"version":"3.2.1","resolved":"https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz","integrity":"sha1-bRX7qITAhnnA136I53WegR4H+kE=","dev":true},"yargs-parser":{"version":"8.1.0","resolved":"https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz","integrity":"sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==","dev":true,"requires":{"camelcase":"^4.1.0"}}}},"yargs-parser":{"version":"11.1.1","resolved":"https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz","integrity":"sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==","dev":true,"requires":{"camelcase":"^5.0.0","decamelize":"^1.2.0"}}}} \ No newline at end of file +{ + "name": "darkmode-js", + "version": "1.5.7", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/cli": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.1.5.tgz", + "integrity": "sha512-zbO/DtTnaDappBflIU3zYEgATLToRDmW5uN/EGH1GXaes7ydfjqmAoK++xmJIA+8HfDw7UyPZNdM8fhGhfmMhw==", + "dev": true, + "requires": { + "chokidar": "^2.0.3", + "commander": "^2.8.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.10", + "mkdirp": "^0.5.1", + "output-file-sync": "^2.0.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + } + }, + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.1.6.tgz", + "integrity": "sha512-Hz6PJT6e44iUNpAn8AoyAs6B3bl60g7MJQaI0rZEar6ECzh6+srYO1xlIdssio34mPaUtAb1y+XlkkSJzok3yw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.6", + "@babel/helpers": "^7.1.5", + "@babel/parser": "^7.1.6", + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.1.6", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.10", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.1.6.tgz", + "integrity": "sha512-brwPBtVvdYdGxtenbQgfCdDPmtkmUBZPjUoK5SXJEBuHaA5BCubh9ly65fzXz7R6o5rA76Rs22ES8Z+HCc0YIQ==", + "dev": true, + "requires": { + "@babel/types": "^7.1.6", + "jsesc": "^2.5.1", + "lodash": "^4.17.10", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz", + "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-define-map": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz", + "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz", + "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", + "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz", + "integrity": "sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz", + "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz", + "integrity": "sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "dev": true, + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", + "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-wrap-function": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz", + "integrity": "sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helpers": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.5.tgz", + "integrity": "sha512-2jkcdL02ywNBry1YNFAH/fViq4fXG0vdckHqeJk+75fpQ2OH+Az6076tX/M0835zA45E0Cqa6pV5Kiv9YOqjEg==", + "dev": true, + "requires": { + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.5", + "@babel/types": "^7.1.5" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.1.6.tgz", + "integrity": "sha512-dWP6LJm9nKT6ALaa+bnL247GHHMWir3vSlZ2+IHgHgktZQx0L3Uvq2uAWcuzIe+fujRsYWBW2q622C5UvGK9iQ==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz", + "integrity": "sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.0.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz", + "integrity": "sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.0.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz", + "integrity": "sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0.tgz", + "integrity": "sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.0.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz", + "integrity": "sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.2.0" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0.tgz", + "integrity": "sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz", + "integrity": "sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz", + "integrity": "sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0.tgz", + "integrity": "sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz", + "integrity": "sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz", + "integrity": "sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0.tgz", + "integrity": "sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.1.5.tgz", + "integrity": "sha512-jlYcDrz+5ayWC7mxgpn1Wj8zj0mmjCT2w0mPIMSwO926eXBRxpEgoN/uQVRBfjtr8ayjcmS+xk2G1jaP8JjMJQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.10" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz", + "integrity": "sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.1.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0.tgz", + "integrity": "sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.1.3.tgz", + "integrity": "sha512-Mb9M4DGIOspH1ExHOUnn2UUXFOyVTiX84fXCd+6B5iWrQg/QMeeRmSwpZ9lnjYLSXtZwiw80ytVMr3zue0ucYw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0.tgz", + "integrity": "sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0.tgz", + "integrity": "sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.1.0.tgz", + "integrity": "sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz", + "integrity": "sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.1.0.tgz", + "integrity": "sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0.tgz", + "integrity": "sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.1.0.tgz", + "integrity": "sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz", + "integrity": "sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.1.3.tgz", + "integrity": "sha512-PvTxgjxQAq4pvVUZF3mD5gEtVDuId8NtWkJsZLEJZMZAW3TvgQl1pmydLLN1bM8huHFVVU43lf0uvjQj9FRkKw==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.1.0.tgz", + "integrity": "sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz", + "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.1.0.tgz", + "integrity": "sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.1.0.tgz", + "integrity": "sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.1.0", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz", + "integrity": "sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==", + "dev": true, + "requires": { + "regenerator-transform": "^0.13.3" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz", + "integrity": "sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0.tgz", + "integrity": "sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0.tgz", + "integrity": "sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0.tgz", + "integrity": "sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0.tgz", + "integrity": "sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz", + "integrity": "sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" + } + }, + "@babel/preset-env": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.6.tgz", + "integrity": "sha512-YIBfpJNQMBkb6MCkjz/A9J76SNCSuGVamOVBgoUkLzpJD/z8ghHi9I42LQ4pulVX68N/MmImz6ZTixt7Azgexw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.1.0", + "@babel/plugin-proposal-json-strings": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.0.0", + "@babel/plugin-syntax-async-generators": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.1.0", + "@babel/plugin-transform-block-scoped-functions": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.1.5", + "@babel/plugin-transform-classes": "^7.1.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-dotall-regex": "^7.0.0", + "@babel/plugin-transform-duplicate-keys": "^7.0.0", + "@babel/plugin-transform-exponentiation-operator": "^7.1.0", + "@babel/plugin-transform-for-of": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.1.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-amd": "^7.1.0", + "@babel/plugin-transform-modules-commonjs": "^7.1.0", + "@babel/plugin-transform-modules-systemjs": "^7.0.0", + "@babel/plugin-transform-modules-umd": "^7.1.0", + "@babel/plugin-transform-new-target": "^7.0.0", + "@babel/plugin-transform-object-super": "^7.1.0", + "@babel/plugin-transform-parameters": "^7.1.0", + "@babel/plugin-transform-regenerator": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "@babel/plugin-transform-typeof-symbol": "^7.0.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "browserslist": "^4.1.0", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.3.0" + } + }, + "@babel/template": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz", + "integrity": "sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.1.2", + "@babel/types": "^7.1.2" + } + }, + "@babel/traverse": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.6.tgz", + "integrity": "sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.6", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.1.6", + "@babel/types": "^7.1.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.10" + } + }, + "@babel/types": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.1.6.tgz", + "integrity": "sha512-DMiUzlY9DSjVsOylJssxLHSgj6tWM9PRFJOGW/RaOglVOK9nzTxoOMfTfRQXGUCUQ/HmlG2efwC+XqUEJ5ay4w==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.10", + "to-fast-properties": "^2.0.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz", + "integrity": "sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/wast-parser": "1.7.11" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz", + "integrity": "sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz", + "integrity": "sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz", + "integrity": "sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz", + "integrity": "sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.7.11" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz", + "integrity": "sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz", + "integrity": "sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg==", + "dev": true + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz", + "integrity": "sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz", + "integrity": "sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-buffer": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/wasm-gen": "1.7.11" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz", + "integrity": "sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.7.11.tgz", + "integrity": "sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.1" + } + }, + "@webassemblyjs/utf8": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.7.11.tgz", + "integrity": "sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz", + "integrity": "sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-buffer": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/helper-wasm-section": "1.7.11", + "@webassemblyjs/wasm-gen": "1.7.11", + "@webassemblyjs/wasm-opt": "1.7.11", + "@webassemblyjs/wasm-parser": "1.7.11", + "@webassemblyjs/wast-printer": "1.7.11" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz", + "integrity": "sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/ieee754": "1.7.11", + "@webassemblyjs/leb128": "1.7.11", + "@webassemblyjs/utf8": "1.7.11" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz", + "integrity": "sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-buffer": "1.7.11", + "@webassemblyjs/wasm-gen": "1.7.11", + "@webassemblyjs/wasm-parser": "1.7.11" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz", + "integrity": "sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-api-error": "1.7.11", + "@webassemblyjs/helper-wasm-bytecode": "1.7.11", + "@webassemblyjs/ieee754": "1.7.11", + "@webassemblyjs/leb128": "1.7.11", + "@webassemblyjs/utf8": "1.7.11" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz", + "integrity": "sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/floating-point-hex-parser": "1.7.11", + "@webassemblyjs/helper-api-error": "1.7.11", + "@webassemblyjs/helper-code-frame": "1.7.11", + "@webassemblyjs/helper-fsm": "1.7.11", + "@xtuc/long": "4.2.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz", + "integrity": "sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/wast-parser": "1.7.11", + "@xtuc/long": "4.2.1" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz", + "integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==", + "dev": true + }, + "abab": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", + "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=", + "dev": true + }, + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", + "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", + "dev": true, + "requires": { + "acorn": "^5.0.0" + }, + "dependencies": { + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true + } + } + }, + "acorn-globals": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", + "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + } + }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true + }, + "acorn-walk": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", + "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", + "dev": true + }, + "ajv": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", + "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.0.tgz", + "integrity": "sha1-7PAh+hCP0X37Xms4Py3SM+Mf/Fk=", + "dev": true + }, + "ajv-keywords": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "dev": true + }, + "ansi-escapes": { + "version": "3.1.0", + "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "babel-code-frame": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-7.0.0-beta.3.tgz", + "integrity": "sha512-flMsJ9eSpShupt2Gwpka84DoMePvE4HlDObzdEc+1iNkacv3+NHlsJ7dMKmbnVA/AT22UhcGEBHwbJLoXWBO6Q==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + } + } + }, + "babel-core": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-beta.3.tgz", + "integrity": "sha512-zdng6WxI4cUjvstvFo/ke+hxohXCi/vxrMTM1S/bsAqnvKb+C+pHx78T3ZdJlWC3bGGxYqUnmM4p9VMzJ0uVVg==", + "dev": true, + "requires": { + "babel-code-frame": "7.0.0-beta.3", + "babel-generator": "7.0.0-beta.3", + "babel-helpers": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3", + "babylon": "7.0.0-beta.27", + "convert-source-map": "^1.1.0", + "debug": "^3.0.1", + "json5": "^0.5.0", + "lodash": "^4.2.0", + "micromatch": "^2.3.11", + "resolve": "^1.3.2", + "source-map": "^0.5.0" + }, + "dependencies": { + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "babylon": { + "version": "7.0.0-beta.27", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.27.tgz", + "integrity": "sha512-ksRx+r8eFIfdt63MCgLc9VxGL7W3jcyveQvMpNMVHgW+eb9mq3Xbm45FLCNkw8h92RvoNp4uuiwzcCEwxjDBZg==", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + } + } + }, + "babel-eslint": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz", + "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/traverse": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "^1.0.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0-beta.44", + "resolved": "http://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", + "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", + "dev": true, + "requires": { + "@babel/highlight": "7.0.0-beta.44" + } + }, + "@babel/generator": { + "version": "7.0.0-beta.44", + "resolved": "http://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz", + "integrity": "sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.44", + "jsesc": "^2.5.1", + "lodash": "^4.2.0", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-function-name": { + "version": "7.0.0-beta.44", + "resolved": "http://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz", + "integrity": "sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "7.0.0-beta.44", + "@babel/template": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0-beta.44", + "resolved": "http://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz", + "integrity": "sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0-beta.44", + "resolved": "http://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz", + "integrity": "sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/highlight": { + "version": "7.0.0-beta.44", + "resolved": "http://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", + "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "@babel/template": { + "version": "7.0.0-beta.44", + "resolved": "http://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz", + "integrity": "sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "lodash": "^4.2.0" + } + }, + "@babel/traverse": { + "version": "7.0.0-beta.44", + "resolved": "http://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz", + "integrity": "sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/generator": "7.0.0-beta.44", + "@babel/helper-function-name": "7.0.0-beta.44", + "@babel/helper-split-export-declaration": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "debug": "^3.1.0", + "globals": "^11.1.0", + "invariant": "^2.2.0", + "lodash": "^4.2.0" + } + }, + "@babel/types": { + "version": "7.0.0-beta.44", + "resolved": "http://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz", + "integrity": "sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + } + } + }, + "babel-generator": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-7.0.0-beta.3.tgz", + "integrity": "sha512-Bok77tKwQZUVaLBRnDGDEaMZ4xEeyvzsgnCRxlVgfKmgn+vPxuka//ug3nrMmmgZ8TAMVPoXzeaAcs47lExrPg==", + "dev": true, + "requires": { + "babel-types": "7.0.0-beta.3", + "jsesc": "^2.5.1", + "lodash": "^4.2.0", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "babel-helper-annotate-as-pure": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-annotate-as-pure/-/babel-helper-annotate-as-pure-7.0.0-beta.3.tgz", + "integrity": "sha512-C6uYc7RmuPDZmkwTaV/ya0BGuZJFyuU/mAyDDqSfyuUZavk04eKdEWxjaKRGd3UA/fpzLNKViYO4aQgY4TsxCQ==", + "dev": true, + "requires": { + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-7.0.0-beta.3.tgz", + "integrity": "sha512-faPNvJ2w/YLRN0pD3mX3Ro/Og+uBNMdwPXg2bq5xXERQCyuYWzAmVbKnjGNaI4CLPDEbAZiZpq+AlMO3cT0QQA==", + "dev": true, + "requires": { + "babel-helper-explode-assignable-expression": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helper-call-delegate": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-7.0.0-beta.3.tgz", + "integrity": "sha512-omi9OEknlyt8LxZ46SRVMY/20EpwU2GMkXHcswcGNANNcaB3aiDcYQRAgtU0vrhjD/+fIGb9xl7+plpUnADKIw==", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helper-define-map": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-7.0.0-beta.3.tgz", + "integrity": "sha512-F2DrZDfS4EIFi5HTK3eaL8ojJwM6jjEM26D/i7h1YAwlm6PytiOXlhcXNbOoSBv6767WesNWpLVDQoX68SjDrQ==", + "dev": true, + "requires": { + "babel-helper-function-name": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3", + "lodash": "^4.2.0" + } + }, + "babel-helper-explode-assignable-expression": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-7.0.0-beta.3.tgz", + "integrity": "sha512-MugrfM38GSj7+8I/yFYjQwOEPSGmCLsJFNrWz7KVH4HA5Ntim19cMmdMUWSls30rTeGYQpLECjHNFv+ITbA7wA==", + "dev": true, + "requires": { + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helper-function-name": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-7.0.0-beta.3.tgz", + "integrity": "sha512-iMWYqwDarQOVlEGcK1MfbtK9vrFGs5Z4UQsdASJUHdhBp918EM5kndwriiIbhUX8gr2B/CEV/udJkFTrHsjdMQ==", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helper-get-function-arity": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-7.0.0-beta.3.tgz", + "integrity": "sha512-ZkYFRMWKx1c9fUW72YNM3eieBG701CMbLjmLLWmJTTPc0F0kddS9Fwok26EAmndUAgD6kFdh7ms3PH94MdGuGQ==", + "dev": true, + "requires": { + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helper-hoist-variables": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-7.0.0-beta.3.tgz", + "integrity": "sha512-9XOLW0nN3154gYf0OrRpatRYpB5s5NkRAcFseGYn/sxf+450iURwq442O7USvg9dRl1WWBgH23fsQQ5+xjKsGw==", + "dev": true, + "requires": { + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helper-module-imports": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-module-imports/-/babel-helper-module-imports-7.0.0-beta.3.tgz", + "integrity": "sha512-bdPrIXbUTYfREhRhjbN8SstwQaj0S4+rW4PKi1f2Wc5fizSh0hGYkfXUdiSSOgyTydm956tAyz4FrG61bqdQyw==", + "dev": true, + "requires": { + "babel-types": "7.0.0-beta.3", + "lodash": "^4.2.0" + } + }, + "babel-helper-module-transforms": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-module-transforms/-/babel-helper-module-transforms-7.0.0-beta.3.tgz", + "integrity": "sha512-mnCAqH2fpcYny6LMyCg/bMif/D8FxER/at9R3xNWvfAv2N5x5Yhai0g8tBQZuINqZkAxQ4Tl7x/8ImviwKBQSA==", + "dev": true, + "requires": { + "babel-helper-module-imports": "7.0.0-beta.3", + "babel-helper-simple-access": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3", + "lodash": "^4.2.0" + } + }, + "babel-helper-optimise-call-expression": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-7.0.0-beta.3.tgz", + "integrity": "sha512-X614MCHT+to5dnH4uecU63VUmOs+4Hn8DfH6vT2090HHE9/swOuNFKpeNeI3hebt59eAYyoWb2iPGv7FTpIh3Q==", + "dev": true, + "requires": { + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helper-regex": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-7.0.0-beta.3.tgz", + "integrity": "sha512-ZmM3LrVJec0WUzugRvEvoNkoGygkN7PGSB3ZS2XiACb39t2uQhFzaVuaucYTGupXNt3aZ71usE1vt55FlVEFqg==", + "dev": true, + "requires": { + "lodash": "^4.2.0" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-7.0.0-beta.3.tgz", + "integrity": "sha512-zTuzSAn4FM7WlduV9o/GoY7iU1Rfm6WqO6edwZ3LwexnJ/eGEa/46DNUYSUA2ApvXjRX/J7Ox9TRJHv2U4xbhg==", + "dev": true, + "requires": { + "babel-helper-wrap-function": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helper-replace-supers": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-7.0.0-beta.3.tgz", + "integrity": "sha512-ZkTdE7XBDW0PUQkKTeax+m1JpZqzo9ze3zbqjRxyt+x328NeGLD3edmNCIxmFt86njxIo3AFfZ00PKd4g/7jqg==", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helper-simple-access": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-simple-access/-/babel-helper-simple-access-7.0.0-beta.3.tgz", + "integrity": "sha512-4gaS4Eej6+qY35EWuwtkDQ47oKTRIBmGEGMzTigyDVjRfNltAlhN8lZPhNsIcKxG3zJ/UTOhtx7j8dmn757PUw==", + "dev": true, + "requires": { + "babel-template": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3", + "lodash": "^4.2.0" + } + }, + "babel-helper-wrap-function": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helper-wrap-function/-/babel-helper-wrap-function-7.0.0-beta.3.tgz", + "integrity": "sha512-uje7ahcNwS0vn6/Uw+4zSycwOcasFIB/2ek5dMQ3K3OICsXPmeDn9cKaugot+q1TfsyN9wfU9qEAEIZvIllWNQ==", + "dev": true, + "requires": { + "babel-helper-function-name": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-helpers": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-7.0.0-beta.3.tgz", + "integrity": "sha512-zNX7FgdXT8645igxTyAVIArMbxUsFl1w3K+v+SKlGbDocIVjWMnRszRfgVwJflzI11yE0kY+fy6SNfulykW8CA==", + "dev": true, + "requires": { + "babel-template": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-loader": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.4.tgz", + "integrity": "sha512-fhBhNkUToJcW9nV46v8w87AJOwAJDz84c1CL57n3Stj73FANM/b9TbCUK4YhdOwEyZ+OxhYpdeZDNzSI29Firw==", + "dev": true, + "requires": { + "find-cache-dir": "^1.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "util.promisify": "^1.0.0" + } + }, + "babel-plugin-add-module-exports": { + "version": "0.2.1", + "resolved": "http://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz", + "integrity": "sha1-mumh9KjcZ/DN7E9K7aHkOl/2XiU=", + "dev": true + }, + "babel-plugin-check-es2015-constants": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-7.0.0-beta.3.tgz", + "integrity": "sha512-cosavMPmT+fz17Bugk2sK60k/U+AkniFntFWx09aOkidkRSL9gRAJaE7zg6A8J6uBbWDi7XKdm+47T9iia5KYw==", + "dev": true + }, + "babel-plugin-istanbul": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.0.tgz", + "integrity": "sha512-CLoXPRSUWiR8yao8bShqZUIC6qLfZVVY3X1wj+QPNXu0wfmrRRfarh1LYy+dYMVI+bDj0ghy3tuqFFRFZmL1Nw==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.0.0", + "test-exclude": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", + "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + } + } + }, + "babel-plugin-syntax-async-functions": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-7.0.0-beta.0.tgz", + "integrity": "sha512-IKh5AA3LKrqluJVc3xVE0i4zD7OIW1Iyua4uZQ3PCwey5lv/pM668eYhIEQT3fj8SmdP3cXVquvKQ0IdMVgQxg==", + "dev": true + }, + "babel-plugin-syntax-async-generators": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-7.0.0-beta.3.tgz", + "integrity": "sha512-isPmqPGxMKOoXF+bzIlA+MjwhbLRhLrqc2mA/7HWFuu7fGtTWG9XGlFVd9aR7pTkGMh+cVcFsUCLhvEaojC9xA==", + "dev": true + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-7.0.0-beta.0.tgz", + "integrity": "sha512-qFH1aInJPJefgefIXekOtNkzyjlfC2TOIp+O27ya0jFhtuUAqfAmEgVTIjYSi0E5mCpT70IeCZ6J0Rz62F+uog==", + "dev": true + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-7.0.0-beta.3.tgz", + "integrity": "sha512-21/MnmUFduLr4JzxrKMm/MeF+Jjyi5UdZo38IqzrP0sLhmPbal5ZAUJ4HgWH4339SdjnYgENacbY5wfk/zxTGg==", + "dev": true + }, + "babel-plugin-syntax-optional-catch-binding": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-optional-catch-binding/-/babel-plugin-syntax-optional-catch-binding-7.0.0-beta.3.tgz", + "integrity": "sha512-IDrRx+htXqZO0IvQ0Heru01LDfDvC2lIFeM19pVS0EHVLy4Bpj5Sg0o7joOjj1j8ewzgSJLC1FOXqj7zXVedkg==", + "dev": true + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz", + "integrity": "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==", + "dev": true + }, + "babel-plugin-transform-async-generator-functions": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-7.0.0-beta.3.tgz", + "integrity": "sha512-sIVkKihVjq930ONro7sMo080kyIznrEDdMmq4JX1OYtDVV9OiiUF/yrHnc2tBrldOzTYyD3iPeIskTDuRVAnfA==", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "7.0.0-beta.3", + "babel-plugin-syntax-async-generators": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-async-to-generator": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-7.0.0-beta.3.tgz", + "integrity": "sha512-LDOTVxH72pFNl9l9KQic0Pi0owwxvolcTg9IbA5QzdLo49Y9oe5GwYQxqHNGbVDOlm62iJ8cYbRA2+gLJpAzwQ==", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "7.0.0-beta.3", + "babel-plugin-syntax-async-functions": "7.0.0-beta.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-7.0.0-beta.3.tgz", + "integrity": "sha512-zrdLNzy22R6hzRrlSTPJWmN6N0Z11S0GPHE6R8SpSeAN4p9REgOOmNgfdHn5Nw3hDxWyvrPnBXdYug9HpBt8Yg==", + "dev": true + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-7.0.0-beta.3.tgz", + "integrity": "sha512-IzUjWeIa5670asiCA/xsyuH5lQYdsTJf3+yYssp/7/4KkUX7yWhP+L+VAihBGK9QtoyHE7dopIbRo/In07VWcQ==", + "dev": true + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-7.0.0-beta.3.tgz", + "integrity": "sha512-Jm4ozOLdFkZpMCXhJLQ0y/+Nh920jV0b5ORrKhSu1jW3uaokhINi6tCLgJrQ/CwKPbVHlra+JwPVN+pITJjE7w==", + "dev": true, + "requires": { + "babel-template": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3", + "lodash": "^4.2.0" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-7.0.0-beta.3.tgz", + "integrity": "sha512-4vH3pzhx3oZ6rphe3EDCkxFfMsWlJoEMSk8pIHnfXm4dOL+goij5mrxqoTAh7W/DcMzpakZOdKkgsgg+iujg8Q==", + "dev": true, + "requires": { + "babel-helper-annotate-as-pure": "7.0.0-beta.3", + "babel-helper-define-map": "7.0.0-beta.3", + "babel-helper-function-name": "7.0.0-beta.3", + "babel-helper-optimise-call-expression": "7.0.0-beta.3", + "babel-helper-replace-supers": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-7.0.0-beta.3.tgz", + "integrity": "sha512-HazW3EWODEav1LRA+FBPq3Oefpg0UOBN7yS1xV8HxNLwlWneg6g0dNnS2piVj8GJUk1N/wYa4SiMO0pOcgOcAA==", + "dev": true, + "requires": { + "babel-template": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-7.0.0-beta.3.tgz", + "integrity": "sha512-BDjEuIS7SCI7mGEO8lfvo4f3UAVLwZYjHwt1WqRNklc1Y0mcY0/UZzM3NHoa+eBxkNPl5XApwyha/rxW3XyLUQ==", + "dev": true + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-7.0.0-beta.3.tgz", + "integrity": "sha512-JLLlw+1XnYrgnVSMS56QN4idRyZJWBREQf0HmaaJQEw3Em+TwO84Tvjgvv7GBxCbXvX4wY+Teuncs2tJd6yqjg==", + "dev": true, + "requires": { + "babel-types": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-7.0.0-beta.3.tgz", + "integrity": "sha512-eaJ5ClU6XF9na+Fcle4sYfYEQtqBMy0CFg6H1dJbtmnWAkzYz4wnwR1unUe0vz5RPp5lA43ECWTTZE+1aH+e3A==", + "dev": true + }, + "babel-plugin-transform-es2015-function-name": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-7.0.0-beta.3.tgz", + "integrity": "sha512-ioqyK/Y9/OlJ5L0pqYS9RosFh6PaIGFjT/zJdkoUKJgeK+H3ulEJ/YxqgLlSA0wuhPca0ztLD3xBEk5NR9Hwzw==", + "dev": true, + "requires": { + "babel-helper-function-name": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-7.0.0-beta.3.tgz", + "integrity": "sha512-Zc+kpYJymHtHom+uw+NoNnnyPbxcbyFgeceMFVApavd49JtfdIj7pZS/XpRlxffjIAHSF2D/xDt+bRhq8zk69Q==", + "dev": true + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-7.0.0-beta.3.tgz", + "integrity": "sha512-Fm1mLWiaDy4457O880czMMpu4IiYOdjr1Hy8gz39BvV722QPo5Y2mITo6vO4oNYtaBIc3L0XlwBWavXEDe8iRA==", + "dev": true, + "requires": { + "babel-helper-module-transforms": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-7.0.0-beta.3.tgz", + "integrity": "sha512-RcRIKOAerrm2M5+w8ITVoadLynjU4inaw+VtZwq1G10VBNn2bbik7hfXWdgnTUdHE8h3TGAafHX9Iw0Zxxuhrg==", + "dev": true, + "requires": { + "babel-helper-module-transforms": "7.0.0-beta.3", + "babel-helper-simple-access": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-7.0.0-beta.3.tgz", + "integrity": "sha512-i621ym8MDfuG3gmgq22uS6JLj+bIJl0mMsZDI/s3457aAPKDl5HwyWGjxcVZHw6WpSKGf4ulqvospsgXOMQ4bA==", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-7.0.0-beta.3.tgz", + "integrity": "sha512-sBn8Dtg2r8QCRmm8pT9kpNSn0qnOorN+gYy45gUwf9NBt6oGftncuecMlj1Mo3NCyRqHQ1WnwHLX4C3yDB5LPg==", + "dev": true, + "requires": { + "babel-helper-module-transforms": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-7.0.0-beta.3.tgz", + "integrity": "sha512-yNMxez22uwWZ17nKH+PbZl4sIq7VCqjbOXF8B7pItq2cGRDH2wTbdpRCkWWfIJyxoXR9JYftSj4g95Ev+ris5g==", + "dev": true, + "requires": { + "babel-helper-replace-supers": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-7.0.0-beta.3.tgz", + "integrity": "sha512-0LdLhxyhIZz5y+1jfRSM7uBen5dCIft3KWwLbr/Wy3Amz9V4Mnfn1mr25BIBDL/RTNYpZGrJ2DWan7KD7DoHEA==", + "dev": true, + "requires": { + "babel-helper-call-delegate": "7.0.0-beta.3", + "babel-helper-get-function-arity": "7.0.0-beta.3", + "babel-template": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-7.0.0-beta.3.tgz", + "integrity": "sha512-PuyQlEurcTfp7pCf3qLEeaDUNJdnxWJ70DjjNQbSW7Q4U2oLYnXrgNcnNfyUumdwMkJQnA6xI20plRT42AEmVw==", + "dev": true, + "requires": { + "babel-types": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-7.0.0-beta.3.tgz", + "integrity": "sha512-D6fi9kAvi+IMcdeOUxgJUFSRlfo0iG2Bn1ZiB43xbtgVgKrA/rerWwQxGuUHhp0lN5lbRSCEpV6tMx+vrYsp1w==", + "dev": true + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-7.0.0-beta.3.tgz", + "integrity": "sha512-ccZeHcyA0rs2L2OPbACECpHoYJa3nxLcAlNfabGfM/l8mPaZ+C/YDJMLRcGP/37eC3pTA+G9+jPK7i5wT/6QaA==", + "dev": true, + "requires": { + "babel-helper-regex": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-7.0.0-beta.3.tgz", + "integrity": "sha512-7W++eDsz4JNm+V2T/KNfYXD5fjtUv4n1aqR1zl1jVoA7lbRWp3Y0ipWJqNHKhJg8Q5B9U/FOTPxJOBtHRp+HBQ==", + "dev": true + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-7.0.0-beta.3.tgz", + "integrity": "sha512-tR3r8pdT4mW1lOMyoHDGbwp3wNlY1ks1K/fI0G/nZeZLQcRZm+XQEf8ia0DC17eUFCmrduJw/AyqC7Z6sCZb1A==", + "dev": true + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-7.0.0-beta.3.tgz", + "integrity": "sha512-Yov86wC/0ZcBEXzeFONacrDIkX/7cXQ/lJjH0ajP5scYOFzBji8DGAGW7mRn/OeY3c+/MBGkTNQhA+ojJsiFhA==", + "dev": true, + "requires": { + "babel-helper-regex": "7.0.0-beta.3", + "regexpu-core": "^4.1.3" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-7.0.0-beta.3.tgz", + "integrity": "sha512-5RaRPN5I+vyL6gyxriauB8wOncBUmDJbcUUGy0V8agBrnakCG5Fr2uiLuVPzKXAoac7CS3dtmTv+vObyvcxAMg==", + "dev": true, + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "7.0.0-beta.3", + "babel-plugin-syntax-exponentiation-operator": "7.0.0-beta.0" + } + }, + "babel-plugin-transform-new-target": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-new-target/-/babel-plugin-transform-new-target-7.0.0-beta.3.tgz", + "integrity": "sha512-zoezg2Z3OIIwtk1PrVpn6zLNgw3/Kff2ZMWLWMDkPGHS0s7f2Gy2HCC8DZqITFUDGujOOopEE2acqKi8P7wx0g==", + "dev": true + }, + "babel-plugin-transform-object-rest-spread": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-7.0.0-beta.3.tgz", + "integrity": "sha512-NOlhrq1CmxyuI94vNsqMhRPMuL5VG2EKUOIJQ0bwNiXBiwWRLdPoWyPT+Irrx5g4g0PkFgA46tnRj7Dc4ZGsxg==", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-optional-catch-binding": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-optional-catch-binding/-/babel-plugin-transform-optional-catch-binding-7.0.0-beta.3.tgz", + "integrity": "sha512-Gx4L2A1rXCboKxqdrwXq8HKU/e1xJkBYZJZ2b7ISE0KOp4CNQeX1+1MSWjC3e0habFIMRAATJ3UiKmqty3oOzA==", + "dev": true, + "requires": { + "babel-plugin-syntax-optional-catch-binding": "7.0.0-beta.3" + } + }, + "babel-plugin-transform-regenerator": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-7.0.0-beta.3.tgz", + "integrity": "sha512-25qxAISuEL+MtISK0cShFQ3T8MUh3rbWAVqqFORTezcxBaxr28SNQR75ZdwkiNINEDZ/r7klLcxjNDQgJ67+MA==", + "dev": true, + "requires": { + "regenerator-transform": "^0.11.0" + }, + "dependencies": { + "regenerator-transform": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.11.1.tgz", + "integrity": "sha512-q8SAPMEyARQHzyXNWNrlz5oNnI6k4yo8ncEcvH1aXjUCqyVQ7TeV/AttqBLcySCReXVk/+fUydo/RaEIAOnRfA==", + "dev": true, + "requires": { + "babel-types": "7.0.0-beta.3", + "private": "^0.1.6" + } + } + } + }, + "babel-plugin-transform-unicode-property-regex": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-unicode-property-regex/-/babel-plugin-transform-unicode-property-regex-2.0.5.tgz", + "integrity": "sha512-Q3L4R7tGc5z7FIGNt9TqzIChsiMK3xn+4qkmluQtnWyUSwQyzzYmXKDOdOHVaCRAM/fDnZsG+TT5GxaVGACxiQ==", + "dev": true, + "requires": { + "babel-helper-regex": "^6.26.0", + "regexpu-core": "^4.1.3" + }, + "dependencies": { + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + } + } + }, + "babel-preset-env": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-7.0.0-beta.3.tgz", + "integrity": "sha512-i7XlRdAxUyPeeaGzf2RxkHODE/N646ydnZ7sQe54rTlUjIdg7wEE/5t40Gf/by3er8fg3kEr8YBJo0f+A3v9qA==", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "7.0.0-beta.3", + "babel-plugin-syntax-async-generators": "7.0.0-beta.3", + "babel-plugin-syntax-object-rest-spread": "7.0.0-beta.3", + "babel-plugin-syntax-optional-catch-binding": "7.0.0-beta.3", + "babel-plugin-syntax-trailing-function-commas": "7.0.0-beta.0", + "babel-plugin-transform-async-generator-functions": "7.0.0-beta.3", + "babel-plugin-transform-async-to-generator": "7.0.0-beta.3", + "babel-plugin-transform-es2015-arrow-functions": "7.0.0-beta.3", + "babel-plugin-transform-es2015-block-scoped-functions": "7.0.0-beta.3", + "babel-plugin-transform-es2015-block-scoping": "7.0.0-beta.3", + "babel-plugin-transform-es2015-classes": "7.0.0-beta.3", + "babel-plugin-transform-es2015-computed-properties": "7.0.0-beta.3", + "babel-plugin-transform-es2015-destructuring": "7.0.0-beta.3", + "babel-plugin-transform-es2015-duplicate-keys": "7.0.0-beta.3", + "babel-plugin-transform-es2015-for-of": "7.0.0-beta.3", + "babel-plugin-transform-es2015-function-name": "7.0.0-beta.3", + "babel-plugin-transform-es2015-literals": "7.0.0-beta.3", + "babel-plugin-transform-es2015-modules-amd": "7.0.0-beta.3", + "babel-plugin-transform-es2015-modules-commonjs": "7.0.0-beta.3", + "babel-plugin-transform-es2015-modules-systemjs": "7.0.0-beta.3", + "babel-plugin-transform-es2015-modules-umd": "7.0.0-beta.3", + "babel-plugin-transform-es2015-object-super": "7.0.0-beta.3", + "babel-plugin-transform-es2015-parameters": "7.0.0-beta.3", + "babel-plugin-transform-es2015-shorthand-properties": "7.0.0-beta.3", + "babel-plugin-transform-es2015-spread": "7.0.0-beta.3", + "babel-plugin-transform-es2015-sticky-regex": "7.0.0-beta.3", + "babel-plugin-transform-es2015-template-literals": "7.0.0-beta.3", + "babel-plugin-transform-es2015-typeof-symbol": "7.0.0-beta.3", + "babel-plugin-transform-es2015-unicode-regex": "7.0.0-beta.3", + "babel-plugin-transform-exponentiation-operator": "7.0.0-beta.3", + "babel-plugin-transform-new-target": "7.0.0-beta.3", + "babel-plugin-transform-object-rest-spread": "7.0.0-beta.3", + "babel-plugin-transform-optional-catch-binding": "7.0.0-beta.3", + "babel-plugin-transform-regenerator": "7.0.0-beta.3", + "babel-plugin-transform-unicode-property-regex": "^2.0.5", + "browserslist": "^2.4.0", + "invariant": "^2.2.2", + "semver": "^5.3.0" + }, + "dependencies": { + "browserslist": { + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz", + "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000792", + "electron-to-chromium": "^1.3.30" + } + } + } + }, + "babel-register": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-7.0.0-beta.3.tgz", + "integrity": "sha512-9H/TMXFuG7iDGEs/wakN9lFLmfpqNGg8YHzZ5Tah5UER7veLIPEspAwxKsGNA/4+X4z30tyBNoBhW6JkC9AKFQ==", + "dev": true, + "requires": { + "babel-core": "7.0.0-beta.3", + "core-js": "^2.4.0", + "find-cache-dir": "^1.0.0", + "home-or-tmp": "^3.0.0", + "lodash": "^4.2.0", + "mkdirp": "^0.5.1", + "pirates": "^3.0.1", + "source-map-support": "^0.4.2" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-7.0.0-beta.3.tgz", + "integrity": "sha512-urJduLja89kSDGqY8ryw8iIwQnMl30IvhMtMNmDD7vBX0l0oylaLgK+7df/9ODX9vR/PhXuif6HYl5HlzAKXMg==", + "dev": true, + "requires": { + "babel-code-frame": "7.0.0-beta.3", + "babel-traverse": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3", + "babylon": "7.0.0-beta.27", + "lodash": "^4.2.0" + }, + "dependencies": { + "babylon": { + "version": "7.0.0-beta.27", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.27.tgz", + "integrity": "sha512-ksRx+r8eFIfdt63MCgLc9VxGL7W3jcyveQvMpNMVHgW+eb9mq3Xbm45FLCNkw8h92RvoNp4uuiwzcCEwxjDBZg==", + "dev": true + } + } + }, + "babel-traverse": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-7.0.0-beta.3.tgz", + "integrity": "sha512-xyh/aPYuedMAfQlSj2kjHjsEmY5/Dpxs576L05DySAVMrV+ADX6l4mTOLysAEGwJfkePJlDLhFuS6SKaxv1V7w==", + "dev": true, + "requires": { + "babel-code-frame": "7.0.0-beta.3", + "babel-helper-function-name": "7.0.0-beta.3", + "babel-types": "7.0.0-beta.3", + "babylon": "7.0.0-beta.27", + "debug": "^3.0.1", + "globals": "^10.0.0", + "invariant": "^2.2.0", + "lodash": "^4.2.0" + }, + "dependencies": { + "babylon": { + "version": "7.0.0-beta.27", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.27.tgz", + "integrity": "sha512-ksRx+r8eFIfdt63MCgLc9VxGL7W3jcyveQvMpNMVHgW+eb9mq3Xbm45FLCNkw8h92RvoNp4uuiwzcCEwxjDBZg==", + "dev": true + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-10.4.0.tgz", + "integrity": "sha512-uNUtxIZpGyuaq+5BqGGQHsL4wUlJAXRqOm6g3Y48/CWNGTLONgBibI0lh6lGxjR2HljFYUfszb+mk4WkgMntsA==", + "dev": true + } + } + }, + "babel-types": { + "version": "7.0.0-beta.3", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-7.0.0-beta.3.tgz", + "integrity": "sha512-36k8J+byAe181OmCMawGhw+DtKO7AwexPVtsPXoMfAkjtZgoCX3bEuHWfdE5sYxRM8dojvtG/+O08M0Z/YDC6w==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" + } + }, + "babylon": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz", + "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "binary-extensions": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", + "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "dev": true + }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "dev": true + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.3.4.tgz", + "integrity": "sha512-u5iz+ijIMUlmV8blX82VGFrB9ecnUg5qEt55CMZ/YJEhha+d8qpBfOFuutJ6F/VKRXjZoD33b6uvarpPxcl3RA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000899", + "electron-to-chromium": "^1.3.82", + "node-releases": "^1.0.1" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cacache": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", + "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", + "dev": true, + "requires": { + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "caching-transform": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", + "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "dev": true, + "requires": { + "hasha": "^3.0.0", + "make-dir": "^2.0.0", + "package-hash": "^3.0.0", + "write-file-atomic": "^2.4.2" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "^0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "http://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30000910", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000910.tgz", + "integrity": "sha512-u/nxtHGAzCGZzIxt3dA/tpSPOcirBZFWKwz1EPz4aaupnBI2XR0Rbr74g0zc6Hzy41OEM4uMoZ38k56TpYAWjQ==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chai-dom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/chai-dom/-/chai-dom-1.8.1.tgz", + "integrity": "sha512-ysWinPU3fc+Bp+xMn/u2/PQyk65jnnCZl0alWupUuFFMGaG+KxrUnsoYOgjMDhSKPkm3WqE/5RTnOowIb7asMg==", + "dev": true + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", + "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.2.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "lodash.debounce": "^4.0.8", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.5" + } + }, + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz", + "integrity": "sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true + }, + "cp-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", + "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "make-dir": "^2.0.0", + "nested-error-stacks": "^2.0.0", + "pify": "^4.0.1", + "safe-buffer": "^5.0.1" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-env": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz", + "integrity": "sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.5", + "is-windows": "^1.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "cssom": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz", + "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==", + "dev": true + }, + "cssstyle": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.3.1.tgz", + "integrity": "sha512-tNvaxM5blOnxanyxI6panOsnfiyLRj3HV4qjqqS45WPNS1usdYWRUQjqTEEELK73lpeP/1KoIGYUwrBn/VcECA==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, + "cyclist": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", + "dev": true + }, + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", + "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "duplexify": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", + "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ecstatic": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", + "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "dev": true, + "requires": { + "he": "^1.1.1", + "mime": "^1.6.0", + "minimist": "^1.1.0", + "url-join": "^2.0.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "electron-to-chromium": { + "version": "1.3.84", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.84.tgz", + "integrity": "sha512-IYhbzJYOopiTaNWMBp7RjbecUBsbnbDneOP86f3qvS0G0xfzwNSvMJpTrvi5/Y1gU7tg2NAgeg8a8rCYvW9Whw==", + "dev": true + }, + "elliptic": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", + "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", + "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "eslint": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.9.0.tgz", + "integrity": "sha512-g4KWpPdqN0nth+goDNICNXGfJF7nNnepthp46CAlJoJtC5K/cLu3NgCM3AHu1CkJ5Hzt9V0Y0PBAO6Ay/gGb+w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.5.3", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^2.1.0", + "eslint-scope": "^4.0.0", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^4.0.0", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "imurmurhash": "^0.1.4", + "inquirer": "^6.1.0", + "is-resolvable": "^1.1.0", + "js-yaml": "^3.12.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.5", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.0.2", + "text-table": "^0.2.0" + }, + "dependencies": { + "eslint-scope": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + } + } + }, + "eslint-loader": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.1.1.tgz", + "integrity": "sha512-1GrJFfSevQdYpoDzx8mEE2TDWsb/zmFuY09l6hURg1AeFIKQOvZ+vH0UPjzmd1CZIbfTV5HUkMeBmFiDBkgIsQ==", + "dev": true, + "requires": { + "loader-fs-cache": "^1.0.0", + "loader-utils": "^1.0.2", + "object-assign": "^4.0.1", + "object-hash": "^1.1.4", + "rimraf": "^2.6.1" + } + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", + "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.0.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", + "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", + "dev": true, + "requires": { + "acorn": "^6.0.2", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", + "dev": true + }, + "events": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", + "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + } + }, + "flush-write-stream": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", + "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "follow-redirects": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", + "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", + "dev": true, + "requires": { + "debug": "^3.2.6" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "foreground-child": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true, + "requires": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + } + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "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" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "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" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-modules-path": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/global-modules-path/-/global-modules-path-2.3.0.tgz", + "integrity": "sha512-HchvMJNYh9dGSCy8pOQ2O8u/hoXaL+0XhnrwH0RyLiSXMMTl9W3N6KUU73+JFOg5PGjtzl6VZzUQsnrpm7Szag==", + "dev": true + }, + "globals": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", + "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==", + "dev": true + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", + "dev": true + }, + "handlebars": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.0.tgz", + "integrity": "sha512-xkRtOt3/3DzTKMOt3xahj2M/EqNhY988T+imYSlMgs5fVhLN2fmKVVj0LtEGmb+3UUYV5Qmm1052Mm3dIQxOvw==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "commander": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz", + "integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==", + "dev": true, + "optional": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "uglify-js": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + } + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", + "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hasha": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", + "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "dev": true, + "requires": { + "is-stream": "^1.0.1" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "home-or-tmp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-3.0.0.tgz", + "integrity": "sha1-V6j+JM8zzdUkhgoVgh3cJchmcfs=", + "dev": true + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "http-proxy": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "dev": true, + "requires": { + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-server": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz", + "integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==", + "dev": true, + "requires": { + "colors": "1.0.3", + "corser": "~2.0.0", + "ecstatic": "^3.0.0", + "http-proxy": "^1.8.1", + "opener": "~1.4.0", + "optimist": "0.6.x", + "portfinder": "^1.0.13", + "union": "~0.4.3" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", + "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "inquirer": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz", + "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.0", + "figures": "^2.0.0", + "lodash": "^4.17.10", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.1.0", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-nPvSZsVlbG9aLhZYaC3Oi1gT/tpyo3Yt5fNyf6NmcKIayz4VV/txxJFFKAK/gU4dcNn8ehsanBbVHVl0+amOLA==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.0.0.tgz", + "integrity": "sha512-eQY9vN9elYjdgN9Iv6NS/00bptm02EBBk70lRMaVjeA6QYocQgenVrSgC28TJurdnZa80AGO3ASdFN+w/njGiQ==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.1", + "semver": "^5.5.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "dev": true, + "requires": { + "handlebars": "^4.1.2" + } + }, + "js-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz", + "integrity": "sha512-PxfGzSs0ztShKrUYPIn5r0MtyAhYcCwmndozzpz8YObbPnD1jFxzlBGbRnX2mIu6Z13xN6+PTu05TQFnZFlzow==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsdom": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.11.0.tgz", + "integrity": "sha512-ou1VyfjwsSuWkudGxb03FotDajxAto6USAlmMZjE2lc0jCznt7sBWkhfRBRaWwbnmDqdMSTKTLT5d9sBFkkM7A==", + "dev": true, + "requires": { + "abab": "^1.0.4", + "acorn": "^5.3.0", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": ">= 0.3.1 < 0.4.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.0", + "escodegen": "^1.9.0", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.2.0", + "nwsapi": "^2.0.0", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.83.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.3", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^4.0.0", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true + } + } + }, + "jsdom-global": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", + "integrity": "sha1-a9KZwTsMRiay2iwDk81DhdYGrLk=", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "loader-fs-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz", + "integrity": "sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw=", + "dev": true, + "requires": { + "find-cache-dir": "^0.1.1", + "mkdirp": "0.5.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + } + } + }, + "loader-runner": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.1.tgz", + "integrity": "sha512-By6ZFY7ETWOc9RFaAIb23IjJVcM4dvJC/N57nmdz9RSkMXvAXGI7SyVlAw3v8vjtDRlqThgVDVmTnr9fqMlxkw==", + "dev": true + }, + "loader-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0" + }, + "dependencies": { + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.4.tgz", + "integrity": "sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "math-random": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mem": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", + "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^1.1.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", + "dev": true + }, + "mime-types": { + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", + "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "dev": true, + "requires": { + "mime-db": "~1.37.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mississippi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", + "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz", + "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.3.1", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.3", + "he": "1.1.1", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + }, + "dependencies": { + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "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" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true + }, + "nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-libs-browser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", + "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^1.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.0", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.10.3", + "vm-browserify": "0.0.4" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-releases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.0.4.tgz", + "integrity": "sha512-GqRV9GcHw8JCRDaP/JoeNMNzEGzHAknMvIHqMb2VeTOmg1Cf9+ej8bkV12tHfzWHQMCkQ5zUFgwFUkfraynNCw==", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nwsapi": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz", + "integrity": "sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==", + "dev": true + }, + "nyc": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", + "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "caching-transform": "^3.0.2", + "convert-source-map": "^1.6.0", + "cp-file": "^6.2.0", + "find-cache-dir": "^2.1.0", + "find-up": "^3.0.0", + "foreground-child": "^1.5.6", + "glob": "^7.1.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "merge-source-map": "^1.1.0", + "resolve-from": "^4.0.0", + "rimraf": "^2.6.3", + "signal-exit": "^3.0.2", + "spawn-wrap": "^1.4.2", + "test-exclude": "^5.2.3", + "uuid": "^3.3.2", + "yargs": "^13.2.2", + "yargs-parser": "^13.0.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", + "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/parser": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz", + "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==", + "dev": true + }, + "@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/traverse": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz", + "integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.4.5", + "@babel/types": "^7.4.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "@babel/types": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", + "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": false, + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", + "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", + "dev": true + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": false, + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": false, + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": false, + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": false, + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-hash": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", + "dev": true + }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "opener": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", + "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", + "dev": true + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", + "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", + "dev": true, + "requires": { + "execa": "^0.10.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "output-file-sync": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz", + "integrity": "sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "is-plain-obj": "^1.1.0", + "mkdirp": "^0.5.1" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "package-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", + "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^3.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "dev": true + }, + "parallel-transform": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", + "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "dev": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parse-asn1": { + "version": "5.1.1", + "resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", + "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pirates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-3.0.2.tgz", + "integrity": "sha512-c5CgUJq6H2k6MJz72Ak1F5sN9n9wlSlJyEnwvpm9/y3WB4E3pHBDT2c6PEiS1vyJvq2bUxUAIu0EGf8Cx4Ic7Q==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "portfinder": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz", + "integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==", + "dev": true, + "requires": { + "async": "^1.5.2", + "debug": "^2.2.0", + "mkdirp": "0.5.x" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", + "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dev": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "randombytes": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", + "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", + "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz", + "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "regenerator-transform": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz", + "integrity": "sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==", + "dev": true, + "requires": { + "private": "^0.1.6" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "regexpu-core": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz", + "integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^7.0.0", + "regjsgen": "^0.4.0", + "regjsparser": "^0.3.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.0.2" + } + }, + "regjsgen": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz", + "integrity": "sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA==", + "dev": true + }, + "regjsparser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz", + "integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "dev": true, + "requires": { + "lodash": "^4.13.1" + } + }, + "request-promise-native": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", + "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "dev": true, + "requires": { + "request-promise-core": "1.1.1", + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "http://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rxjs": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", + "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "serialize-javascript": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", + "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spawn-wrap": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", + "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", + "dev": true, + "requires": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, + "spdx-correct": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", + "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", + "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", + "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", + "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.1" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "stream-browserify": { + "version": "2.0.1", + "resolved": "http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, + "table": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz", + "integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==", + "dev": true, + "requires": { + "ajv": "^6.5.3", + "lodash": "^4.17.10", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, + "tapable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.0.tgz", + "integrity": "sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==", + "dev": true + }, + "terser": { + "version": "3.10.12", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.10.12.tgz", + "integrity": "sha512-3ODPC1eVt25EVNb04s/PkHxOmzKBQUF6bwwuR6h2DbEF8/j265Y1UkwNtOk9am/pRxfJ5HPapOlUlO6c16mKQQ==", + "dev": true, + "requires": { + "commander": "~2.17.1", + "source-map": "~0.6.1", + "source-map-support": "~0.5.6" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "terser-webpack-plugin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz", + "integrity": "sha512-61lV0DSxMAZ8AyZG7/A4a3UPlrbOBo8NIQ4tJzLPAdGOQ+yoNC7l5ijEow27lBAL2humer01KLS6bGIMYQxKoA==", + "dev": true, + "requires": { + "cacache": "^11.0.2", + "find-cache-dir": "^2.0.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "terser": "^3.8.1", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" + }, + "dependencies": { + "cacache": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.1.tgz", + "integrity": "sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==", + "dev": true, + "requires": { + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "figgy-pudding": "^3.1.0", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.3", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^6.0.0", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" + } + }, + "find-cache-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz", + "integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "p-limit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", + "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + } + } + }, + "test-exclude": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.0.0.tgz", + "integrity": "sha512-bO3Lj5+qFa9YLfYW2ZcXMOV1pmQvw+KS/DpjqhyX6Y6UZ8zstpZJ+mA2ERkXfpOqhxsJlQiLeVXD3Smsrs6oLw==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^1.0.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "timers-browserify": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-es": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", + "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", + "dev": true, + "requires": { + "commander": "~2.13.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "uglifyjs-webpack-plugin": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz", + "integrity": "sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==", + "dev": true, + "requires": { + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "schema-utils": "^0.4.5", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "uglify-es": "^3.3.4", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz", + "integrity": "sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz", + "integrity": "sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg==", + "dev": true + }, + "union": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz", + "integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=", + "dev": true, + "requires": { + "qs": "~2.3.3" + }, + "dependencies": { + "qs": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz", + "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=", + "dev": true + } + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz", + "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz", + "integrity": "sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "webpack": { + "version": "4.26.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.26.0.tgz", + "integrity": "sha512-J/dP9SJIc5OtX2FZ/+U9ikQtd6H6Mcbqt0xeXtmPwYGDKf8nkbOQQA9KL2Y0rJOsN1Al9Pdn+/j63X58ub8gvQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.7.11", + "@webassemblyjs/helper-module-context": "1.7.11", + "@webassemblyjs/wasm-edit": "1.7.11", + "@webassemblyjs/wasm-parser": "1.7.11", + "acorn": "^5.6.2", + "acorn-dynamic-import": "^3.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "chrome-trace-event": "^1.0.0", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.0", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "micromatch": "^3.1.8", + "mkdirp": "~0.5.0", + "neo-async": "^2.5.0", + "node-libs-browser": "^2.0.0", + "schema-utils": "^0.4.4", + "tapable": "^1.1.0", + "terser-webpack-plugin": "^1.1.0", + "watchpack": "^1.5.0", + "webpack-sources": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true + }, + "eslint-scope": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + } + } + }, + "webpack-cli": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.1.2.tgz", + "integrity": "sha512-Cnqo7CeqeSvC6PTdts+dywNi5CRlIPbLx1AoUPK2T6vC1YAugMG3IOoO9DmEscd+Dghw7uRlnzV1KwOe5IrtgQ==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.0", + "global-modules-path": "^2.3.0", + "import-local": "^2.0.0", + "interpret": "^1.1.0", + "loader-utils": "^1.1.0", + "supports-color": "^5.5.0", + "v8-compile-cache": "^2.0.2", + "yargs": "^12.0.2" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", + "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + } + } + }, + "webpack-sources": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", + "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "worker-farm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", + "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true + }, + "yargs": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz", + "integrity": "sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^8.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs-parser": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", + "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } +}