diff --git a/.gitignore b/.gitignore index 0e71421ee7..21586748b7 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,10 @@ jmeter/src/main/resources/*-JMeter.csv **/nb-configuration.xml core-scala/.cache-main core-scala/.cache-tests + + +persistence-modules/hibernate5/transaction.log +apache-avro/src/main/java/com/baeldung/avro/model/ +jta/transaction-logs/ +software-security/sql-injection-samples/derby.log +spring-soap/src/main/java/com/baeldung/springsoap/gen/ \ No newline at end of file diff --git a/akka-http/pom.xml b/akka-http/pom.xml index 05e50d2229..6d73f2f2e6 100644 --- a/akka-http/pom.xml +++ b/akka-http/pom.xml @@ -41,7 +41,6 @@ UTF-8 UTF-8 - 1.8 10.0.11 2.5.11 diff --git a/algorithms-genetic/pom.xml b/algorithms-genetic/pom.xml index fc6d36dac1..56f6a31525 100644 --- a/algorithms-genetic/pom.xml +++ b/algorithms-genetic/pom.xml @@ -54,7 +54,6 @@ - 1.16.12 3.6.1 3.7.0 3.9.0 diff --git a/algorithms-miscellaneous-1/README.md b/algorithms-miscellaneous-1/README.md index 7ed805f7c4..ea6d6f379b 100644 --- a/algorithms-miscellaneous-1/README.md +++ b/algorithms-miscellaneous-1/README.md @@ -17,3 +17,4 @@ - [Java Two Pointer Technique](https://www.baeldung.com/java-two-pointer-technique) - [Permutations of an Array in Java](https://www.baeldung.com/java-array-permutations) - [Implementing Simple State Machines with Java Enums](https://www.baeldung.com/java-enum-simple-state-machine) +- [Generate Combinations in Java](https://www.baeldung.com/java-combinations-algorithm) diff --git a/algorithms-miscellaneous-1/pom.xml b/algorithms-miscellaneous-1/pom.xml index 5006670dd9..30130208f8 100644 --- a/algorithms-miscellaneous-1/pom.xml +++ b/algorithms-miscellaneous-1/pom.xml @@ -39,6 +39,11 @@ ${org.assertj.core.version} test + + com.github.dpaukov + combinatoricslib3 + 3.3.0 + @@ -74,11 +79,10 @@ - 1.16.12 3.6.1 3.9.0 1.11 - 25.1-jre + 27.0.1-jre \ No newline at end of file diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/ApacheCommonsCombinationGenerator.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/ApacheCommonsCombinationGenerator.java new file mode 100644 index 0000000000..40142ce940 --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/ApacheCommonsCombinationGenerator.java @@ -0,0 +1,29 @@ +package com.baeldung.algorithms.combination; + +import java.util.Arrays; +import java.util.Iterator; + +import org.apache.commons.math3.util.CombinatoricsUtils; + +public class ApacheCommonsCombinationGenerator { + + private static final int N = 6; + private static final int R = 3; + + /** + * Print all combinations of r elements from a set + * @param n - number of elements in set + * @param r - number of elements in selection + */ + public static void generate(int n, int r) { + Iterator iterator = CombinatoricsUtils.combinationsIterator(n, r); + while (iterator.hasNext()) { + final int[] combination = iterator.next(); + System.out.println(Arrays.toString(combination)); + } + } + + public static void main(String[] args) { + generate(N, R); + } +} \ No newline at end of file diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/CombinatoricsLibCombinationGenerator.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/CombinatoricsLibCombinationGenerator.java new file mode 100644 index 0000000000..0afdeefb8b --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/CombinatoricsLibCombinationGenerator.java @@ -0,0 +1,13 @@ +package com.baeldung.algorithms.combination; + +import org.paukov.combinatorics3.Generator; + +public class CombinatoricsLibCombinationGenerator { + + public static void main(String[] args) { + Generator.combination(0, 1, 2, 3, 4, 5) + .simple(3) + .stream() + .forEach(System.out::println); + } +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/GuavaCombinationsGenerator.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/GuavaCombinationsGenerator.java new file mode 100644 index 0000000000..d2783881ba --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/GuavaCombinationsGenerator.java @@ -0,0 +1,17 @@ +package com.baeldung.algorithms.combination; + +import java.util.Arrays; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +public class GuavaCombinationsGenerator { + + public static void main(String[] args) { + + Set> combinations = Sets.combinations(ImmutableSet.of(0, 1, 2, 3, 4, 5), 3); + System.out.println(combinations.size()); + System.out.println(Arrays.toString(combinations.toArray())); + } +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/IterativeCombinationGenerator.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/IterativeCombinationGenerator.java new file mode 100644 index 0000000000..676d2f41e3 --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/IterativeCombinationGenerator.java @@ -0,0 +1,52 @@ +package com.baeldung.algorithms.combination; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class IterativeCombinationGenerator { + + private static final int N = 5; + private static final int R = 2; + + /** + * Generate all combinations of r elements from a set + * @param n the number of elements in input set + * @param r the number of elements in a combination + * @return the list containing all combinations + */ + public List generate(int n, int r) { + List combinations = new ArrayList<>(); + int[] combination = new int[r]; + + // initialize with lowest lexicographic combination + for (int i = 0; i < r; i++) { + combination[i] = i; + } + + while (combination[r - 1] < n) { + combinations.add(combination.clone()); + + // generate next combination in lexicographic order + int t = r - 1; + while (t != 0 && combination[t] == n - r + t) { + t--; + } + combination[t]++; + for (int i = t + 1; i < r; i++) { + combination[i] = combination[i - 1] + 1; + } + } + + return combinations; + } + + public static void main(String[] args) { + IterativeCombinationGenerator generator = new IterativeCombinationGenerator(); + List combinations = generator.generate(N, R); + System.out.println(combinations.size()); + for (int[] combination : combinations) { + System.out.println(Arrays.toString(combination)); + } + } +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/SelectionRecursiveCombinationGenerator.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/SelectionRecursiveCombinationGenerator.java new file mode 100644 index 0000000000..52305b8c2f --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/SelectionRecursiveCombinationGenerator.java @@ -0,0 +1,53 @@ +package com.baeldung.algorithms.combination; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class SelectionRecursiveCombinationGenerator { + + private static final int N = 6; + private static final int R = 3; + + /** + * Generate all combinations of r elements from a set + * @param n - number of elements in input set + * @param r - number of elements to be chosen + * @return the list containing all combinations + */ + public List generate(int n, int r) { + List combinations = new ArrayList<>(); + helper(combinations, new int[r], 0, n - 1, 0); + return combinations; + } + + /** + * Choose elements from set by recursing over elements selected + * @param combinations - List to store generated combinations + * @param data - current combination + * @param start - starting element of remaining set + * @param end - last element of remaining set + * @param index - number of elements chosen so far. + */ + private void helper(List combinations, int data[], int start, int end, int index) { + if (index == data.length) { + int[] combination = data.clone(); + combinations.add(combination); + } else { + int max = Math.min(end, end + 1 - data.length + index); + for (int i = start; i <= max; i++) { + data[index] = i; + helper(combinations, data, i + 1, end, index + 1); + } + } + } + + public static void main(String[] args) { + SelectionRecursiveCombinationGenerator generator = new SelectionRecursiveCombinationGenerator(); + List combinations = generator.generate(N, R); + for (int[] combination : combinations) { + System.out.println(Arrays.toString(combination)); + } + System.out.printf("generated %d combinations of %d items from %d ", combinations.size(), R, N); + } +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/SetRecursiveCombinationGenerator.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/SetRecursiveCombinationGenerator.java new file mode 100644 index 0000000000..a73447b31d --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/combination/SetRecursiveCombinationGenerator.java @@ -0,0 +1,50 @@ +package com.baeldung.algorithms.combination; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class SetRecursiveCombinationGenerator { + + private static final int N = 5; + private static final int R = 2; + + /** + * Generate all combinations of r elements from a set + * @param n - number of elements in set + * @param r - number of elements in selection + * @return the list containing all combinations + */ + public List generate(int n, int r) { + List combinations = new ArrayList<>(); + helper(combinations, new int[r], 0, n-1, 0); + return combinations; + } + + /** + * @param combinations - List to contain the generated combinations + * @param data - List of elements in the selection + * @param start - index of the starting element in the remaining set + * @param end - index of the last element in the set + * @param index - number of elements selected so far + */ + private void helper(List combinations, int data[], int start, int end, int index) { + if (index == data.length) { + int[] combination = data.clone(); + combinations.add(combination); + } else if (start <= end) { + data[index] = start; + helper(combinations, data, start + 1, end, index + 1); + helper(combinations, data, start + 1, end, index); + } + } + + public static void main(String[] args) { + SetRecursiveCombinationGenerator generator = new SetRecursiveCombinationGenerator(); + List combinations = generator.generate(N, R); + for (int[] combination : combinations) { + System.out.println(Arrays.toString(combination)); + } + System.out.printf("generated %d combinations of %d items from %d ", combinations.size(), R, N); + } +} diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/combination/CombinationUnitTest.java b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/combination/CombinationUnitTest.java new file mode 100644 index 0000000000..987b6ddae6 --- /dev/null +++ b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/combination/CombinationUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.algorithms.combination; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +import org.junit.Test; + +public class CombinationUnitTest { + + private static final int N = 5; + private static final int R = 3; + private static final int nCr = 10; + + @Test + public void givenSetAndSelectionSize_whenCalculatedUsingSetRecursiveAlgorithm_thenExpectedCount() { + SetRecursiveCombinationGenerator generator = new SetRecursiveCombinationGenerator(); + List selection = generator.generate(N, R); + assertEquals(nCr, selection.size()); + } + + @Test + public void givenSetAndSelectionSize_whenCalculatedUsingSelectionRecursiveAlgorithm_thenExpectedCount() { + SelectionRecursiveCombinationGenerator generator = new SelectionRecursiveCombinationGenerator(); + List selection = generator.generate(N, R); + assertEquals(nCr, selection.size()); + } + + @Test + public void givenSetAndSelectionSize_whenCalculatedUsingIterativeAlgorithm_thenExpectedCount() { + IterativeCombinationGenerator generator = new IterativeCombinationGenerator(); + List selection = generator.generate(N, R); + assertEquals(nCr, selection.size()); + } +} diff --git a/algorithms-miscellaneous-2/pom.xml b/algorithms-miscellaneous-2/pom.xml index d5f3172eaa..e85dd456a3 100644 --- a/algorithms-miscellaneous-2/pom.xml +++ b/algorithms-miscellaneous-2/pom.xml @@ -84,7 +84,6 @@ - 1.16.12 3.6.1 1.0.1 1.0.1 diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/relativelyprime/RelativelyPrime.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/relativelyprime/RelativelyPrime.java new file mode 100644 index 0000000000..fbea87be30 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/relativelyprime/RelativelyPrime.java @@ -0,0 +1,45 @@ +package com.baeldung.algorithms.relativelyprime; + +import java.math.BigInteger; + +class RelativelyPrime { + + static boolean iterativeRelativelyPrime(int a, int b) { + return iterativeGCD(a, b) == 1; + } + + static boolean recursiveRelativelyPrime(int a, int b) { + return recursiveGCD(a, b) == 1; + } + + static boolean bigIntegerRelativelyPrime(int a, int b) { + return BigInteger.valueOf(a).gcd(BigInteger.valueOf(b)).equals(BigInteger.ONE); + } + + private static int iterativeGCD(int a, int b) { + int tmp; + while (b != 0) { + if (a < b) { + tmp = a; + a = b; + b = tmp; + } + tmp = b; + b = a % b; + a = tmp; + } + return a; + } + + private static int recursiveGCD(int a, int b) { + if (b == 0) { + return a; + } + if (a < b) { + return recursiveGCD(b, a); + } + return recursiveGCD(b, a % b); + } + + +} diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeNode.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeNode.java new file mode 100644 index 0000000000..7905b752a9 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeNode.java @@ -0,0 +1,42 @@ +package com.baeldung.algorithms.reversingtree; + +public class TreeNode { + + private int value; + private TreeNode rightChild; + private TreeNode leftChild; + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public TreeNode getRightChild() { + return rightChild; + } + + public void setRightChild(TreeNode rightChild) { + this.rightChild = rightChild; + } + + public TreeNode getLeftChild() { + return leftChild; + } + + public void setLeftChild(TreeNode leftChild) { + this.leftChild = leftChild; + } + + public TreeNode(int value, TreeNode rightChild, TreeNode leftChild) { + this.value = value; + this.rightChild = rightChild; + this.leftChild = leftChild; + } + + public TreeNode(int value) { + this.value = value; + } +} diff --git a/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeReverser.java b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeReverser.java new file mode 100644 index 0000000000..6d3a9ddd31 --- /dev/null +++ b/algorithms-miscellaneous-2/src/main/java/com/baeldung/algorithms/reversingtree/TreeReverser.java @@ -0,0 +1,68 @@ +package com.baeldung.algorithms.reversingtree; + +import java.util.LinkedList; + +public class TreeReverser { + + public TreeNode createBinaryTree() { + + TreeNode leaf1 = new TreeNode(3); + TreeNode leaf2 = new TreeNode(1); + TreeNode leaf3 = new TreeNode(9); + TreeNode leaf4 = new TreeNode(6); + + TreeNode nodeLeft = new TreeNode(2, leaf1, leaf2); + TreeNode nodeRight = new TreeNode(7, leaf3, leaf4); + + TreeNode root = new TreeNode(4, nodeRight, nodeLeft); + + return root; + } + + public void reverseRecursive(TreeNode treeNode) { + if (treeNode == null) { + return; + } + + TreeNode temp = treeNode.getLeftChild(); + treeNode.setLeftChild(treeNode.getRightChild()); + treeNode.setRightChild(temp); + + reverseRecursive(treeNode.getLeftChild()); + reverseRecursive(treeNode.getRightChild()); + } + + public void reverseIterative(TreeNode treeNode) { + LinkedList queue = new LinkedList(); + + if (treeNode != null) { + queue.add(treeNode); + } + + while (!queue.isEmpty()) { + + TreeNode node = queue.poll(); + if (node.getLeftChild() != null) + queue.add(node.getLeftChild()); + if (node.getRightChild() != null) + queue.add(node.getRightChild()); + + TreeNode temp = node.getLeftChild(); + node.setLeftChild(node.getRightChild()); + node.setRightChild(temp); + } + } + + public String toString(TreeNode root) { + if (root == null) { + return ""; + } + + StringBuffer buffer = new StringBuffer(String.valueOf(root.getValue())).append(" "); + + buffer.append(toString(root.getLeftChild())); + buffer.append(toString(root.getRightChild())); + + return buffer.toString(); + } +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/relativelyprime/RelativelyPrimeUnitTest.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/relativelyprime/RelativelyPrimeUnitTest.java new file mode 100644 index 0000000000..84bb2620af --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/relativelyprime/RelativelyPrimeUnitTest.java @@ -0,0 +1,51 @@ +package com.baeldung.algorithms.relativelyprime; + +import org.junit.Test; + +import static com.baeldung.algorithms.relativelyprime.RelativelyPrime.*; +import static org.assertj.core.api.Assertions.assertThat; + +public class RelativelyPrimeUnitTest { + + @Test + public void givenNonRelativelyPrimeNumbers_whenCheckingIteratively_shouldReturnFalse() { + + boolean result = iterativeRelativelyPrime(45, 35); + assertThat(result).isFalse(); + } + + @Test + public void givenRelativelyPrimeNumbers_whenCheckingIteratively_shouldReturnTrue() { + + boolean result = iterativeRelativelyPrime(500, 501); + assertThat(result).isTrue(); + } + + @Test + public void givenNonRelativelyPrimeNumbers_whenCheckingRecursively_shouldReturnFalse() { + + boolean result = recursiveRelativelyPrime(45, 35); + assertThat(result).isFalse(); + } + + @Test + public void givenRelativelyPrimeNumbers_whenCheckingRecursively_shouldReturnTrue() { + + boolean result = recursiveRelativelyPrime(500, 501); + assertThat(result).isTrue(); + } + + @Test + public void givenNonRelativelyPrimeNumbers_whenCheckingUsingBigIntegers_shouldReturnFalse() { + + boolean result = bigIntegerRelativelyPrime(45, 35); + assertThat(result).isFalse(); + } + + @Test + public void givenRelativelyPrimeNumbers_whenCheckingBigIntegers_shouldReturnTrue() { + + boolean result = bigIntegerRelativelyPrime(500, 501); + assertThat(result).isTrue(); + } +} diff --git a/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/reversingtree/TreeReverserUnitTest.java b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/reversingtree/TreeReverserUnitTest.java new file mode 100644 index 0000000000..cbc265fae1 --- /dev/null +++ b/algorithms-miscellaneous-2/src/test/java/com/baeldung/algorithms/reversingtree/TreeReverserUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.algorithms.reversingtree; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class TreeReverserUnitTest { + + @Test + public void givenTreeWhenReversingRecursivelyThenReversed() { + TreeReverser reverser = new TreeReverser(); + + TreeNode treeNode = reverser.createBinaryTree(); + + reverser.reverseRecursive(treeNode); + + assertEquals("4 7 9 6 2 3 1", reverser.toString(treeNode) + .trim()); + } + + @Test + public void givenTreeWhenReversingIterativelyThenReversed() { + TreeReverser reverser = new TreeReverser(); + + TreeNode treeNode = reverser.createBinaryTree(); + + reverser.reverseIterative(treeNode); + + assertEquals("4 7 9 6 2 3 1", reverser.toString(treeNode) + .trim()); + } + +} diff --git a/algorithms-sorting/pom.xml b/algorithms-sorting/pom.xml index 2aee6e9199..b25adf05a8 100644 --- a/algorithms-sorting/pom.xml +++ b/algorithms-sorting/pom.xml @@ -49,7 +49,6 @@ - 1.16.12 3.6.1 3.9.0 1.11 diff --git a/apache-avro/pom.xml b/apache-avro/pom.xml index b98e52be75..5d170f0a81 100644 --- a/apache-avro/pom.xml +++ b/apache-avro/pom.xml @@ -82,7 +82,6 @@ UTF-8 3.5 1.8.2 - 1.8 1.7.25 diff --git a/apache-curator/pom.xml b/apache-curator/pom.xml index 3306c0613f..259319d547 100644 --- a/apache-curator/pom.xml +++ b/apache-curator/pom.xml @@ -39,7 +39,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson-databind.version} + ${jackson.version} @@ -59,7 +59,6 @@ 4.0.1 3.4.11 - 2.9.7 3.6.1 1.7.0 diff --git a/apache-fop/README.md b/apache-fop/README.md index 772681ad57..1e734a5f36 100644 --- a/apache-fop/README.md +++ b/apache-fop/README.md @@ -3,7 +3,3 @@ ## Core Java Cookbooks and Examples ### Relevant Articles: -- [Immutable ArrayList in Java](http://www.baeldung.com/java-immutable-list) -- [Java - Reading a Large File Efficiently](http://www.baeldung.com/java-read-lines-large-file) -- [Java InputStream to String](http://www.baeldung.com/convert-input-stream-to-string) - diff --git a/apache-geode/pom.xml b/apache-geode/pom.xml index a39e4a811e..15c7e04d29 100644 --- a/apache-geode/pom.xml +++ b/apache-geode/pom.xml @@ -32,8 +32,8 @@ org.apache.maven.plugins maven-compiler-plugin - ${maven.compiler.source} - ${maven.compiler.target} + ${java.version} + ${java.version} @@ -41,7 +41,5 @@ 1.6.0 - 1.8 - 1.8 \ No newline at end of file diff --git a/apache-spark/pom.xml b/apache-spark/pom.xml index 1aed5b1db9..f0f002a7e9 100644 --- a/apache-spark/pom.xml +++ b/apache-spark/pom.xml @@ -56,8 +56,8 @@ maven-compiler-plugin ${maven-compiler-plugin.version} - ${maven.compiler.source} - ${maven.compiler.target} + ${java.version} + ${java.version} @@ -85,8 +85,6 @@ 2.3.0 2.3.0 1.5.2 - 1.8 - 1.8 3.2 diff --git a/aws/README.md b/aws/README.md index 2c61928095..d14ea8a75e 100644 --- a/aws/README.md +++ b/aws/README.md @@ -4,7 +4,6 @@ - [AWS S3 with Java](http://www.baeldung.com/aws-s3-java) - [AWS Lambda With Java](http://www.baeldung.com/java-aws-lambda) - [Managing EC2 Instances in Java](http://www.baeldung.com/ec2-java) -- [http://www.baeldung.com/aws-s3-multipart-upload](https://github.com/eugenp/tutorials/tree/master/aws) - [Multipart Uploads in Amazon S3 with Java](http://www.baeldung.com/aws-s3-multipart-upload) - [Integration Testing with a Local DynamoDB Instance](http://www.baeldung.com/dynamodb-local-integration-tests) - [Using the JetS3t Java Client With Amazon S3](http://www.baeldung.com/jets3t-amazon-s3) diff --git a/azure/pom.xml b/azure/pom.xml index e2a05796d6..270b3e4829 100644 --- a/azure/pom.xml +++ b/azure/pom.xml @@ -127,7 +127,6 @@ ${azure.containerRegistry}.azurecr.io 1.1.0 1.1.0 - 1.8 diff --git a/cas/pom.xml b/cas/pom.xml new file mode 100644 index 0000000000..6d141277c5 --- /dev/null +++ b/cas/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + cas + cas + pom + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + .. + + + + cas-secured-app + cas-server + + + diff --git a/cdi/pom.xml b/cdi/pom.xml index ba649127a0..85da8518d0 100644 --- a/cdi/pom.xml +++ b/cdi/pom.xml @@ -66,7 +66,6 @@ 1.9.2 1.3 3.10.0 - 4.12 5.1.2.RELEASE diff --git a/cloud-foundry-uaa/cf-uaa-config/uaa.yml b/cloud-foundry-uaa/cf-uaa-config/uaa.yml new file mode 100644 index 0000000000..ebaa99fb6c --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-config/uaa.yml @@ -0,0 +1,68 @@ +issuer: + uri: http://localhost:8080/uaa + +spring_profiles: default,hsqldb + +encryption: + active_key_label: CHANGE-THIS-KEY + encryption_keys: + - label: CHANGE-THIS-KEY + passphrase: CHANGEME + +login: + serviceProviderKey: | + -----BEGIN RSA PRIVATE KEY----- + MIICXQIBAAKBgQDHtC5gUXxBKpEqZTLkNvFwNGnNIkggNOwOQVNbpO0WVHIivig5 + L39WqS9u0hnA+O7MCA/KlrAR4bXaeVVhwfUPYBKIpaaTWFQR5cTR1UFZJL/OF9vA + fpOwznoD66DDCnQVpbCjtDYWX+x6imxn8HCYxhMol6ZnTbSsFW6VZjFMjQIDAQAB + AoGAVOj2Yvuigi6wJD99AO2fgF64sYCm/BKkX3dFEw0vxTPIh58kiRP554Xt5ges + 7ZCqL9QpqrChUikO4kJ+nB8Uq2AvaZHbpCEUmbip06IlgdA440o0r0CPo1mgNxGu + lhiWRN43Lruzfh9qKPhleg2dvyFGQxy5Gk6KW/t8IS4x4r0CQQD/dceBA+Ndj3Xp + ubHfxqNz4GTOxndc/AXAowPGpge2zpgIc7f50t8OHhG6XhsfJ0wyQEEvodDhZPYX + kKBnXNHzAkEAyCA76vAwuxqAd3MObhiebniAU3SnPf2u4fdL1EOm92dyFs1JxyyL + gu/DsjPjx6tRtn4YAalxCzmAMXFSb1qHfwJBAM3qx3z0gGKbUEWtPHcP7BNsrnWK + vw6By7VC8bk/ffpaP2yYspS66Le9fzbFwoDzMVVUO/dELVZyBnhqSRHoXQcCQQCe + A2WL8S5o7Vn19rC0GVgu3ZJlUrwiZEVLQdlrticFPXaFrn3Md82ICww3jmURaKHS + N+l4lnMda79eSp3OMmq9AkA0p79BvYsLshUJJnvbk76pCjR28PK4dV1gSDUEqQMB + qy45ptdwJLqLJCeNoR0JUcDNIRhOCuOPND7pcMtX6hI/ + -----END RSA PRIVATE KEY----- + serviceProviderKeyPassword: password + serviceProviderCertificate: | + -----BEGIN CERTIFICATE----- + MIIDSTCCArKgAwIBAgIBADANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJhdzEO + MAwGA1UECBMFYXJ1YmExDjAMBgNVBAoTBWFydWJhMQ4wDAYDVQQHEwVhcnViYTEO + MAwGA1UECxMFYXJ1YmExDjAMBgNVBAMTBWFydWJhMR0wGwYJKoZIhvcNAQkBFg5h + cnViYUBhcnViYS5hcjAeFw0xNTExMjAyMjI2MjdaFw0xNjExMTkyMjI2MjdaMHwx + CzAJBgNVBAYTAmF3MQ4wDAYDVQQIEwVhcnViYTEOMAwGA1UEChMFYXJ1YmExDjAM + BgNVBAcTBWFydWJhMQ4wDAYDVQQLEwVhcnViYTEOMAwGA1UEAxMFYXJ1YmExHTAb + BgkqhkiG9w0BCQEWDmFydWJhQGFydWJhLmFyMIGfMA0GCSqGSIb3DQEBAQUAA4GN + ADCBiQKBgQDHtC5gUXxBKpEqZTLkNvFwNGnNIkggNOwOQVNbpO0WVHIivig5L39W + qS9u0hnA+O7MCA/KlrAR4bXaeVVhwfUPYBKIpaaTWFQR5cTR1UFZJL/OF9vAfpOw + znoD66DDCnQVpbCjtDYWX+x6imxn8HCYxhMol6ZnTbSsFW6VZjFMjQIDAQABo4Ha + MIHXMB0GA1UdDgQWBBTx0lDzjH/iOBnOSQaSEWQLx1syGDCBpwYDVR0jBIGfMIGc + gBTx0lDzjH/iOBnOSQaSEWQLx1syGKGBgKR+MHwxCzAJBgNVBAYTAmF3MQ4wDAYD + VQQIEwVhcnViYTEOMAwGA1UEChMFYXJ1YmExDjAMBgNVBAcTBWFydWJhMQ4wDAYD + VQQLEwVhcnViYTEOMAwGA1UEAxMFYXJ1YmExHTAbBgkqhkiG9w0BCQEWDmFydWJh + QGFydWJhLmFyggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAYvBJ + 0HOZbbHClXmGUjGs+GS+xC1FO/am2suCSYqNB9dyMXfOWiJ1+TLJk+o/YZt8vuxC + KdcZYgl4l/L6PxJ982SRhc83ZW2dkAZI4M0/Ud3oePe84k8jm3A7EvH5wi5hvCkK + RpuRBwn3Ei+jCRouxTbzKPsuCVB+1sNyxMTXzf0= + -----END CERTIFICATE----- + +#The secret that an external login server will use to authenticate to the uaa using the id `login` +LOGIN_SECRET: loginsecret + +jwt: + token: + signing-key: | + -----BEGIN RSA PRIVATE KEY----- + MIIEpAIBAAKCAQEAqUeygEfDGxI6c1VDQ6xIyUSLrP6iz1y97iHFbtXSxXaArL4a + ... + v6Mtt5LcRAAVP7pemunTdju4h8Q/noKYlVDVL30uLYUfKBL4UKfOBw== + -----END RSA PRIVATE KEY----- + verification-key: | + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqUeygEfDGxI6c1VDQ6xI + ... + AwIDAQAB + -----END PUBLIC KEY----- diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-client/pom.xml b/cloud-foundry-uaa/cf-uaa-oauth2-client/pom.xml new file mode 100644 index 0000000000..8e31cc41fb --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-client/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.3.RELEASE + + + com.example + cf-uaa-oauth2-client + 0.0.1-SNAPSHOT + uaa-client-webapp + Demo project for Spring Boot + + + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientApplication.java b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientApplication.java new file mode 100644 index 0000000000..c9e81fcd5d --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.cfuaa.oauth2.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CFUAAOAuth2ClientApplication { + + public static void main(String[] args) { + SpringApplication.run(CFUAAOAuth2ClientApplication.class, args); + } + +} diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientController.java b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientController.java new file mode 100644 index 0000000000..b1631ed327 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/java/com/baeldung/cfuaa/oauth2/client/CFUAAOAuth2ClientController.java @@ -0,0 +1,80 @@ +package com.baeldung.cfuaa.oauth2.client; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +@RestController +public class CFUAAOAuth2ClientController { + + @Value("${resource.server.url}") + private String remoteResourceServer; + + private RestTemplate restTemplate; + + private OAuth2AuthorizedClientService authorizedClientService; + + public CFUAAOAuth2ClientController(OAuth2AuthorizedClientService authorizedClientService) { + this.authorizedClientService = authorizedClientService; + this.restTemplate = new RestTemplate(); + } + + @RequestMapping("/") + public String index(OAuth2AuthenticationToken authenticationToken) { + OAuth2AuthorizedClient oAuth2AuthorizedClient = this.authorizedClientService.loadAuthorizedClient(authenticationToken.getAuthorizedClientRegistrationId(), authenticationToken.getName()); + OAuth2AccessToken oAuth2AccessToken = oAuth2AuthorizedClient.getAccessToken(); + + String response = "Hello, " + authenticationToken.getPrincipal().getName(); + response += "

"; + response += "Here is your accees token :
" + oAuth2AccessToken.getTokenValue(); + response += "
"; + response += "
You can use it to call these Resource Server APIs:"; + response += "

"; + response += "Call Resource Server Read API"; + response += "
"; + response += "Call Resource Server Write API"; + return response; + } + + @RequestMapping("/read") + public String read(OAuth2AuthenticationToken authenticationToken) { + String url = remoteResourceServer + "/read"; + return callResourceServer(authenticationToken, url); + } + + @RequestMapping("/write") + public String write(OAuth2AuthenticationToken authenticationToken) { + String url = remoteResourceServer + "/write"; + return callResourceServer(authenticationToken, url); + } + + private String callResourceServer(OAuth2AuthenticationToken authenticationToken, String url) { + OAuth2AuthorizedClient oAuth2AuthorizedClient = this.authorizedClientService.loadAuthorizedClient(authenticationToken.getAuthorizedClientRegistrationId(), authenticationToken.getName()); + OAuth2AccessToken oAuth2AccessToken = oAuth2AuthorizedClient.getAccessToken(); + + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Bearer " + oAuth2AccessToken.getTokenValue()); + + HttpEntity entity = new HttpEntity<>("parameters", headers); + ResponseEntity responseEntity = null; + + String response = null; + try { + responseEntity = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); + response = responseEntity.getBody(); + } catch (HttpClientErrorException e) { + response = e.getMessage(); + } + return response; + } +} \ No newline at end of file diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/application.properties b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/application.properties new file mode 100644 index 0000000000..8e8797ce54 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/application.properties @@ -0,0 +1,11 @@ +server.port=8081 + +resource.server.url=http://localhost:8082 + +spring.security.oauth2.client.registration.uaa.client-name=Web App Client +spring.security.oauth2.client.registration.uaa.client-id=webappclient +spring.security.oauth2.client.registration.uaa.client-secret=webappclientsecret +spring.security.oauth2.client.registration.uaa.scope=resource.read,resource.write,openid,profile + +spring.security.oauth2.client.provider.uaa.issuer-uri=http://localhost:8080/uaa/oauth/token + diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/templates/index.html b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/templates/index.html new file mode 100644 index 0000000000..eb6e267b94 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-client/src/main/resources/templates/index.html @@ -0,0 +1 @@ +tintin \ No newline at end of file diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/pom.xml b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/pom.xml new file mode 100644 index 0000000000..9cf8993cd2 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.3.RELEASE + + + com.baeldung.cfuaa + cf-uaa-oauth2-resource-server + 0.0.1-SNAPSHOT + cf-uaa-oauth2-resource-server + Demo project for Spring Boot + + + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-web + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerApplication.java b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerApplication.java new file mode 100644 index 0000000000..51ad6e938d --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.cfuaa.oauth2.resourceserver; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CFUAAOAuth2ResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(CFUAAOAuth2ResourceServerApplication.class, args); + } + +} diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerRestController.java b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerRestController.java new file mode 100644 index 0000000000..c08f17d8d8 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerRestController.java @@ -0,0 +1,28 @@ +package com.baeldung.cfuaa.oauth2.resourceserver; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.security.Principal; + +@RestController +public class CFUAAOAuth2ResourceServerRestController { + + @GetMapping("/") + public String index(@AuthenticationPrincipal Jwt jwt) { + return String.format("Hello, %s!", jwt.getSubject()); + } + + @GetMapping("/read") + public String read(JwtAuthenticationToken jwtAuthenticationToken) { + return "Hello write: " + jwtAuthenticationToken.getTokenAttributes(); + } + + @GetMapping("/write") + public String write(Principal principal) { + return "Hello write: " + principal.getName(); + } +} diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerSecurityConfiguration.java b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerSecurityConfiguration.java new file mode 100644 index 0000000000..d04d51cda3 --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerSecurityConfiguration.java @@ -0,0 +1,21 @@ +package com.baeldung.cfuaa.oauth2.resourceserver; + +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +public class CFUAAOAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .antMatchers("/read/**").hasAuthority("SCOPE_resource.read") + .antMatchers("/write/**").hasAuthority("SCOPE_resource.write") + .anyRequest().authenticated() + .and() + .oauth2ResourceServer() + .jwt(); + } +} \ No newline at end of file diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/resources/application.properties b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/resources/application.properties new file mode 100644 index 0000000000..a6e846a00f --- /dev/null +++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/resources/application.properties @@ -0,0 +1,3 @@ +server.port=8082 + +spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/uaa/oauth/token diff --git a/core-groovy/README.md b/core-groovy/README.md index 71788acdb7..606a317747 100644 --- a/core-groovy/README.md +++ b/core-groovy/README.md @@ -4,3 +4,10 @@ - [JDBC with Groovy](http://www.baeldung.com/jdbc-groovy) - [Working with JSON in Groovy](http://www.baeldung.com/groovy-json) +- [Reading a File in Groovy](https://www.baeldung.com/groovy-file-read) +- [Types of Strings in Groovy](https://www.baeldung.com/groovy-strings) +- [A Quick Guide to Iterating a Map in Groovy](https://www.baeldung.com/groovy-map-iterating) +- [An Introduction to Traits in Groovy](https://www.baeldung.com/groovy-traits) +- [Lists in Groovy](https://www.baeldung.com/groovy-lists) +- [Converting a String to a Date in Groovy](https://www.baeldung.com/groovy-string-to-date) +- [Guide to I/O in Groovy](https://www.baeldung.com/groovy-io) diff --git a/core-groovy/pom.xml b/core-groovy/pom.xml index e54c766280..029e5460ab 100644 --- a/core-groovy/pom.xml +++ b/core-groovy/pom.xml @@ -23,6 +23,12 @@ org.codehaus.groovy groovy-all ${groovy-all.version} + pom + + + org.codehaus.groovy + groovy-dateutil + ${groovy.version} org.codehaus.groovy @@ -103,9 +109,12 @@ 1.0.0 - 2.4.13 - 2.4.13 - 2.4.13 + + + + 2.5.6 + 2.5.6 + 2.5.6 2.4.0 1.1-groovy-2.4 1.6 diff --git a/core-groovy/src/main/groovy/com/baeldung/Person.groovy b/core-groovy/src/main/groovy/com/baeldung/Person.groovy new file mode 100644 index 0000000000..6a009aeee0 --- /dev/null +++ b/core-groovy/src/main/groovy/com/baeldung/Person.groovy @@ -0,0 +1,37 @@ +package com.baeldung + +class Person { + private String firstname + private String lastname + private Integer age + + Person(String firstname, String lastname, Integer age) { + this.firstname = firstname + this.lastname = lastname + this.age = age + } + + String getFirstname() { + return firstname + } + + void setFirstname(String firstname) { + this.firstname = firstname + } + + String getLastname() { + return lastname + } + + void setLastname(String lastname) { + this.lastname = lastname + } + + Integer getAge() { + return age + } + + void setAge(Integer age) { + this.age = age + } +} diff --git a/core-groovy/src/main/groovy/com/baeldung/closures/Closures.groovy b/core-groovy/src/main/groovy/com/baeldung/closures/Closures.groovy new file mode 100644 index 0000000000..607329ce88 --- /dev/null +++ b/core-groovy/src/main/groovy/com/baeldung/closures/Closures.groovy @@ -0,0 +1,87 @@ +package com.baeldung.closures + +class Closures { + + def printWelcome = { + println "Welcome to Closures!" + } + + def print = { name -> + println name + } + + def formatToLowerCase(name) { + return name.toLowerCase() + } + def formatToLowerCaseClosure = { name -> + return name.toLowerCase() + } + + def count=0 + + def increaseCount = { + count++ + } + + def greet = { + return "Hello! ${it}" + } + + def multiply = { x, y -> + return x*y + } + + def calculate = {int x, int y, String operation -> + + //log closure + def log = { + println "Performing $it" + } + + def result = 0 + switch(operation) { + case "ADD": + log("Addition") + result = x+y + break + case "SUB": + log("Subtraction") + result = x-y + break + case "MUL": + log("Multiplication") + result = x*y + break + case "DIV": + log("Division") + result = x/y + break + } + return result + } + + def addAll = { int... args -> + return args.sum() + } + + def volume(Closure areaCalculator, int... dimensions) { + if(dimensions.size() == 3) { + + //consider dimension[0] = length, dimension[1] = breadth, dimension[2] = height + //for cube and cuboid + return areaCalculator(dimensions[0], dimensions[1]) * dimensions[2] + } else if(dimensions.size() == 2) { + + //consider dimension[0] = radius, dimension[1] = height + //for cylinder and cone + return areaCalculator(dimensions[0]) * dimensions[1] + } else if(dimensions.size() == 1) { + + //consider dimension[0] = radius + //for sphere + return areaCalculator(dimensions[0]) * dimensions[0] + } + + } + +} \ No newline at end of file diff --git a/core-groovy/src/main/groovy/com/baeldung/closures/Employee.groovy b/core-groovy/src/main/groovy/com/baeldung/closures/Employee.groovy new file mode 100644 index 0000000000..78eb5aadeb --- /dev/null +++ b/core-groovy/src/main/groovy/com/baeldung/closures/Employee.groovy @@ -0,0 +1,6 @@ +package com.baeldung.closures + +class Employee { + + String fullName +} \ No newline at end of file diff --git a/core-groovy/src/main/groovy/com/baeldung/io/Task.groovy b/core-groovy/src/main/groovy/com/baeldung/io/Task.groovy new file mode 100644 index 0000000000..8a3bedc048 --- /dev/null +++ b/core-groovy/src/main/groovy/com/baeldung/io/Task.groovy @@ -0,0 +1,8 @@ +package com.baeldung.io + +class Task implements Serializable { + String description + Date startDate + Date dueDate + int status +} diff --git a/core-groovy/src/main/groovy/com/baeldung/traits/Car.groovy b/core-groovy/src/main/groovy/com/baeldung/traits/Car.groovy new file mode 100644 index 0000000000..eb4d1f7f87 --- /dev/null +++ b/core-groovy/src/main/groovy/com/baeldung/traits/Car.groovy @@ -0,0 +1,3 @@ +package com.baeldung + +class Car implements VehicleTrait {} \ No newline at end of file diff --git a/core-groovy/src/main/groovy/com/baeldung/traits/UserTrait.groovy b/core-groovy/src/main/groovy/com/baeldung/traits/UserTrait.groovy index 3f1e694f17..0d395bffcd 100644 --- a/core-groovy/src/main/groovy/com/baeldung/traits/UserTrait.groovy +++ b/core-groovy/src/main/groovy/com/baeldung/traits/UserTrait.groovy @@ -22,7 +22,7 @@ trait UserTrait implements Human { msg } - def whoAmI() { + def self() { return this } diff --git a/core-groovy/src/main/groovy/com/baeldung/traits/VehicleTrait.groovy b/core-groovy/src/main/groovy/com/baeldung/traits/VehicleTrait.groovy new file mode 100644 index 0000000000..f5ae8fab30 --- /dev/null +++ b/core-groovy/src/main/groovy/com/baeldung/traits/VehicleTrait.groovy @@ -0,0 +1,9 @@ +package com.baeldung + +trait VehicleTrait extends WheelTrait { + + String showWheels() { + return "Num of Wheels $noOfWheels" + } + +} \ No newline at end of file diff --git a/core-groovy/src/main/groovy/com/baeldung/traits/WheelTrait.groovy b/core-groovy/src/main/groovy/com/baeldung/traits/WheelTrait.groovy new file mode 100644 index 0000000000..364d5b883e --- /dev/null +++ b/core-groovy/src/main/groovy/com/baeldung/traits/WheelTrait.groovy @@ -0,0 +1,7 @@ +package com.baeldung + +trait WheelTrait { + + int noOfWheels + +} \ No newline at end of file diff --git a/core-groovy/src/main/resources/binaryExample.jpg b/core-groovy/src/main/resources/binaryExample.jpg new file mode 100644 index 0000000000..4b32645ac9 Binary files /dev/null and b/core-groovy/src/main/resources/binaryExample.jpg differ diff --git a/core-groovy/src/main/resources/ioData.txt b/core-groovy/src/main/resources/ioData.txt new file mode 100644 index 0000000000..d2741339d1 Binary files /dev/null and b/core-groovy/src/main/resources/ioData.txt differ diff --git a/core-groovy/src/main/resources/ioInput.txt b/core-groovy/src/main/resources/ioInput.txt new file mode 100644 index 0000000000..b180256dd5 --- /dev/null +++ b/core-groovy/src/main/resources/ioInput.txt @@ -0,0 +1,4 @@ +First line of text +Second line of text +Third line of text +Fourth line of text \ No newline at end of file diff --git a/core-groovy/src/main/resources/ioOutput.txt b/core-groovy/src/main/resources/ioOutput.txt new file mode 100644 index 0000000000..bcf76c43d8 --- /dev/null +++ b/core-groovy/src/main/resources/ioOutput.txt @@ -0,0 +1,3 @@ +Line one of output example +Line two of output example +Line three of output example \ No newline at end of file diff --git a/core-groovy/src/main/resources/ioSerializedObject.txt b/core-groovy/src/main/resources/ioSerializedObject.txt new file mode 100644 index 0000000000..833ed32bf1 Binary files /dev/null and b/core-groovy/src/main/resources/ioSerializedObject.txt differ diff --git a/core-groovy/src/test/groovy/com/baeldung/closures/ClosuresUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/closures/ClosuresUnitTest.groovy new file mode 100644 index 0000000000..32c67e99bc --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/closures/ClosuresUnitTest.groovy @@ -0,0 +1,80 @@ +package com.baeldung.closures + +import spock.lang.Specification + +class ClosuresUnitTest extends GroovyTestCase { + + Closures closures = new Closures() + + void testDeclaration() { + + closures.print("Hello! Closure") + closures.formatToLowerCaseClosure("Hello! Closure") + + closures.print.call("Hello! Closure") + closures.formatToLowerCaseClosure.call("Hello! Closure") + + } + + void testClosureVsMethods() { + assert closures.formatToLowerCase("TONY STARK") == closures.formatToLowerCaseClosure("Tony STark") + } + + void testParameters() { + //implicit parameter + assert closures.greet("Alex") == "Hello! Alex" + + //multiple parameters + assert closures.multiply(2, 4) == 8 + + assert closures.calculate(12, 4, "ADD") == 16 + assert closures.calculate(12, 4, "SUB") == 8 + assert closures.calculate(43, 8, "DIV") == 5.375 + + //varags + assert closures.addAll(12, 10, 14) == 36 + + } + + void testClosureAsAnArgument() { + assert closures.volume({ l, b -> return l*b }, 12, 6, 10) == 720 + + assert closures.volume({ radius -> return Math.PI*radius*radius/3 }, 5, 10) == Math.PI * 250/3 + } + + void testGStringsLazyEvaluation() { + def name = "Samwell" + def welcomeMsg = "Welcome! $name" + + assert welcomeMsg == "Welcome! Samwell" + + // changing the name does not affect original interpolated value + name = "Tarly" + assert welcomeMsg != "Welcome! Tarly" + + def fullName = "Tarly Samson" + def greetStr = "Hello! ${-> fullName}" + + assert greetStr == "Hello! Tarly Samson" + + // this time changing the variable affects the interpolated String's value + fullName = "Jon Smith" + assert greetStr == "Hello! Jon Smith" + } + + void testClosureInLists() { + def list = [10, 11, 12, 13, 14, true, false, "BUNTHER"] + list.each { + println it + } + + assert [13, 14] == list.findAll{ it instanceof Integer && it >= 13} + } + + void testClosureInMaps() { + def map = [1:10, 2:30, 4:5] + + assert [10, 60, 20] == map.collect{it.key * it.value} + } + +} \ No newline at end of file diff --git a/core-groovy/src/test/groovy/com/baeldung/date/DateTest.groovy b/core-groovy/src/test/groovy/com/baeldung/date/DateTest.groovy new file mode 100644 index 0000000000..4e7a7189a6 --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/date/DateTest.groovy @@ -0,0 +1,57 @@ +package com.baeldung.groovy.sql + +import static org.junit.Assert.* +import java.util.Calendar.* +import java.time.LocalDate +import java.text.SimpleDateFormat +import org.junit.Test + + +class DateTest { + + def dateStr = "2019-02-28" + def pattern = "yyyy-MM-dd" + + @Test + void whenGetStringRepresentation_thenCorrectlyConvertIntoDate() { + def dateFormat = new SimpleDateFormat(pattern) + def date = dateFormat.parse(dateStr) + + println(" String to Date with DateFormatter : " + date) + + def cal = new GregorianCalendar(); + cal.setTime(date); + + assertEquals(cal.get(Calendar.YEAR),2019) + assertEquals(cal.get(Calendar.DAY_OF_MONTH),28) + assertEquals(cal.get(Calendar.MONTH),java.util.Calendar.FEBRUARY) + } + + @Test + void whenGetStringRepresentation_thenCorrectlyConvertWithDateUtilsExtension() { + + def date = Date.parse(pattern, dateStr) + + println(" String to Date with Date.parse : " + date) + + def cal = new GregorianCalendar(); + cal.setTime(date); + + assertEquals(cal.get(Calendar.YEAR),2019) + assertEquals(cal.get(Calendar.DAY_OF_MONTH),28) + assertEquals(cal.get(Calendar.MONTH),java.util.Calendar.FEBRUARY) + } + + @Test + void whenGetStringRepresentation_thenCorrectlyConvertIntoDateWithLocalDate() { + def date = LocalDate.parse(dateStr, pattern) + + println(" String to Date with LocalDate : " + date) + + assertEquals(date.getYear(),2019) + assertEquals(date.getMonth(),java.time.Month.FEBRUARY) + assertEquals(date.getDayOfMonth(),28) + } + + +} diff --git a/core-groovy/src/test/groovy/com/baeldung/io/DataAndObjectsUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/io/DataAndObjectsUnitTest.groovy new file mode 100644 index 0000000000..0b413cf76c --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/io/DataAndObjectsUnitTest.groovy @@ -0,0 +1,51 @@ +package com.baeldung.io + +import static org.junit.Assert.* + +import org.junit.Test + +class DataAndObjectsUnitTest { + @Test + void whenUsingWithDataOutputStream_thenDataIsSerializedToAFile() { + String message = 'This is a serialized string' + int length = message.length() + boolean valid = true + new File('src/main/resources/ioData.txt').withDataOutputStream { out -> + out.writeUTF(message) + out.writeInt(length) + out.writeBoolean(valid) + } + + String loadedMessage = "" + int loadedLength + boolean loadedValid + + new File('src/main/resources/ioData.txt').withDataInputStream { is -> + loadedMessage = is.readUTF() + loadedLength = is.readInt() + loadedValid = is.readBoolean() + } + + assertEquals(message, loadedMessage) + assertEquals(length, loadedLength) + assertEquals(valid, loadedValid) + } + + @Test + void whenUsingWithObjectOutputStream_thenObjectIsSerializedToFile() { + Task task = new Task(description:'Take out the trash', startDate:new Date(), status:0) + new File('src/main/resources/ioSerializedObject.txt').withObjectOutputStream { out -> + out.writeObject(task) + } + + Task taskRead + + new File('src/main/resources/ioSerializedObject.txt').withObjectInputStream { is -> + taskRead = is.readObject() + } + + assertEquals(task.description, taskRead.description) + assertEquals(task.startDate, taskRead.startDate) + assertEquals(task.status, taskRead.status) + } +} diff --git a/core-groovy/src/test/groovy/com/baeldung/io/ReadExampleUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/io/ReadExampleUnitTest.groovy new file mode 100644 index 0000000000..bed77b4d81 --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/io/ReadExampleUnitTest.groovy @@ -0,0 +1,134 @@ +package com.baeldung.io + +import static org.junit.Assert.* +import org.junit.Test + +class ReadExampleUnitTest { + + @Test + void whenUsingEachLine_thenCorrectLinesReturned() { + def expectedList = [ + 'First line of text', + 'Second line of text', + 'Third line of text', + 'Fourth line of text'] + + def lines = [] + + new File('src/main/resources/ioInput.txt').eachLine { line -> + lines.add(line) + } + assertEquals(expectedList, lines) + } + + @Test + void whenUsingReadEachLineWithLineNumber_thenCorrectLinesReturned() { + def expectedList = [ + 'Second line of text', + 'Third line of text', + 'Fourth line of text'] + + def lineNoRange = 2..4 + def lines = [] + + new File('src/main/resources/ioInput.txt').eachLine { line, lineNo -> + if (lineNoRange.contains(lineNo)) { + lines.add(line) + } + } + assertEquals(expectedList, lines) + } + + @Test + void whenUsingReadEachLineWithLineNumberStartAtZero_thenCorrectLinesReturned() { + def expectedList = [ + 'Second line of text', + 'Third line of text', + 'Fourth line of text'] + + def lineNoRange = 1..3 + def lines = [] + + new File('src/main/resources/ioInput.txt').eachLine(0, { line, lineNo -> + if (lineNoRange.contains(lineNo)) { + lines.add(line) + } + }) + assertEquals(expectedList, lines) + } + + @Test + void whenUsingWithReader_thenLineCountReturned() { + def expectedCount = 4 + def actualCount = 0 + new File('src/main/resources/ioInput.txt').withReader { reader -> + while(reader.readLine()) { + actualCount++ + } + } + assertEquals(expectedCount, actualCount) + } + + @Test + void whenUsingNewReader_thenOutputFileCreated() { + def outputPath = 'src/main/resources/ioOut.txt' + def reader = new File('src/main/resources/ioInput.txt').newReader() + new File(outputPath).append(reader) + reader.close() + def ioOut = new File(outputPath) + assertTrue(ioOut.exists()) + ioOut.delete() + } + + @Test + void whenUsingWithInputStream_thenCorrectBytesAreReturned() { + def expectedLength = 1139 + byte[] data = [] + new File("src/main/resources/binaryExample.jpg").withInputStream { stream -> + data = stream.getBytes() + } + assertEquals(expectedLength, data.length) + } + + @Test + void whenUsingNewInputStream_thenOutputFileCreated() { + def outputPath = 'src/main/resources/binaryOut.jpg' + def is = new File('src/main/resources/binaryExample.jpg').newInputStream() + new File(outputPath).append(is) + is.close() + def ioOut = new File(outputPath) + assertTrue(ioOut.exists()) + ioOut.delete() + } + + @Test + void whenUsingCollect_thenCorrectListIsReturned() { + def expectedList = ['First line of text', 'Second line of text', 'Third line of text', 'Fourth line of text'] + + def actualList = new File('src/main/resources/ioInput.txt').collect {it} + assertEquals(expectedList, actualList) + } + + @Test + void whenUsingAsStringArray_thenCorrectArrayIsReturned() { + String[] expectedArray = ['First line of text', 'Second line of text', 'Third line of text', 'Fourth line of text'] + + def actualArray = new File('src/main/resources/ioInput.txt') as String[] + assertArrayEquals(expectedArray, actualArray) + } + + @Test + void whenUsingText_thenCorrectStringIsReturned() { + def ln = System.getProperty('line.separator') + def expectedString = "First line of text${ln}Second line of text${ln}Third line of text${ln}Fourth line of text" + def actualString = new File('src/main/resources/ioInput.txt').text + assertEquals(expectedString.toString(), actualString) + } + + @Test + void whenUsingBytes_thenByteArrayIsReturned() { + def expectedLength = 1139 + def contents = new File('src/main/resources/binaryExample.jpg').bytes + assertEquals(expectedLength, contents.length) + } +} diff --git a/core-groovy/src/test/groovy/com/baeldung/io/TraverseFileTreeUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/io/TraverseFileTreeUnitTest.groovy new file mode 100644 index 0000000000..dac0189fb9 --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/io/TraverseFileTreeUnitTest.groovy @@ -0,0 +1,61 @@ +package com.baeldung.io + +import org.junit.Test + +import groovy.io.FileType +import groovy.io.FileVisitResult + +class TraverseFileTreeUnitTest { + @Test + void whenUsingEachFile_filesAreListed() { + new File('src/main/resources').eachFile { file -> + println file.name + } + } + + @Test(expected = IllegalArgumentException) + void whenUsingEachFileOnAFile_anErrorOccurs() { + new File('src/main/resources/ioInput.txt').eachFile { file -> + println file.name + } + } + + @Test + void whenUsingEachFileMatch_filesAreListed() { + new File('src/main/resources').eachFileMatch(~/io.*\.txt/) { file -> + println file.name + } + } + + @Test + void whenUsingEachFileRecurse_thenFilesInSubfoldersAreListed() { + new File('src/main').eachFileRecurse(FileType.FILES) { file -> + println "$file.parent $file.name" + } + } + + @Test + void whenUsingEachFileRecurse_thenDirsInSubfoldersAreListed() { + new File('src/main').eachFileRecurse(FileType.DIRECTORIES) { file -> + println "$file.parent $file.name" + } + } + + @Test + void whenUsingEachDirRecurse_thenDirsAndSubDirsAreListed() { + new File('src/main').eachDirRecurse { dir -> + println "$dir.parent $dir.name" + } + } + + @Test + void whenUsingTraverse_thenDirectoryIsTraversed() { + new File('src/main').traverse { file -> + if (file.directory && file.name == 'groovy') { + FileVisitResult.SKIP_SUBTREE + } else { + println "$file.parent - $file.name" + } + } + } +} diff --git a/core-groovy/src/test/groovy/com/baeldung/io/WriteExampleUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/io/WriteExampleUnitTest.groovy new file mode 100644 index 0000000000..81758b430a --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/io/WriteExampleUnitTest.groovy @@ -0,0 +1,96 @@ +package com.baeldung.io + +import static org.junit.Assert.* + +import org.junit.Before +import org.junit.Test + +class WriteExampleUnitTest { + @Before + void clearOutputFile() { + new File('src/main/resources/ioOutput.txt').text = '' + new File('src/main/resources/ioBinaryOutput.bin').delete() + } + + @Test + void whenUsingWithWriter_thenFileCreated() { + def outputLines = [ + 'Line one of output example', + 'Line two of output example', + 'Line three of output example' + ] + + def outputFileName = 'src/main/resources/ioOutput.txt' + new File(outputFileName).withWriter { writer -> + outputLines.each { line -> + writer.writeLine line + } + } + def writtenLines = new File(outputFileName).collect {it} + assertEquals(outputLines, writtenLines) + } + + @Test + void whenUsingNewWriter_thenFileCreated() { + def outputLines = [ + 'Line one of output example', + 'Line two of output example', + 'Line three of output example' + ] + + def outputFileName = 'src/main/resources/ioOutput.txt' + def writer = new File(outputFileName).newWriter() + outputLines.forEach {line -> + writer.writeLine line + } + writer.flush() + writer.close() + + def writtenLines = new File(outputFileName).collect {it} + assertEquals(outputLines, writtenLines) + } + + @Test + void whenUsingDoubleLessThanOperator_thenFileCreated() { + def outputLines = [ + 'Line one of output example', + 'Line two of output example', + 'Line three of output example' + ] + + def ln = System.getProperty('line.separator') + def outputFileName = 'src/main/resources/ioOutput.txt' + new File(outputFileName) << "Line one of output example${ln}Line two of output example${ln}Line three of output example" + def writtenLines = new File(outputFileName).collect {it} + assertEquals(outputLines.size(), writtenLines.size()) + } + + @Test + void whenUsingBytes_thenBinaryFileCreated() { + def outputFileName = 'src/main/resources/ioBinaryOutput.bin' + def outputFile = new File(outputFileName) + byte[] outBytes = [44, 88, 22] + outputFile.bytes = outBytes + assertEquals(3, new File(outputFileName).size()) + } + + @Test + void whenUsingWithOutputStream_thenBinaryFileCreated() { + def outputFileName = 'src/main/resources/ioBinaryOutput.bin' + byte[] outBytes = [44, 88, 22] + new File(outputFileName).withOutputStream { stream -> + stream.write(outBytes) + } + assertEquals(3, new File(outputFileName).size()) + } + + @Test + void whenUsingNewOutputStream_thenBinaryFileCreated() { + def outputFileName = 'src/main/resources/ioBinaryOutput.bin' + byte[] outBytes = [44, 88, 22] + def os = new File(outputFileName).newOutputStream() + os.write(outBytes) + os.close() + assertEquals(3, new File(outputFileName).size()) + } +} diff --git a/core-groovy/src/test/groovy/com/baeldung/lists/ListTest.groovy b/core-groovy/src/test/groovy/com/baeldung/lists/ListTest.groovy new file mode 100644 index 0000000000..7771028132 --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/lists/ListTest.groovy @@ -0,0 +1,173 @@ +package com.baeldung.groovy.lists + +import static groovy.test.GroovyAssert.* +import org.junit.Test + +class ListTest{ + + @Test + void testCreateList() { + + def list = [1, 2, 3] + assertNotNull(list) + + def listMix = ['A', "b", 1, true] + assertTrue(listMix == ['A', "b", 1, true]) + + def linkedList = [1, 2, 3] as LinkedList + assertTrue(linkedList instanceof LinkedList) + + ArrayList arrList = [1, 2, 3] + assertTrue(arrList.class == ArrayList) + + def copyList = new ArrayList(arrList) + assertTrue(copyList == arrList) + + def cloneList = arrList.clone() + assertTrue(cloneList == arrList) + } + + @Test + void testCreateEmptyList() { + + def emptyList = [] + assertTrue(emptyList.size() == 0) + } + + @Test + void testCompareTwoLists() { + + def list1 = [5, 6.0, 'p'] + def list2 = [5, 6.0, 'p'] + assertTrue(list1 == list2) + } + + @Test + void testGetItemsFromList(){ + + def list = ["Hello", "World"] + + assertTrue(list.get(1) == "World") + assertTrue(list[1] == "World") + assertTrue(list[-1] == "World") + assertTrue(list.getAt(1) == "World") + assertTrue(list.getAt(-2) == "Hello") + } + + @Test + void testAddItemsToList() { + + def list = [] + + list << 1 + list.add("Apple") + assertTrue(list == [1, "Apple"]) + + list[2] = "Box" + list[4] = true + assertTrue(list == [1, "Apple", "Box", null, true]) + + list.add(1, 6.0) + assertTrue(list == [1, 6.0, "Apple", "Box", null, true]) + + def list2 = [1, 2] + list += list2 + list += 12 + assertTrue(list == [1, 6.0, "Apple", "Box", null, true, 1, 2, 12]) + } + + @Test + void testUpdateItemsInList() { + + def list =[1, "Apple", 80, "App"] + list[1] = "Box" + list.set(2,90) + assertTrue(list == [1, "Box", 90, "App"]) + } + + @Test + void testRemoveItemsFromList(){ + + def list = [1, 2, 3, 4, 5, 5, 6, 6, 7] + + list.remove(3) + assertTrue(list == [1, 2, 3, 5, 5, 6, 6, 7]) + + list.removeElement(5) + assertTrue(list == [1, 2, 3, 5, 6, 6, 7]) + + assertTrue(list - 6 == [1, 2, 3, 5, 7]) + } + + @Test + void testIteratingOnAList(){ + + def list = [1, "App", 3, 4] + list.each{ println it * 2} + + list.eachWithIndex{ it, i -> println "$i : $it" } + } + + @Test + void testCollectingToAnotherList(){ + + def list = ["Kay", "Henry", "Justin", "Tom"] + assertTrue(list.collect{"Hi " + it} == ["Hi Kay", "Hi Henry", "Hi Justin", "Hi Tom"]) + } + + @Test + void testJoinItemsInAList(){ + assertTrue(["One", "Two", "Three"].join(",") == "One,Two,Three") + } + + @Test + void testFilteringOnLists(){ + def filterList = [2, 1, 3, 4, 5, 6, 76] + + assertTrue(filterList.find{it > 3} == 4) + + assertTrue(filterList.findAll{it > 3} == [4, 5, 6, 76]) + + assertTrue(filterList.findAll{ it instanceof Number} == [2, 1, 3, 4, 5, 6, 76]) + + assertTrue(filterList.grep( Number )== [2, 1, 3, 4, 5, 6, 76]) + + assertTrue(filterList.grep{ it> 6 }== [76]) + + def conditionList = [2, 1, 3, 4, 5, 6, 76] + + assertFalse(conditionList.every{ it < 6}) + + assertTrue(conditionList.any{ it%2 == 0}) + + } + + @Test + void testGetUniqueItemsInAList(){ + assertTrue([1, 3, 3, 4].toUnique() == [1, 3, 4]) + + def uniqueList = [1, 3, 3, 4] + uniqueList.unique() + assertTrue(uniqueList == [1, 3, 4]) + + assertTrue(["A", "B", "Ba", "Bat", "Cat"].toUnique{ it.size()} == ["A", "Ba", "Bat"]) + } + + @Test + void testSorting(){ + + assertTrue([1, 2, 1, 0].sort() == [0, 1, 1, 2]) + Comparator mc = {a,b -> a == b? 0: a < b? 1 : -1} + + def list = [1, 2, 1, 0] + list.sort(mc) + assertTrue(list == [2, 1, 1, 0]) + + def strList = ["na", "ppp", "as"] + assertTrue(strList.max() == "ppp") + + Comparator minc = {a,b -> a == b? 0: a < b? -1 : 1} + def numberList = [3, 2, 0, 7] + assertTrue(numberList.min(minc) == 0) + } +} \ No newline at end of file diff --git a/core-groovy/src/test/groovy/com/baeldung/lists/ListUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/lists/ListUnitTest.groovy new file mode 100644 index 0000000000..9617c099ce --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/lists/ListUnitTest.groovy @@ -0,0 +1,58 @@ +package com.baeldung.lists + +import com.baeldung.Person +import org.junit.Test + +import static org.junit.Assert.* + +class ListUnitTest { + + private final personList = [ + new Person("Regina", "Fitzpatrick", 25), + new Person("Abagail", "Ballard", 26), + new Person("Lucian", "Walter", 30), + ] + + @Test + void whenListContainsElement_thenCheckReturnsTrue() { + def list = ['a', 'b', 'c'] + + assertTrue(list.indexOf('a') > -1) + assertTrue(list.contains('a')) + } + + @Test + void whenListContainsElement_thenCheckWithMembershipOperatorReturnsTrue() { + def list = ['a', 'b', 'c'] + + assertTrue('a' in list) + } + + @Test + void givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList() { + assertTrue(personList.stream().anyMatch {it.age > 20}) + assertFalse(personList.stream().allMatch {it.age < 30}) + } + + @Test + void givenListOfPerson_whenUsingCollectionMatching_thenShouldEvaluateList() { + assertTrue(personList.any {it.age > 20}) + assertFalse(personList.every {it.age < 30}) + } + + @Test + void givenListOfPerson_whenUsingStreamFind_thenShouldReturnMatchingElements() { + assertTrue(personList.stream().filter {it.age > 20}.findAny().isPresent()) + assertFalse(personList.stream().filter {it.age > 30}.findAny().isPresent()) + assertTrue(personList.stream().filter {it.age > 20}.findAll().size() == 3) + assertTrue(personList.stream().filter {it.age > 30}.findAll().isEmpty()) + } + + @Test + void givenListOfPerson_whenUsingCollectionFind_thenShouldReturnMatchingElements() { + assertNotNull(personList.find {it.age > 20}) + assertNull(personList.find {it.age > 30}) + assertTrue(personList.findAll {it.age > 20}.size() == 3) + assertTrue(personList.findAll {it.age > 30}.isEmpty()) + } +} diff --git a/core-groovy/src/test/groovy/com/baeldung/map/MapUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/map/MapUnitTest.groovy new file mode 100644 index 0000000000..0d6bbed04b --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/map/MapUnitTest.groovy @@ -0,0 +1,154 @@ +package com.baeldung.map + +import com.baeldung.Person +import org.junit.Test + +import static org.junit.Assert.* + +class MapUnitTest { + + private final personMap = [ + Regina : new Person("Regina", "Fitzpatrick", 25), + Abagail: new Person("Abagail", "Ballard", 26), + Lucian : new Person("Lucian", "Walter", 30) + ] + + @Test + void whenUsingEach_thenMapIsIterated() { + def map = [ + 'FF0000' : 'Red', + '00FF00' : 'Lime', + '0000FF' : 'Blue', + 'FFFF00' : 'Yellow' + ] + + map.each { println "Hex Code: $it.key = Color Name: $it.value" } + } + + @Test + void whenUsingEachWithEntry_thenMapIsIterated() { + def map = [ + 'E6E6FA' : 'Lavender', + 'D8BFD8' : 'Thistle', + 'DDA0DD' : 'Plum', + ] + + map.each { entry -> println "Hex Code: $entry.key = Color Name: $entry.value" } + } + + @Test + void whenUsingEachWithKeyAndValue_thenMapIsIterated() { + def map = [ + '000000' : 'Black', + 'FFFFFF' : 'White', + '808080' : 'Gray' + ] + + map.each { key, val -> + println "Hex Code: $key = Color Name $val" + } + } + + @Test + void whenUsingEachWithIndexAndEntry_thenMapIsIterated() { + def map = [ + '800080' : 'Purple', + '4B0082' : 'Indigo', + '6A5ACD' : 'Slate Blue' + ] + + map.eachWithIndex { entry, index -> + def indent = ((index == 0 || index % 2 == 0) ? " " : "") + println "$indent Hex Code: $entry.key = Color Name: $entry.value" + } + } + + @Test + void whenUsingEachWithIndexAndKeyAndValue_thenMapIsIterated() { + def map = [ + 'FFA07A' : 'Light Salmon', + 'FF7F50' : 'Coral', + 'FF6347' : 'Tomato', + 'FF4500' : 'Orange Red' + ] + + map.eachWithIndex { key, val, index -> + def indent = ((index == 0 || index % 2 == 0) ? " " : "") + println "$indent Hex Code: $key = Color Name: $val" + } + } + + @Test + void whenUsingForLoop_thenMapIsIterated() { + def map = [ + '2E8B57' : 'Seagreen', + '228B22' : 'Forest Green', + '008000' : 'Green' + ] + + for (entry in map) { + println "Hex Code: $entry.key = Color Name: $entry.value" + } + } + + @Test + void whenMapContainsKeyElement_thenCheckReturnsTrue() { + def map = [a: 'd', b: 'e', c: 'f'] + + assertTrue(map.containsKey('a')) + assertFalse(map.containsKey('e')) + assertTrue(map.containsValue('e')) + } + + @Test + void whenMapContainsKeyElement_thenCheckByMembershipReturnsTrue() { + def map = [a: 'd', b: 'e', c: 'f'] + + assertTrue('a' in map) + assertFalse('f' in map) + } + + @Test + void whenMapContainsFalseBooleanValues_thenCheckReturnsFalse() { + def map = [a: true, b: false, c: null] + + assertTrue(map.containsKey('b')) + assertTrue('a' in map) + assertFalse('b' in map) + assertFalse('c' in map) + } + + @Test + void givenMapOfPerson_whenUsingStreamMatching_thenShouldEvaluateMap() { + assertTrue(personMap.keySet().stream().anyMatch {it == "Regina"}) + assertFalse(personMap.keySet().stream().allMatch {it == "Albert"}) + assertFalse(personMap.values().stream().allMatch {it.age < 30}) + assertTrue(personMap.entrySet().stream().anyMatch {it.key == "Abagail" && it.value.lastname == "Ballard"}) + } + + @Test + void givenMapOfPerson_whenUsingCollectionMatching_thenShouldEvaluateMap() { + assertTrue(personMap.keySet().any {it == "Regina"}) + assertFalse(personMap.keySet().every {it == "Albert"}) + assertFalse(personMap.values().every {it.age < 30}) + assertTrue(personMap.any {firstname, person -> firstname == "Abagail" && person.lastname == "Ballard"}) + } + + @Test + void givenMapOfPerson_whenUsingCollectionFind_thenShouldReturnElements() { + assertNotNull(personMap.find {it.key == "Abagail" && it.value.lastname == "Ballard"}) + assertTrue(personMap.findAll {it.value.age > 20}.size() == 3) + } + + @Test + void givenMapOfPerson_whenUsingStreamFind_thenShouldReturnElements() { + assertTrue( + personMap.entrySet().stream() + .filter {it.key == "Abagail" && it.value.lastname == "Ballard"} + .findAny().isPresent()) + assertTrue( + personMap.entrySet().stream() + .filter {it.value.age > 20} + .findAll().size() == 3) + } +} diff --git a/core-groovy/src/test/groovy/com/baeldung/set/SetUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/set/SetUnitTest.groovy new file mode 100644 index 0000000000..1248c9ac91 --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/set/SetUnitTest.groovy @@ -0,0 +1,16 @@ +package com.baeldung.set + +import org.junit.Test + +import static org.junit.Assert.assertTrue + +class SetUnitTest { + + @Test + void whenSetContainsElement_thenCheckReturnsTrue() { + def set = ['a', 'b', 'c'] as Set + + assertTrue(set.contains('a')) + assertTrue('a' in set) + } +} \ No newline at end of file diff --git a/core-groovy/src/test/groovy/com/baeldung/traits/TraitsUnitTest.groovy b/core-groovy/src/test/groovy/com/baeldung/traits/TraitsUnitTest.groovy index 0c74a9be62..85130e8f07 100644 --- a/core-groovy/src/test/groovy/com/baeldung/traits/TraitsUnitTest.groovy +++ b/core-groovy/src/test/groovy/com/baeldung/traits/TraitsUnitTest.groovy @@ -57,7 +57,7 @@ class TraitsUnitTest extends Specification { def 'Should return employee instance when using Employee.whoAmI method' () { when: - def emp = employee.whoAmI() + def emp = employee.self() then: emp emp instanceof Employee diff --git a/core-java-11/README.md b/core-java-11/README.md index 3c8b94fa28..b09649f4f1 100644 --- a/core-java-11/README.md +++ b/core-java-11/README.md @@ -4,3 +4,5 @@ - [Java 11 Local Variable Syntax for Lambda Parameters](https://www.baeldung.com/java-var-lambda-params) - [Java 11 String API Additions](https://www.baeldung.com/java-11-string-api) - [Java 11 Nest Based Access Control](https://www.baeldung.com/java-nest-based-access-control) +- [Exploring the New HTTP Client in Java 9 and 11](https://www.baeldung.com/java-9-http-client) +- [An Introduction to Epsilon GC: A No-Op Experimental Garbage Collector](https://www.baeldung.com/jvm-epsilon-gc-garbage-collector) diff --git a/core-java-11/src/main/java/com/baeldung/epsilongc/MemoryPolluter.java b/core-java-11/src/main/java/com/baeldung/epsilongc/MemoryPolluter.java new file mode 100644 index 0000000000..97e216513b --- /dev/null +++ b/core-java-11/src/main/java/com/baeldung/epsilongc/MemoryPolluter.java @@ -0,0 +1,18 @@ +package com.baeldung.epsilongc; + +public class MemoryPolluter { + + private static final int MEGABYTE_IN_BYTES = 1024 * 1024; + private static final int ITERATION_COUNT = 1024 * 10; + + public static void main(String[] args) { + System.out.println("Starting pollution"); + + for (int i = 0; i < ITERATION_COUNT; i++) { + byte[] array = new byte[MEGABYTE_IN_BYTES]; + } + + System.out.println("Terminating"); + } + +} diff --git a/core-java-11/src/modules/jlinkModule/com/baeldung/jlink/HelloWorld.java b/core-java-11/src/modules/jlinkModule/com/baeldung/jlink/HelloWorld.java new file mode 100644 index 0000000000..47fe62ba40 --- /dev/null +++ b/core-java-11/src/modules/jlinkModule/com/baeldung/jlink/HelloWorld.java @@ -0,0 +1,12 @@ +package com.baeldung.jlink; + +import java.util.logging.Logger; + +public class HelloWorld { + + private static final Logger LOG = Logger.getLogger(HelloWorld.class.getName()); + + public static void main(String[] args) { + LOG.info("Hello World!"); + } +} diff --git a/core-java-11/src/modules/jlinkModule/module-info.java b/core-java-11/src/modules/jlinkModule/module-info.java new file mode 100644 index 0000000000..0587c65b53 --- /dev/null +++ b/core-java-11/src/modules/jlinkModule/module-info.java @@ -0,0 +1,3 @@ +module jlinkModule { + requires java.logging; +} \ No newline at end of file diff --git a/core-java-12/pom.xml b/core-java-12/pom.xml new file mode 100644 index 0000000000..defef5e9d3 --- /dev/null +++ b/core-java-12/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + com.baeldung + core-java-12 + 0.1.0-SNAPSHOT + core-java-12 + jar + http://maven.apache.org + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source.version} + ${maven.compiler.target.version} + + + + + + + 12 + 12 + 3.6.1 + + + \ No newline at end of file diff --git a/core-java-12/src/test/java/com/baeldung/collectors/CollectorsUnitTest.java b/core-java-12/src/test/java/com/baeldung/collectors/CollectorsUnitTest.java new file mode 100644 index 0000000000..7c4cb9e8f0 --- /dev/null +++ b/core-java-12/src/test/java/com/baeldung/collectors/CollectorsUnitTest.java @@ -0,0 +1,71 @@ +package com.baeldung.collectors; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import org.junit.Test; + +import static java.util.stream.Collectors.maxBy; +import static java.util.stream.Collectors.minBy; +import static java.util.stream.Collectors.teeing; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for collectors additions in Java 12. + */ +public class CollectorsUnitTest { + + @Test + public void whenTeeing_ItShouldCombineTheResultsAsExpected() { + List numbers = Arrays.asList(42, 4, 2, 24); + Range range = numbers.stream() + .collect(teeing(minBy(Integer::compareTo), maxBy(Integer::compareTo), (min, max) -> new Range(min.orElse(null), max.orElse(null)))); + + assertThat(range).isEqualTo(new Range(2, 42)); + } + + /** + * Represents a closed range of numbers between {@link #min} and + * {@link #max}, both inclusive. + */ + private static class Range { + + private final Integer min; + + private final Integer max; + + Range(Integer min, Integer max) { + this.min = min; + this.max = max; + } + + Integer getMin() { + return min; + } + + Integer getMax() { + return max; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Range range = (Range) o; + return Objects.equals(getMin(), range.getMin()) && Objects.equals(getMax(), range.getMax()); + } + + @Override + public int hashCode() { + return Objects.hash(getMin(), getMax()); + } + + @Override + public String toString() { + return "Range{" + "min=" + min + ", max=" + max + '}'; + } + } +} diff --git a/core-java-8/README.md b/core-java-8/README.md index 892dc71f76..99182da390 100644 --- a/core-java-8/README.md +++ b/core-java-8/README.md @@ -4,9 +4,9 @@ ### Relevant Articles: - [Java 8 Collectors](http://www.baeldung.com/java-8-collectors) -- [Guide to Java 8’s Functional Interfaces](http://www.baeldung.com/java-8-functional-interfaces) +- [Functional Interfaces in Java 8](http://www.baeldung.com/java-8-functional-interfaces) - [Java 8 – Powerful Comparison with Lambdas](http://www.baeldung.com/java-8-sort-lambda) -- [Java 8 New Features](http://www.baeldung.com/java-8-new-features) +- [New Features in Java 8](http://www.baeldung.com/java-8-new-features) - [Lambda Expressions and Functional Interfaces: Tips and Best Practices](http://www.baeldung.com/java-8-lambda-expressions-tips) - [The Double Colon Operator in Java 8](http://www.baeldung.com/java-8-double-colon-operator) - [Guide to Java 8 groupingBy Collector](http://www.baeldung.com/java-groupingby-collector) @@ -38,3 +38,5 @@ - [Java @SafeVarargs Annotation](https://www.baeldung.com/java-safevarargs) - [Java @Deprecated Annotation](https://www.baeldung.com/java-deprecated) - [Java 8 Predicate Chain](https://www.baeldung.com/java-predicate-chain) +- [Method References in Java](https://www.baeldung.com/java-method-references) +- [Creating a Custom Annotation in Java](https://www.baeldung.com/java-custom-annotation) diff --git a/core-java-8/pom.xml b/core-java-8/pom.xml index b4519a8161..b63afef7d4 100644 --- a/core-java-8/pom.xml +++ b/core-java-8/pom.xml @@ -180,7 +180,6 @@ 4.1 4.01 1.10 - 1.16.12 0.9.0 1.13 2.10 diff --git a/core-java-8/src/main/java/com/baeldung/streamreduce/application/Application.java b/core-java-8/src/main/java/com/baeldung/streamreduce/application/Application.java new file mode 100644 index 0000000000..0b1dd952dc --- /dev/null +++ b/core-java-8/src/main/java/com/baeldung/streamreduce/application/Application.java @@ -0,0 +1,62 @@ +package com.baeldung.streamreduce.application; + +import com.baeldung.streamreduce.entities.User; +import com.baeldung.streamreduce.utilities.NumberUtils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Application { + + public static void main(String[] args) { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result1 = numbers.stream().reduce(0, (a, b) -> a + b); + System.out.println(result1); + + int result2 = numbers.stream().reduce(0, Integer::sum); + System.out.println(result2); + + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result3 = letters.stream().reduce("", (a, b) -> a + b); + System.out.println(result3); + + String result4 = letters.stream().reduce("", String::concat); + System.out.println(result4); + + String result5 = letters.stream().reduce("", (a, b) -> a.toUpperCase() + b.toUpperCase()); + System.out.println(result5); + + List users = Arrays.asList(new User("John", 30), new User("Julie", 35)); + int result6 = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + System.out.println(result6); + + String result7 = letters.parallelStream().reduce("", String::concat); + System.out.println(result7); + + int result8 = users.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + System.out.println(result8); + + List userList = new ArrayList<>(); + for (int i = 0; i <= 1000000; i++) { + userList.add(new User("John" + i, i)); + } + + long t1 = System.currentTimeMillis(); + int result9 = userList.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + long t2 = System.currentTimeMillis(); + System.out.println(result9); + System.out.println("Sequential stream time: " + (t2 - t1) + "ms"); + + long t3 = System.currentTimeMillis(); + int result10 = userList.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + long t4 = System.currentTimeMillis(); + System.out.println(result10); + System.out.println("Parallel stream time: " + (t4 - t3) + "ms"); + + int result11 = NumberUtils.divideListElements(numbers, 1); + System.out.println(result11); + + int result12 = NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 0); + System.out.println(result12); + } +} diff --git a/core-java-8/src/main/java/com/baeldung/streamreduce/entities/User.java b/core-java-8/src/main/java/com/baeldung/streamreduce/entities/User.java new file mode 100644 index 0000000000..bc13a8cde6 --- /dev/null +++ b/core-java-8/src/main/java/com/baeldung/streamreduce/entities/User.java @@ -0,0 +1,25 @@ +package com.baeldung.streamreduce.entities; + +public class User { + + private final String name; + private final int age; + + public User(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + @Override + public String toString() { + return "User{" + "name=" + name + ", age=" + age + '}'; + } +} diff --git a/core-java-8/src/main/java/com/baeldung/streamreduce/utilities/NumberUtils.java b/core-java-8/src/main/java/com/baeldung/streamreduce/utilities/NumberUtils.java new file mode 100644 index 0000000000..7a6a85e6c4 --- /dev/null +++ b/core-java-8/src/main/java/com/baeldung/streamreduce/utilities/NumberUtils.java @@ -0,0 +1,52 @@ +package com.baeldung.streamreduce.utilities; + +import java.util.List; +import java.util.function.BiFunction; +import java.util.logging.Level; +import java.util.logging.Logger; + +public abstract class NumberUtils { + + private static final Logger LOGGER = Logger.getLogger(NumberUtils.class.getName()); + + public static int divideListElements(List values, Integer divider) { + return values.stream() + .reduce(0, (a, b) -> { + try { + return a / divider + b / divider; + } catch (ArithmeticException e) { + LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero"); + } + return 0; + }); + } + + public static int divideListElementsWithExtractedTryCatchBlock(List values, int divider) { + return values.stream().reduce(0, (a, b) -> divide(a, divider) + divide(b, divider)); + } + + public static int divideListElementsWithApplyFunctionMethod(List values, int divider) { + BiFunction division = (a, b) -> a / b; + return values.stream().reduce(0, (a, b) -> applyFunction(division, a, divider) + applyFunction(division, b, divider)); + } + + private static int divide(int value, int factor) { + int result = 0; + try { + result = value / factor; + } catch (ArithmeticException e) { + LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero"); + } + return result; + } + + private static int applyFunction(BiFunction function, int a, int b) { + try { + return function.apply(a, b); + } + catch(Exception e) { + LOGGER.log(Level.INFO, "Exception occurred!"); + } + return 0; + } +} diff --git a/core-java-8/src/test/java/com/baeldung/java8/Java8SortUnitTest.java b/core-java-8/src/test/java/com/baeldung/java8/Java8SortUnitTest.java index 71ec5b147f..57d9d8347b 100644 --- a/core-java-8/src/test/java/com/baeldung/java8/Java8SortUnitTest.java +++ b/core-java-8/src/test/java/com/baeldung/java8/Java8SortUnitTest.java @@ -124,11 +124,44 @@ public class Java8SortUnitTest { @Test public final void givenStreamCustomOrdering_whenSortingEntitiesByName_thenCorrectlySorted() { - final List humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12)); final Comparator nameComparator = (h1, h2) -> h1.getName().compareTo(h2.getName()); final List sortedHumans = humans.stream().sorted(nameComparator).collect(Collectors.toList()); Assert.assertThat(sortedHumans.get(0), equalTo(new Human("Jack", 12))); } + + @Test + public final void givenStreamComparatorOrdering_whenSortingEntitiesByName_thenCorrectlySorted() { + final List humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12)); + + final List sortedHumans = humans.stream().sorted(Comparator.comparing(Human::getName)).collect(Collectors.toList()); + Assert.assertThat(sortedHumans.get(0), equalTo(new Human("Jack", 12))); + } + + @Test + public final void givenStreamNaturalOrdering_whenSortingEntitiesByNameReversed_thenCorrectlySorted() { + final List letters = Lists.newArrayList("B", "A", "C"); + + final List reverseSortedLetters = letters.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList()); + Assert.assertThat(reverseSortedLetters.get(0), equalTo("C")); + } + + @Test + public final void givenStreamCustomOrdering_whenSortingEntitiesByNameReversed_thenCorrectlySorted() { + final List humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12)); + final Comparator reverseNameComparator = (h1, h2) -> h2.getName().compareTo(h1.getName()); + + final List reverseSortedHumans = humans.stream().sorted(reverseNameComparator).collect(Collectors.toList()); + Assert.assertThat(reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10))); + } + + @Test + public final void givenStreamComparatorOrdering_whenSortingEntitiesByNameReversed_thenCorrectlySorted() { + final List humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12)); + + final List reverseSortedHumans = humans.stream().sorted(Comparator.comparing(Human::getName, Comparator.reverseOrder())).collect(Collectors.toList()); + Assert.assertThat(reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10))); + } + } diff --git a/core-java-8/src/test/java/com/baeldung/java8/optional/OptionalChainingUnitTest.java b/core-java-8/src/test/java/com/baeldung/java8/optional/OptionalChainingUnitTest.java new file mode 100644 index 0000000000..70ec324cb3 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/java8/optional/OptionalChainingUnitTest.java @@ -0,0 +1,110 @@ +package com.baeldung.java8.optional; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import static org.junit.Assert.*; + +public class OptionalChainingUnitTest { + + private boolean getEmptyEvaluated; + private boolean getHelloEvaluated; + private boolean getByeEvaluated; + + @Before + public void setUp() { + getEmptyEvaluated = false; + getHelloEvaluated = false; + getByeEvaluated = false; + } + + @Test + public void givenThreeOptionals_whenChaining_thenFirstNonEmptyIsReturned() { + Optional found = Stream.of(getEmpty(), getHello(), getBye()) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + + assertEquals(getHello(), found); + } + + @Test + public void givenTwoEmptyOptionals_whenChaining_thenEmptyOptionalIsReturned() { + Optional found = Stream.of(getEmpty(), getEmpty()) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + + assertFalse(found.isPresent()); + } + + @Test + public void givenTwoEmptyOptionals_whenChaining_thenDefaultIsReturned() { + String found = Stream.>>of( + () -> createOptional("empty"), + () -> createOptional("empty") + ) + .map(Supplier::get) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst() + .orElseGet(() -> "default"); + + assertEquals("default", found); + } + + @Test + public void givenThreeOptionals_whenChaining_thenFirstNonEmptyIsReturnedAndRestNotEvaluated() { + Optional found = Stream.>>of(this::getEmpty, this::getHello, this::getBye) + .map(Supplier::get) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + + assertTrue(this.getEmptyEvaluated); + assertTrue(this.getHelloEvaluated); + assertFalse(this.getByeEvaluated); + assertEquals(getHello(), found); + } + + @Test + public void givenTwoOptionalsReturnedByOneArgMethod_whenChaining_thenFirstNonEmptyIsReturned() { + Optional found = Stream.>>of( + () -> createOptional("empty"), + () -> createOptional("hello") + ) + .map(Supplier::get) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + + assertEquals(createOptional("hello"), found); + } + + private Optional getEmpty() { + this.getEmptyEvaluated = true; + return Optional.empty(); + } + + private Optional getHello() { + this.getHelloEvaluated = true; + return Optional.of("hello"); + } + + private Optional getBye() { + this.getByeEvaluated = true; + return Optional.of("bye"); + } + + private Optional createOptional(String input) { + if (input == null || input == "" || input == "empty") { + return Optional.empty(); + } + + return Optional.of(input); + } +} \ No newline at end of file diff --git a/core-java-8/src/test/java/com/baeldung/streamreduce/tests/StreamReduceManualTest.java b/core-java-8/src/test/java/com/baeldung/streamreduce/tests/StreamReduceManualTest.java new file mode 100644 index 0000000000..9222cbb689 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/streamreduce/tests/StreamReduceManualTest.java @@ -0,0 +1,126 @@ +package com.baeldung.streamreduce.tests; + +import com.baeldung.streamreduce.entities.User; +import com.baeldung.streamreduce.utilities.NumberUtils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; + +public class StreamReduceManualTest { + + @Test + public void givenIntegerList_whenReduceWithSumAccumulatorLambda_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + + int result = numbers.stream().reduce(0, (a, b) -> a + b); + + assertThat(result).isEqualTo(21); + } + + @Test + public void givenIntegerList_whenReduceWithSumAccumulatorMethodReference_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + + int result = numbers.stream().reduce(0, Integer::sum); + + assertThat(result).isEqualTo(21); + } + + @Test + public void givenStringList_whenReduceWithConcatenatorAccumulatorLambda_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + + String result = letters.stream().reduce("", (a, b) -> a + b); + + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenStringList_whenReduceWithConcatenatorAccumulatorMethodReference_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + + String result = letters.stream().reduce("", String::concat); + + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenStringList_whenReduceWithUppercaseConcatenatorAccumulator_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + + String result = letters.stream().reduce("", (a, b) -> a.toUpperCase() + b.toUpperCase()); + + assertThat(result).isEqualTo("ABCDE"); + } + + @Test + public void givenUserList_whenReduceWithAgeAccumulatorAndSumCombiner_thenCorrect() { + List users = Arrays.asList(new User("John", 30), new User("Julie", 35)); + + int result = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + + assertThat(result).isEqualTo(65); + } + + @Test + public void givenStringList_whenReduceWithParallelStream_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + + String result = letters.parallelStream().reduce("", String::concat); + + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenNumberUtilsClass_whenCalledDivideListElements_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + + assertThat(NumberUtils.divideListElements(numbers, 1)).isEqualTo(21); + } + + @Test + public void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlock_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + + assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 1)).isEqualTo(21); + } + + @Test + public void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlockAndListContainsZero_thenCorrect() { + List numbers = Arrays.asList(0, 1, 2, 3, 4, 5, 6); + + assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 1)).isEqualTo(21); + } + + @Test + public void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlockAndDividerIsZero_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + + assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 0)).isEqualTo(0); + } + + @Test + public void givenStream_whneCalleddivideListElementsWithApplyFunctionMethod_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + + assertThat(NumberUtils.divideListElementsWithApplyFunctionMethod(numbers, 1)).isEqualTo(21); + } + + @Test + public void givenTwoStreams_whenCalledReduceOnParallelizedStream_thenFasterExecutionTime() { + List userList = new ArrayList<>(); + for (int i = 0; i <= 1000000; i++) { + userList.add(new User("John" + i, i)); + } + long currentTime1 = System.currentTimeMillis(); + userList.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + long sequentialExecutionTime = System.currentTimeMillis() -currentTime1; + long currentTime2 = System.currentTimeMillis(); + userList.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + long parallelizedExecutionTime = System.currentTimeMillis() - currentTime2; + + assertThat(parallelizedExecutionTime).isLessThan(sequentialExecutionTime); + } +} diff --git a/core-java-9/README.md b/core-java-9/README.md index d9586ba684..2477a38c00 100644 --- a/core-java-9/README.md +++ b/core-java-9/README.md @@ -9,14 +9,13 @@ - [Java 9 Convenience Factory Methods for Collections](http://www.baeldung.com/java-9-collections-factory-methods) - [New Stream Collectors in Java 9](http://www.baeldung.com/java9-stream-collectors) - [Java 9 CompletableFuture API Improvements](http://www.baeldung.com/java-9-completablefuture) -- [Java 9 Process API Improvements](http://www.baeldung.com/java-9-process-api) - [Introduction to Java 9 StackWalking API](http://www.baeldung.com/java-9-stackwalking-api) - [Introduction to Project Jigsaw](http://www.baeldung.com/project-jigsaw-java-modularity) - [Java 9 Optional API Additions](http://www.baeldung.com/java-9-optional) - [Java 9 Reactive Streams](http://www.baeldung.com/java-9-reactive-streams) - [Java 9 java.util.Objects Additions](http://www.baeldung.com/java-9-objects-new) - [Java 9 Variable Handles Demistyfied](http://www.baeldung.com/java-variable-handles) -- [Exploring the New HTTP Client in Java 9](http://www.baeldung.com/java-9-http-client) +- [Exploring the New HTTP Client in Java 9 and 11](http://www.baeldung.com/java-9-http-client) - [Method Handles in Java](http://www.baeldung.com/java-method-handles) - [Introduction to Chronicle Queue](http://www.baeldung.com/java-chronicle-queue) - [A Guide to Java 9 Modularity](http://www.baeldung.com/java-9-modularity) @@ -25,5 +24,7 @@ - [Iterate Through a Range of Dates in Java](https://www.baeldung.com/java-iterate-date-range) - [Initialize a HashMap in Java](https://www.baeldung.com/java-initialize-hashmap) - [Java 9 Platform Logging API](https://www.baeldung.com/java-9-logging-api) -- [Guide to java.lang.Process API](https://www.baeldung.com/java-process-api) - [Immutable Set in Java](https://www.baeldung.com/java-immutable-set) +- [Multi-Release Jar Files](https://www.baeldung.com/java-multi-release-jar) +- [Ahead of Time Compilation (AoT)](https://www.baeldung.com/ahead-of-time-compilation) + diff --git a/core-java-9/src/main/java/com/baeldung/multireleaseapp/App.java b/core-java-9/src/main/java/com/baeldung/multireleaseapp/App.java new file mode 100644 index 0000000000..21bbcc01d4 --- /dev/null +++ b/core-java-9/src/main/java/com/baeldung/multireleaseapp/App.java @@ -0,0 +1,16 @@ +package com.baeldung.multireleaseapp; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class App { + + private static final Logger logger = LoggerFactory.getLogger(App.class); + + public static void main(String[] args) throws Exception { + String dateToCheck = args[0]; + boolean isLeapYear = DateHelper.checkIfLeapYear(dateToCheck); + logger.info("Date given " + dateToCheck + " is leap year: " + isLeapYear); + } + +} diff --git a/core-java-9/src/main/java/com/baeldung/multireleaseapp/DateHelper.java b/core-java-9/src/main/java/com/baeldung/multireleaseapp/DateHelper.java new file mode 100644 index 0000000000..4d943db30b --- /dev/null +++ b/core-java-9/src/main/java/com/baeldung/multireleaseapp/DateHelper.java @@ -0,0 +1,22 @@ +package com.baeldung.multireleaseapp; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.GregorianCalendar; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DateHelper { + + private static final Logger logger = LoggerFactory.getLogger(DateHelper.class); + + public static boolean checkIfLeapYear(String dateStr) throws Exception { + logger.info("Checking for leap year using Java 1 calendar API"); + Calendar cal = Calendar.getInstance(); + cal.setTime(new SimpleDateFormat("yyyy-MM-dd").parse(dateStr)); + int year = cal.get(Calendar.YEAR); + return (new GregorianCalendar()).isLeapYear(year); + } + +} diff --git a/core-java-9/src/main/java9/com/baeldung/multireleaseapp/DateHelper.java b/core-java-9/src/main/java9/com/baeldung/multireleaseapp/DateHelper.java new file mode 100644 index 0000000000..35fb0ada1e --- /dev/null +++ b/core-java-9/src/main/java9/com/baeldung/multireleaseapp/DateHelper.java @@ -0,0 +1,18 @@ +package com.baeldung.multireleaseapp; + +import java.time.LocalDate; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DateHelper { + + private static final Logger logger = LoggerFactory.getLogger(DateHelper.class); + + public static boolean checkIfLeapYear(String dateStr) throws Exception { + logger.info("Checking for leap year using Java 9 Date Api"); + return LocalDate.parse(dateStr) + .isLeapYear(); + } + +} diff --git a/core-java-arrays/pom.xml b/core-java-arrays/pom.xml index 39ac764b27..ac9f7d08f0 100644 --- a/core-java-arrays/pom.xml +++ b/core-java-arrays/pom.xml @@ -390,7 +390,6 @@ 3.8.1 - 1.16.12 1.19 1.19 diff --git a/core-java-collections-list/README.md b/core-java-collections-list/README.md index d1112047ba..bfe06581c0 100644 --- a/core-java-collections-list/README.md +++ b/core-java-collections-list/README.md @@ -5,7 +5,7 @@ ### Relevant Articles: - [Immutable ArrayList in Java](http://www.baeldung.com/java-immutable-list) - [Guide to the Java ArrayList](http://www.baeldung.com/java-arraylist) -- [Random List Element](http://www.baeldung.com/java-random-list-element) +- [Java – Get Random Item/Element From a List](http://www.baeldung.com/java-random-list-element) - [Removing all nulls from a List in Java](http://www.baeldung.com/java-remove-nulls-from-list) - [Removing all duplicates from a List in Java](http://www.baeldung.com/java-remove-duplicates-from-list) - [How to TDD a List Implementation in Java](http://www.baeldung.com/java-test-driven-list) @@ -27,3 +27,7 @@ - [Flattening Nested Collections in Java](http://www.baeldung.com/java-flatten-nested-collections) - [Intersection of Two Lists in Java](https://www.baeldung.com/java-lists-intersection) - [Multi Dimensional ArrayList in Java](https://www.baeldung.com/java-multi-dimensional-arraylist) +- [Determine If All Elements Are the Same in a Java List](https://www.baeldung.com/java-list-all-equal) +- [List of Primitive Integer Values in Java](https://www.baeldung.com/java-list-primitive-int) +- [Performance Comparison of Primitive Lists in Java](https://www.baeldung.com/java-list-primitive-performance) +- [Filtering a Java Collection by a List](https://www.baeldung.com/java-filter-collection-by-list) diff --git a/core-java-collections-list/pom.xml b/core-java-collections-list/pom.xml index 737be8ee34..217278bdf6 100644 --- a/core-java-collections-list/pom.xml +++ b/core-java-collections-list/pom.xml @@ -52,6 +52,17 @@ colt ${colt.version} + + + org.openjdk.jmh + jmh-core + ${jmh-core.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh-core.version} + @@ -59,7 +70,6 @@ 3.8.1 1.7.0 3.11.1 - 1.16.12 3.0.2 8.1.0 1.2.0 diff --git a/core-java-collections-list/src/main/java/com/baeldung/collection/filtering/Employee.java b/core-java-collections-list/src/main/java/com/baeldung/collection/filtering/Employee.java new file mode 100644 index 0000000000..2aa267b4dc --- /dev/null +++ b/core-java-collections-list/src/main/java/com/baeldung/collection/filtering/Employee.java @@ -0,0 +1,44 @@ +package com.baeldung.collection.filtering; + +/** + * Java 8 Collection Filtering by List of Values base class. + * + * @author Rodolfo Felipe + */ +public class Employee { + + private Integer employeeNumber; + private String name; + private Integer departmentId; + + public Employee(Integer employeeNumber, String name, Integer departmentId) { + this.employeeNumber = employeeNumber; + this.name = name; + this.departmentId = departmentId; + } + + public Integer getEmployeeNumber() { + return employeeNumber; + } + + public void setEmployeeNumber(Integer employeeNumber) { + this.employeeNumber = employeeNumber; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getDepartmentId() { + return departmentId; + } + + public void setDepartmentId(Integer departmentId) { + this.departmentId = departmentId; + } + +} diff --git a/core-java-collections-list/src/main/java/com/baeldung/list/primitive/PrimitivesListPerformance.java b/core-java-collections-list/src/main/java/com/baeldung/list/primitive/PrimitivesListPerformance.java new file mode 100644 index 0000000000..bd37e5e74e --- /dev/null +++ b/core-java-collections-list/src/main/java/com/baeldung/list/primitive/PrimitivesListPerformance.java @@ -0,0 +1,96 @@ +package com.baeldung.list.primitive; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import gnu.trove.list.array.TIntArrayList; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.SingleShotTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Measurement(batchSize = 100000, iterations = 10) +@Warmup(batchSize = 100000, iterations = 10) +@State(Scope.Thread) +public class PrimitivesListPerformance { + + private List arrayList = new ArrayList<>(); + private TIntArrayList tList = new TIntArrayList(); + private cern.colt.list.IntArrayList coltList = new cern.colt.list.IntArrayList(); + private IntArrayList fastUtilList = new IntArrayList(); + + private int getValue = 10; + + @Benchmark + public boolean addArrayList() { + return arrayList.add(getValue); + } + + @Benchmark + public boolean addTroveIntList() { + return tList.add(getValue); + } + + @Benchmark + public void addColtIntList() { + coltList.add(getValue); + } + + @Benchmark + public boolean addFastUtilIntList() { + return fastUtilList.add(getValue); + } + + @Benchmark + public int getArrayList() { + return arrayList.get(getValue); + } + + @Benchmark + public int getTroveIntList() { + return tList.get(getValue); + } + + @Benchmark + public int getColtIntList() { + return coltList.get(getValue); + } + + @Benchmark + public int getFastUtilIntList() { + return fastUtilList.getInt(getValue); + } + + @Benchmark + public boolean containsArrayList() { + return arrayList.contains(getValue); + } + + @Benchmark + public boolean containsTroveIntList() { + return tList.contains(getValue); + } + + @Benchmark + public boolean containsColtIntList() { + return coltList.contains(getValue); + } + + @Benchmark + public boolean containsFastUtilIntList() { + return fastUtilList.contains(getValue); + } + + public static void main(String[] args) throws Exception { + Options options = new OptionsBuilder() + .include(PrimitivesListPerformance.class.getSimpleName()).threads(1) + .forks(1).shouldFailOnError(true) + .shouldDoGC(true) + .jvmArgs("-server").build(); + new Runner(options).run(); + } +} diff --git a/core-java-collections-list/src/test/java/com/baeldung/collection/filtering/CollectionFilteringUnitTest.java b/core-java-collections-list/src/test/java/com/baeldung/collection/filtering/CollectionFilteringUnitTest.java new file mode 100644 index 0000000000..cbc7136192 --- /dev/null +++ b/core-java-collections-list/src/test/java/com/baeldung/collection/filtering/CollectionFilteringUnitTest.java @@ -0,0 +1,73 @@ +package com.baeldung.collection.filtering; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; + +/** + * Various filtering examples. + * + * @author Rodolfo Felipe + */ +public class CollectionFilteringUnitTest { + + private List buildEmployeeList() { + return Arrays.asList(new Employee(1, "Mike", 1), new Employee(2, "John", 1), new Employee(3, "Mary", 1), new Employee(4, "Joe", 2), new Employee(5, "Nicole", 2), new Employee(6, "Alice", 2), new Employee(7, "Bob", 3), new Employee(8, "Scarlett", 3)); + } + + private List employeeNameFilter() { + return Arrays.asList("Alice", "Mike", "Bob"); + } + + @Test + public void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingForEachLoop() { + List filteredList = new ArrayList<>(); + List originalList = buildEmployeeList(); + List nameFilter = employeeNameFilter(); + + for (Employee employee : originalList) { + for (String name : nameFilter) { + if (employee.getName() + .equalsIgnoreCase(name)) { + filteredList.add(employee); + } + } + } + + Assert.assertThat(filteredList.size(), Matchers.is(nameFilter.size())); + } + + @Test + public void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingLambda() { + List filteredList; + List originalList = buildEmployeeList(); + List nameFilter = employeeNameFilter(); + + filteredList = originalList.stream() + .filter(employee -> nameFilter.contains(employee.getName())) + .collect(Collectors.toList()); + + Assert.assertThat(filteredList.size(), Matchers.is(nameFilter.size())); + } + + @Test + public void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingLambdaAndHashSet() { + List filteredList; + List originalList = buildEmployeeList(); + Set nameFilterSet = employeeNameFilter().stream() + .collect(Collectors.toSet()); + + filteredList = originalList.stream() + .filter(employee -> nameFilterSet.contains(employee.getName())) + .collect(Collectors.toList()); + + Assert.assertThat(filteredList.size(), Matchers.is(nameFilterSet.size())); + } + +} diff --git a/core-java-collections/README.md b/core-java-collections/README.md index 710be31a08..1e504ded65 100644 --- a/core-java-collections/README.md +++ b/core-java-collections/README.md @@ -32,3 +32,5 @@ - [A Guide to Iterator in Java](http://www.baeldung.com/java-iterator) - [Differences Between HashMap and Hashtable](https://www.baeldung.com/hashmap-hashtable-differences) - [Java ArrayList vs Vector](https://www.baeldung.com/java-arraylist-vs-vector) +- [Defining a Char Stack in Java](https://www.baeldung.com/java-char-stack) +- [Time Comparison of Arrays.sort(Object[]) and Arrays.sort(int[])](https://www.baeldung.com/arrays-sortobject-vs-sortint) diff --git a/core-java-collections/pom.xml b/core-java-collections/pom.xml index 261558836d..b791f38b24 100644 --- a/core-java-collections/pom.xml +++ b/core-java-collections/pom.xml @@ -73,7 +73,6 @@ 1.7.0 3.11.1 7.1.0 - 1.16.12 1.3 diff --git a/core-java-collections/src/main/java/com/baeldung/java/sort/CollectionsSortCompare.java b/core-java-collections/src/main/java/com/baeldung/java/sort/CollectionsSortCompare.java new file mode 100644 index 0000000000..1eff522877 --- /dev/null +++ b/core-java-collections/src/main/java/com/baeldung/java/sort/CollectionsSortCompare.java @@ -0,0 +1,39 @@ +package com.baeldung.java.sort; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class CollectionsSortCompare { + + public static void main(String[] args) { + sortPrimitives(); + sortReferenceType(); + sortCollection(); + } + + private static void sortReferenceType() { + Integer[] numbers = {5, 22, 10, 0}; + Arrays.sort(numbers); + System.out.println(Arrays.toString(numbers)); + } + + private static void sortCollection() { + List numbersList = new ArrayList<>(); + numbersList.add(5); + numbersList.add(22); + numbersList.add(10); + numbersList.add(0); + + Collections.sort(numbersList); + + numbersList.forEach(System.out::print); + } + + private static void sortPrimitives() { + int[] numbers = {5, 22, 10, 0}; + Arrays.sort(numbers); + System.out.println(Arrays.toString(numbers)); + } +} diff --git a/core-java-collections/src/main/java/com/baeldung/performance/ArraySortBenchmark.java b/core-java-collections/src/main/java/com/baeldung/performance/ArraySortBenchmark.java new file mode 100644 index 0000000000..b93f8e9cc2 --- /dev/null +++ b/core-java-collections/src/main/java/com/baeldung/performance/ArraySortBenchmark.java @@ -0,0 +1,51 @@ +package com.baeldung.performance; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Measurement(batchSize = 100000, iterations = 10) +@Warmup(batchSize = 100000, iterations = 10) +public class ArraySortBenchmark { + + @State(Scope.Thread) + public static class Initialize { + Integer[] numbers = { -769214442, -1283881723, 1504158300, -1260321086, -1800976432, 1278262737, 1863224321, 1895424914, 2062768552, -1051922993, 751605209, -1500919212, 2094856518, -1014488489, -931226326, -1677121986, -2080561705, 562424208, -1233745158, 41308167 }; + int[] primitives = { -769214442, -1283881723, 1504158300, -1260321086, -1800976432, 1278262737, 1863224321, 1895424914, 2062768552, -1051922993, 751605209, -1500919212, 2094856518, -1014488489, -931226326, -1677121986, -2080561705, 562424208, -1233745158, 41308167 }; + } + + @Benchmark + public Integer[] benchmarkArraysIntegerSort(ArraySortBenchmark.Initialize state) { + Arrays.sort(state.numbers); + return state.numbers; + } + + @Benchmark + public int[] benchmarkArraysIntSort(ArraySortBenchmark.Initialize state) { + Arrays.sort(state.primitives); + return state.primitives; + } + + + public static void main(String[] args) throws Exception { + Options options = new OptionsBuilder() + .include(ArraySortBenchmark.class.getSimpleName()).threads(1) + .forks(1).shouldFailOnError(true) + .shouldDoGC(true) + .jvmArgs("-server").build(); + new Runner(options).run(); + } +} diff --git a/core-java-concurrency-advanced/README.md b/core-java-concurrency-advanced/README.md index bcbec9d687..f48fd30c73 100644 --- a/core-java-concurrency-advanced/README.md +++ b/core-java-concurrency-advanced/README.md @@ -21,4 +21,5 @@ - [Java CyclicBarrier vs CountDownLatch](https://www.baeldung.com/java-cyclicbarrier-countdownlatch) - [Guide to the Fork/Join Framework in Java](http://www.baeldung.com/java-fork-join) - [A Guide to ThreadLocalRandom in Java](http://www.baeldung.com/java-thread-local-random) -- [The Thread.join() Method in Java](http://www.baeldung.com/java-thread-join) \ No newline at end of file +- [The Thread.join() Method in Java](http://www.baeldung.com/java-thread-join) +- [Passing Parameters to Java Threads](https://www.baeldung.com/java-thread-parameters) diff --git a/core-java-concurrency-basic/README.md b/core-java-concurrency-basic/README.md index ad3de4a758..7d106095e7 100644 --- a/core-java-concurrency-basic/README.md +++ b/core-java-concurrency-basic/README.md @@ -16,3 +16,4 @@ - [Life Cycle of a Thread in Java](http://www.baeldung.com/java-thread-lifecycle) - [Runnable vs. Callable in Java](http://www.baeldung.com/java-runnable-callable) - [What is Thread-Safety and How to Achieve it](https://www.baeldung.com/java-thread-safety) +- [How to Start a Thread in Java](https://www.baeldung.com/java-start-thread) diff --git a/core-java-io/README.md b/core-java-io/README.md index 9a25009849..05b9165147 100644 --- a/core-java-io/README.md +++ b/core-java-io/README.md @@ -3,7 +3,7 @@ ## Core Java IO Cookbooks and Examples ### Relevant Articles: -- [Java - Reading a Large File Efficiently](http://www.baeldung.com/java-read-lines-large-file) +- [How to Read a Large File Efficiently with Java](http://www.baeldung.com/java-read-lines-large-file) - [Java InputStream to String](http://www.baeldung.com/convert-input-stream-to-string) - [Java – Write to File](http://www.baeldung.com/java-write-to-file) - [Java - Convert File to InputStream](http://www.baeldung.com/convert-file-to-input-stream) @@ -11,7 +11,7 @@ - [Java – Byte Array to Writer](http://www.baeldung.com/java-convert-byte-array-to-writer) - [Java – Directory Size](http://www.baeldung.com/java-folder-size) - [Differences Between the Java WatchService API and the Apache Commons IO Monitor Library](http://www.baeldung.com/java-watchservice-vs-apache-commons-io-monitor-library) -- [Calculate the Size of a File in Java](http://www.baeldung.com/java-file-size) +- [File Size in Java](http://www.baeldung.com/java-file-size) - [Comparing getPath(), getAbsolutePath(), and getCanonicalPath() in Java](http://www.baeldung.com/java-path) - [Using Java MappedByteBuffer](http://www.baeldung.com/java-mapped-byte-buffer) - [Copy a File with Java](http://www.baeldung.com/java-copy-file) @@ -30,7 +30,6 @@ - [Download a File From an URL in Java](http://www.baeldung.com/java-download-file) - [Create a Symbolic Link with Java](http://www.baeldung.com/java-symlink) - [Quick Use of FilenameFilter](http://www.baeldung.com/java-filename-filter) -- [Initialize a HashMap in Java](https://www.baeldung.com/java-initialize-hashmap) - [Read a File into an ArrayList](https://www.baeldung.com/java-file-to-arraylist) - [Guide to Java OutputStream](https://www.baeldung.com/java-outputstream) - [Reading a CSV File into an Array](https://www.baeldung.com/java-csv-file-array) @@ -40,3 +39,4 @@ - [Create a Directory in Java](https://www.baeldung.com/java-create-directory) - [How to Write to a CSV File in Java](https://www.baeldung.com/java-csv) - [List Files in a Directory in Java](https://www.baeldung.com/java-list-directory-files) +- [Java InputStream to Byte Array and ByteBuffer](https://www.baeldung.com/convert-input-stream-to-array-of-bytes) diff --git a/core-java-io/pom.xml b/core-java-io/pom.xml index 350e1a8b96..b6f8a317f6 100644 --- a/core-java-io/pom.xml +++ b/core-java-io/pom.xml @@ -246,8 +246,6 @@ - - 2.9.7 3.5 @@ -259,7 +257,6 @@ 4.01 0.4 1.8.7 - 1.16.12 4.6-b01 1.13 0.6.5 diff --git a/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java b/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java index 0658ec6101..5f4827bc21 100644 --- a/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java +++ b/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -17,7 +18,6 @@ import org.slf4j.LoggerFactory; public class WriteCsvFileExampleUnitTest { private static final Logger LOG = LoggerFactory.getLogger(WriteCsvFileExampleUnitTest.class); - private static final String CSV_FILE_NAME = "src/test/resources/exampleOutput.csv"; private WriteCsvFileExample csvExample; @Before @@ -65,12 +65,12 @@ public class WriteCsvFileExampleUnitTest { } @Test - public void givenDataArray_whenConvertToCSV_thenOutputCreated() { + public void givenDataArray_whenConvertToCSV_thenOutputCreated() throws IOException { List dataLines = new ArrayList(); dataLines.add(new String[] { "John", "Doe", "38", "Comment Data\nAnother line of comment data" }); dataLines.add(new String[] { "Jane", "Doe, Jr.", "19", "She said \"I'm being quoted\"" }); - File csvOutputFile = new File(CSV_FILE_NAME); + File csvOutputFile = File.createTempFile("exampleOutput", ".csv"); try (PrintWriter pw = new PrintWriter(csvOutputFile)) { dataLines.stream() .map(csvExample::convertToCSV) @@ -80,5 +80,6 @@ public class WriteCsvFileExampleUnitTest { } assertTrue(csvOutputFile.exists()); + csvOutputFile.deleteOnExit(); } } diff --git a/core-java-io/src/test/resources/exampleOutput.csv b/core-java-io/src/test/resources/exampleOutput.csv deleted file mode 100644 index 45c37f3a3b..0000000000 --- a/core-java-io/src/test/resources/exampleOutput.csv +++ /dev/null @@ -1,2 +0,0 @@ -John,Doe,38,Comment Data Another line of comment data -Jane,"Doe, Jr.",19,"She said ""I'm being quoted""" \ No newline at end of file diff --git a/core-java-jvm/README.md b/core-java-jvm/README.md new file mode 100644 index 0000000000..529453f3c4 --- /dev/null +++ b/core-java-jvm/README.md @@ -0,0 +1,6 @@ +========= + +## Core Java JVM Cookbooks and Examples + +### Relevant Articles: +- [Method Inlining in the JVM](http://www.baeldung.com/method-inlining-in-the-jvm/) diff --git a/core-java-jvm/pom.xml b/core-java-jvm/pom.xml new file mode 100644 index 0000000000..752b26f03f --- /dev/null +++ b/core-java-jvm/pom.xml @@ -0,0 +1,40 @@ + + 4.0.0 + com.baeldung + core-java-jvm + 0.1.0-SNAPSHOT + jar + core-java-jvm + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + junit + junit + ${junit.version} + test + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + 3.5 + 3.6.1 + + diff --git a/core-java-jvm/src/main/java/com/baeldung/inlining/ConsecutiveNumbersSum.java b/core-java-jvm/src/main/java/com/baeldung/inlining/ConsecutiveNumbersSum.java new file mode 100644 index 0000000000..7de642f1c0 --- /dev/null +++ b/core-java-jvm/src/main/java/com/baeldung/inlining/ConsecutiveNumbersSum.java @@ -0,0 +1,19 @@ +package com.baeldung.inlining; + +public class ConsecutiveNumbersSum { + + private long totalSum; + private int totalNumbers; + + public ConsecutiveNumbersSum(int totalNumbers) { + this.totalNumbers = totalNumbers; + } + + public long getTotalSum() { + totalSum = 0; + for (int i = 1; i <= totalNumbers; i++) { + totalSum += i; + } + return totalSum; + } +} diff --git a/core-java-jvm/src/main/java/com/baeldung/inlining/InliningExample.java b/core-java-jvm/src/main/java/com/baeldung/inlining/InliningExample.java new file mode 100644 index 0000000000..4c1802d0e4 --- /dev/null +++ b/core-java-jvm/src/main/java/com/baeldung/inlining/InliningExample.java @@ -0,0 +1,16 @@ +package com.baeldung.inlining; + +public class InliningExample { + + public static final int NUMBERS_OF_ITERATIONS = 15000; + + public static void main(String[] args) { + for (int i = 1; i < NUMBERS_OF_ITERATIONS; i++) { + calculateSum(i); + } + } + + private static long calculateSum(int n) { + return new ConsecutiveNumbersSum(n).getTotalSum(); + } +} diff --git a/core-java-jvm/src/test/java/com/baeldung/inlining/ConsecutiveNumbersSumUnitTest.java b/core-java-jvm/src/test/java/com/baeldung/inlining/ConsecutiveNumbersSumUnitTest.java new file mode 100644 index 0000000000..8e4b0353e6 --- /dev/null +++ b/core-java-jvm/src/test/java/com/baeldung/inlining/ConsecutiveNumbersSumUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.inlining; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ConsecutiveNumbersSumUnitTest { + + private static final int TOTAL_NUMBERS = 10; + + @Test + public void givenTotalIntegersNumber_whenSumCalculated_thenEquals() { + ConsecutiveNumbersSum consecutiveNumbersSum = new ConsecutiveNumbersSum(TOTAL_NUMBERS); + long expectedSum = calculateExpectedSum(TOTAL_NUMBERS); + + assertEquals(expectedSum, consecutiveNumbersSum.getTotalSum()); + } + + private long calculateExpectedSum(int totalNumbers) { + return totalNumbers * (totalNumbers + 1) / 2; + } +} diff --git a/core-java-lang-oop/README.md b/core-java-lang-oop/README.md index bbc3d26c99..970a8d44b1 100644 --- a/core-java-lang-oop/README.md +++ b/core-java-lang-oop/README.md @@ -5,7 +5,6 @@ ### Relevant Articles: - [Guide to hashCode() in Java](http://www.baeldung.com/java-hashcode) - [A Guide to the Static Keyword in Java](http://www.baeldung.com/java-static) -- [A Guide to Java Initialization](http://www.baeldung.com/java-initialization) - [Polymorphism in Java](http://www.baeldung.com/java-polymorphism) - [Method Overloading and Overriding in Java](http://www.baeldung.com/java-method-overload-override) - [How to Make a Deep Copy of an Object in Java](http://www.baeldung.com/java-deep-copy) @@ -22,3 +21,4 @@ - [Inheritance and Composition (Is-a vs Has-a relationship) in Java](http://www.baeldung.com/java-inheritance-composition) - [A Guide to Constructors in Java](https://www.baeldung.com/java-constructors) - [Java equals() and hashCode() Contracts](https://www.baeldung.com/java-equals-hashcode-contracts) +- [Marker Interfaces in Java](https://www.baeldung.com/java-marker-interfaces) diff --git a/core-java-lang-oop/pom.xml b/core-java-lang-oop/pom.xml index 8cfaf2b544..6763bbb26d 100644 --- a/core-java-lang-oop/pom.xml +++ b/core-java-lang-oop/pom.xml @@ -82,7 +82,6 @@ 3.5 - 1.16.12 3.10.0 3.0.3 diff --git a/core-java-lang-syntax/README.md b/core-java-lang-syntax/README.md index 99c8613929..81c3d6c354 100644 --- a/core-java-lang-syntax/README.md +++ b/core-java-lang-syntax/README.md @@ -3,12 +3,12 @@ ## Core Java Lang Syntax Cookbooks and Examples ### Relevant Articles: -- [Introduction to Java Generics](http://www.baeldung.com/java-generics) +- [The Basics of Java Generics](http://www.baeldung.com/java-generics) - [Java Primitive Conversions](http://www.baeldung.com/java-primitive-conversions) - [Java Double Brace Initialization](http://www.baeldung.com/java-double-brace-initialization) - [Guide to the Diamond Operator in Java](http://www.baeldung.com/java-diamond-operator) - [The Java continue and break Keywords](http://www.baeldung.com/java-continue-and-break) -- [A Guide to Java Initialization](http://www.baeldung.com/java-initialization) +- [A Guide to Creating Objects in Java](http://www.baeldung.com/java-initialization) - [A Guide to Java Loops](http://www.baeldung.com/java-loops) - [Varargs in Java](http://www.baeldung.com/java-varargs) - [A Guide to Java Enums](http://www.baeldung.com/a-guide-to-java-enums) diff --git a/core-java-lang-syntax/src/main/java/com/baeldung/enums/README.md b/core-java-lang-syntax/src/main/java/com/baeldung/enums/README.md deleted file mode 100644 index 6ccfa725f5..0000000000 --- a/core-java-lang-syntax/src/main/java/com/baeldung/enums/README.md +++ /dev/null @@ -1,2 +0,0 @@ -### Relevant Articles: -- [A Guide to Java Enums](http://www.baeldung.com/a-guide-to-java-enums) diff --git a/core-java-lang-syntax/src/main/java/com/baeldung/generics/Generics.java b/core-java-lang-syntax/src/main/java/com/baeldung/generics/Generics.java index e0536ca02e..1c4082c58b 100644 --- a/core-java-lang-syntax/src/main/java/com/baeldung/generics/Generics.java +++ b/core-java-lang-syntax/src/main/java/com/baeldung/generics/Generics.java @@ -1,5 +1,6 @@ package com.baeldung.generics; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Function; @@ -28,4 +29,10 @@ public class Generics { buildings.forEach(Building::paint); } + public static List createList(int a) { + List list = new ArrayList<>(); + list.add(a); + return list; + } + } \ No newline at end of file diff --git a/core-java-lang-syntax/src/test/java/com/baeldung/generics/GenericsUnitTest.java b/core-java-lang-syntax/src/test/java/com/baeldung/generics/GenericsUnitTest.java index aca0b182a0..0bdf0afc15 100644 --- a/core-java-lang-syntax/src/test/java/com/baeldung/generics/GenericsUnitTest.java +++ b/core-java-lang-syntax/src/test/java/com/baeldung/generics/GenericsUnitTest.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; @@ -66,4 +67,12 @@ public class GenericsUnitTest { } } + @Test + public void givenAnInt_whenAddedToAGenericIntegerList_thenAListItemCanBeAssignedToAnInt() { + int number = 7; + List list = Generics.createList(number); + int otherNumber = list.get(0); + assertThat(otherNumber, is(number)); + } + } \ No newline at end of file diff --git a/core-java-lang/README.md b/core-java-lang/README.md index c1c22caf6c..eaedc93eed 100644 --- a/core-java-lang/README.md +++ b/core-java-lang/README.md @@ -41,3 +41,4 @@ - [Java Interfaces](https://www.baeldung.com/java-interfaces) - [Attaching Values to Java Enum](https://www.baeldung.com/java-enum-values) - [Variable Scope in Java](https://www.baeldung.com/java-variable-scope) +- [Java Classes and Objects](https://www.baeldung.com/java-classes-objects) diff --git a/core-java-lang/pom.xml b/core-java-lang/pom.xml index 6881fd56db..551c8e8505 100644 --- a/core-java-lang/pom.xml +++ b/core-java-lang/pom.xml @@ -74,14 +74,10 @@ - - - 2.9.7 2.8.2 3.5 - 1.16.12 1.5.0-b01 diff --git a/core-java-networking/README.md b/core-java-networking/README.md index b2367782b6..e76f28030d 100644 --- a/core-java-networking/README.md +++ b/core-java-networking/README.md @@ -12,5 +12,6 @@ - [A Guide to the Java URL](http://www.baeldung.com/java-url) - [Working with Network Interfaces in Java](http://www.baeldung.com/java-network-interfaces) - [A Guide to Java Sockets](http://www.baeldung.com/a-guide-to-java-sockets) -- [URL Encoding and Decoding in Java](http://www.baeldung.com/java-url-encoding-decoding) -- [How to Perform a Simple HTTP Request in Java](http://www.baeldung.com/java-http-request) \ No newline at end of file +- [Guide to Java URL Encoding/Decoding](http://www.baeldung.com/java-url-encoding-decoding) +- [Do a Simple HTTP Request in Java](http://www.baeldung.com/java-http-request) +- [Difference between URL and URI](http://www.baeldung.com/java-url-vs-uri) \ No newline at end of file diff --git a/core-java-networking/src/main/java/com/baeldung/socket/read/Client.java b/core-java-networking/src/main/java/com/baeldung/socket/read/Client.java new file mode 100644 index 0000000000..5e2a84a767 --- /dev/null +++ b/core-java-networking/src/main/java/com/baeldung/socket/read/Client.java @@ -0,0 +1,29 @@ +package com.baeldung.socket.read; + +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.io.*; + +public class Client { + + public void runClient(String ip, int port) { + try { + Socket socket = new Socket(ip, port); + System.out.println("Connected to server ..."); + DataInputStream in = new DataInputStream(System.in); + DataOutputStream out = new DataOutputStream(socket.getOutputStream()); + + char type = 's'; // s for string + int length = 29; + String data = "This is a string of length 29"; + byte[] dataInBytes = data.getBytes(StandardCharsets.UTF_8); + //Sending data in TLV format + out.writeChar(type); + out.writeInt(length); + out.write(dataInBytes); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/core-java-networking/src/main/java/com/baeldung/socket/read/Server.java b/core-java-networking/src/main/java/com/baeldung/socket/read/Server.java new file mode 100644 index 0000000000..2ab91c6cdc --- /dev/null +++ b/core-java-networking/src/main/java/com/baeldung/socket/read/Server.java @@ -0,0 +1,49 @@ +package com.baeldung.socket.read; + +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.io.*; + +public class Server { + + public void runServer(int port) { + //Start the server and wait for connection + try { + ServerSocket server = new ServerSocket(port); + System.out.println("Server Started. Waiting for connection ..."); + Socket socket = server.accept(); + System.out.println("Got connection from client."); + //Get input stream from socket variable and convert the same to DataInputStream + DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream())); + //Read type and length of data + char dataType = in.readChar(); + int length = in.readInt(); + System.out.println("Type : "+dataType); + System.out.println("Lenght :"+length); + if(dataType == 's') { + //Read String data in bytes + byte[] messageByte = new byte[length]; + boolean end = false; + StringBuilder dataString = new StringBuilder(length); + int totalBytesRead = 0; + //We need to run while loop, to read all data in that stream + while(!end) { + int currentBytesRead = in.read(messageByte); + totalBytesRead = currentBytesRead + totalBytesRead; + if(totalBytesRead <= length) { + dataString.append(new String(messageByte,0,currentBytesRead,StandardCharsets.UTF_8)); + } else { + dataString.append(new String(messageByte,0,length - totalBytesRead + currentBytesRead,StandardCharsets.UTF_8)); + } + if(dataString.length()>=length) { + end = true; + } + } + System.out.println("Read "+length+" bytes of message from client. Message = "+dataString); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/core-java-networking/src/test/java/com/baeldung/socket/read/SocketReadAllDataLiveTest.java b/core-java-networking/src/test/java/com/baeldung/socket/read/SocketReadAllDataLiveTest.java new file mode 100644 index 0000000000..da7f5b8d3f --- /dev/null +++ b/core-java-networking/src/test/java/com/baeldung/socket/read/SocketReadAllDataLiveTest.java @@ -0,0 +1,37 @@ +package com.baeldung.socket.read; + +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; + +public class SocketReadAllDataLiveTest { + + @Test + public void givenServerAndClient_whenClientSendsAndServerReceivesData_thenCorrect() { + //Run server in new thread + Runnable runnable1 = () -> { runServer(); }; + Thread thread1 = new Thread(runnable1); + thread1.start(); + //Wait for 10 seconds + try { + TimeUnit.SECONDS.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + //Run client in a new thread + Runnable runnable2 = () -> { runClient(); }; + Thread thread2 = new Thread(runnable2); + thread2.start(); + } + + public static void runServer() { + //Run Server + Server server = new Server(); + server.runServer(5555); + } + + public static void runClient() { + //Run Client + Client client = new Client(); + client.runClient("127.0.0.1", 5555); + } +} \ No newline at end of file diff --git a/core-java-os/.gitignore b/core-java-os/.gitignore new file mode 100644 index 0000000000..3de4cc647e --- /dev/null +++ b/core-java-os/.gitignore @@ -0,0 +1,26 @@ +*.class + +0.* + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* +.resourceCache + +# Packaged files # +*.jar +*.war +*.ear + +# Files generated by integration tests +*.txt +backup-pom.xml +/bin/ +/temp + +#IntelliJ specific +.idea/ +*.iml \ No newline at end of file diff --git a/core-java-os/README.md b/core-java-os/README.md new file mode 100644 index 0000000000..5f5d373d9b --- /dev/null +++ b/core-java-os/README.md @@ -0,0 +1,10 @@ +========= + +This module uses Java 9, so make sure to have the JDK 9 installed to run it. + +## +### Relevant Articles: +- [Java 9 Process API Improvements](http://www.baeldung.com/java-9-process-api) +- [Guide to java.lang.Process API](https://www.baeldung.com/java-process-api) +- [Guide to java.lang.ProcessBuilder API](https://www.baeldung.com/java-lang-processbuilder-api) + diff --git a/core-java-os/pom.xml b/core-java-os/pom.xml new file mode 100644 index 0000000000..c9097cb554 --- /dev/null +++ b/core-java-os/pom.xml @@ -0,0 +1,82 @@ + + 4.0.0 + com.baeldung + core-java-os + 0.1.0-SNAPSHOT + core-java-os + jar + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + commons-io + commons-io + ${commons-io.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + log4j + log4j + ${log4j.version} + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + core-java-os + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + + 3.5 + 4.1 + 4.01 + + + 3.6.1 + 1.8.9 + 1.9 + 1.9 + 25.1-jre + + diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/ChildProcess.java b/core-java-os/src/main/java/com/baeldung/java9/process/ChildProcess.java similarity index 100% rename from core-java-9/src/main/java/com/baeldung/java9/process/ChildProcess.java rename to core-java-os/src/main/java/com/baeldung/java9/process/ChildProcess.java diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/OutputStreamExample.java b/core-java-os/src/main/java/com/baeldung/java9/process/OutputStreamExample.java similarity index 100% rename from core-java-9/src/main/java/com/baeldung/java9/process/OutputStreamExample.java rename to core-java-os/src/main/java/com/baeldung/java9/process/OutputStreamExample.java diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java b/core-java-os/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java similarity index 87% rename from core-java-9/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java rename to core-java-os/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java index 8b6ae0b441..73eacddc4c 100644 --- a/core-java-9/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java +++ b/core-java-os/src/main/java/com/baeldung/java9/process/ProcessCompilationError.java @@ -3,5 +3,5 @@ package com.baeldung.java9.process; public class ProcessCompilationError { //This method has been written to generate error to display //how process errorStream() can consume error - public static void(); + //public static void(); } diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/ProcessUnderstanding.java b/core-java-os/src/main/java/com/baeldung/java9/process/ProcessUnderstanding.java similarity index 100% rename from core-java-9/src/main/java/com/baeldung/java9/process/ProcessUnderstanding.java rename to core-java-os/src/main/java/com/baeldung/java9/process/ProcessUnderstanding.java diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/ProcessUtils.java b/core-java-os/src/main/java/com/baeldung/java9/process/ProcessUtils.java similarity index 100% rename from core-java-9/src/main/java/com/baeldung/java9/process/ProcessUtils.java rename to core-java-os/src/main/java/com/baeldung/java9/process/ProcessUtils.java diff --git a/core-java-9/src/main/java/com/baeldung/java9/process/ServiceMain.java b/core-java-os/src/main/java/com/baeldung/java9/process/ServiceMain.java similarity index 100% rename from core-java-9/src/main/java/com/baeldung/java9/process/ServiceMain.java rename to core-java-os/src/main/java/com/baeldung/java9/process/ServiceMain.java diff --git a/noexception/src/main/resources/logback.xml b/core-java-os/src/main/resources/logback.xml similarity index 100% rename from noexception/src/main/resources/logback.xml rename to core-java-os/src/main/resources/logback.xml diff --git a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java similarity index 89% rename from core-java-9/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java rename to core-java-os/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java index 9a227a9c8f..8cefceef1d 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java +++ b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java @@ -18,13 +18,13 @@ import org.slf4j.LoggerFactory; public class ProcessAPIEnhancementsUnitTest { - Logger log = LoggerFactory.getLogger(ProcessAPIEnhancementsTest.class); + Logger log = LoggerFactory.getLogger(ProcessAPIEnhancementsUnitTest.class); @Test public void givenCurrentProcess_whenInvokeGetInfo_thenSuccess() throws IOException { ProcessHandle processHandle = ProcessHandle.current(); ProcessHandle.Info processInfo = processHandle.info(); - assertNotNull(processHandle.getPid()); + assertNotNull(processHandle.pid()); assertEquals(false, processInfo.arguments() .isPresent()); assertEquals(true, processInfo.command() @@ -51,7 +51,7 @@ public class ProcessAPIEnhancementsUnitTest { .start(); ProcessHandle processHandle = process.toHandle(); ProcessHandle.Info processInfo = processHandle.info(); - assertNotNull(processHandle.getPid()); + assertNotNull(processHandle.pid()); assertEquals(false, processInfo.arguments() .isPresent()); assertEquals(true, processInfo.command() @@ -72,7 +72,7 @@ public class ProcessAPIEnhancementsUnitTest { Stream liveProcesses = ProcessHandle.allProcesses(); liveProcesses.filter(ProcessHandle::isAlive) .forEach(ph -> { - assertNotNull(ph.getPid()); + assertNotNull(ph.pid()); assertEquals(true, ph.info() .command() .isPresent()); @@ -102,12 +102,12 @@ public class ProcessAPIEnhancementsUnitTest { Stream children = ProcessHandle.current() .children(); children.filter(ProcessHandle::isAlive) - .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.getPid(), ph.info() + .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.pid(), ph.info() .command())); Stream descendants = ProcessHandle.current() .descendants(); descendants.filter(ProcessHandle::isAlive) - .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.getPid(), ph.info() + .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.pid(), ph.info() .command())); } @@ -121,12 +121,12 @@ public class ProcessAPIEnhancementsUnitTest { .start(); ProcessHandle processHandle = process.toHandle(); - log.info("PID: {} has started", processHandle.getPid()); + log.info("PID: {} has started", processHandle.pid()); CompletableFuture onProcessExit = processHandle.onExit(); onProcessExit.get(); assertEquals(false, processHandle.isAlive()); onProcessExit.thenAccept(ph -> { - log.info("PID: {} has stopped", ph.getPid()); + log.info("PID: {} has stopped", ph.pid()); }); } diff --git a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java similarity index 85% rename from core-java-9/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java rename to core-java-os/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java index e125f10da7..8bdf8cb09f 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java +++ b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessApiUnitTest.java @@ -30,7 +30,7 @@ public class ProcessApiUnitTest { @Test public void processInfoExample() throws NoSuchAlgorithmException { ProcessHandle self = ProcessHandle.current(); - long PID = self.getPid(); + long PID = self.pid(); ProcessHandle.Info procInfo = self.info(); Optional args = procInfo.arguments(); Optional cmd = procInfo.commandLine(); @@ -45,7 +45,7 @@ public class ProcessApiUnitTest { Stream allProc = ProcessHandle.current().children(); allProc.forEach(p -> { - System.out.println("Proc " + p.getPid()); + System.out.println("Proc " + p.pid()); }); } @@ -54,7 +54,7 @@ public class ProcessApiUnitTest { public void createAndDestroyProcess() throws IOException, InterruptedException { int numberOfChildProcesses = 5; for (int i = 0; i < numberOfChildProcesses; i++) { - createNewJVM(ServiceMain.class, i).getPid(); + createNewJVM(ServiceMain.class, i).pid(); } Stream childProc = ProcessHandle.current().children(); @@ -62,10 +62,10 @@ public class ProcessApiUnitTest { childProc = ProcessHandle.current().children(); childProc.forEach(processHandle -> { - assertTrue("Process " + processHandle.getPid() + " should be alive!", processHandle.isAlive()); + assertTrue("Process " + processHandle.pid() + " should be alive!", processHandle.isAlive()); CompletableFuture onProcExit = processHandle.onExit(); onProcExit.thenAccept(procHandle -> { - System.out.println("Process with PID " + procHandle.getPid() + " has stopped"); + System.out.println("Process with PID " + procHandle.pid() + " has stopped"); }); }); @@ -73,14 +73,14 @@ public class ProcessApiUnitTest { childProc = ProcessHandle.current().children(); childProc.forEach(procHandle -> { - assertTrue("Could not kill process " + procHandle.getPid(), procHandle.destroy()); + assertTrue("Could not kill process " + procHandle.pid(), procHandle.destroy()); }); Thread.sleep(5000); childProc = ProcessHandle.current().children(); childProc.forEach(procHandle -> { - assertFalse("Process " + procHandle.getPid() + " should not be alive!", procHandle.isAlive()); + assertFalse("Process " + procHandle.pid() + " should not be alive!", procHandle.isAlive()); }); } diff --git a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessUnderstandingTest.java b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessUnderstandingUnitTest.java similarity index 99% rename from core-java-9/src/test/java/com/baeldung/java9/process/ProcessUnderstandingTest.java rename to core-java-os/src/test/java/com/baeldung/java9/process/ProcessUnderstandingUnitTest.java index 2c5525b9ed..6ad07c5c3a 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessUnderstandingTest.java +++ b/core-java-os/src/test/java/com/baeldung/java9/process/ProcessUnderstandingUnitTest.java @@ -14,7 +14,7 @@ import java.lang.Integer; import org.junit.jupiter.api.Test; -class ProcessUnderstandingTest { +class ProcessUnderstandingUnitTest { @Test public void givenSourceProgram_whenExecutedFromAnotherProgram_thenSourceProgramOutput3() throws IOException { diff --git a/core-java-os/src/test/java/com/baeldung/processbuilder/ProcessBuilderUnitTest.java b/core-java-os/src/test/java/com/baeldung/processbuilder/ProcessBuilderUnitTest.java new file mode 100644 index 0000000000..0458383e99 --- /dev/null +++ b/core-java-os/src/test/java/com/baeldung/processbuilder/ProcessBuilderUnitTest.java @@ -0,0 +1,182 @@ +package com.baeldung.processbuilder; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.ProcessBuilder.Redirect; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class ProcessBuilderUnitTest { + + @Rule + public TemporaryFolder tempFolder = new TemporaryFolder(); + + @Test + public void givenProcessBuilder_whenInvokeStart_thenSuccess() throws IOException, InterruptedException, ExecutionException { + ProcessBuilder processBuilder = new ProcessBuilder("java", "-version"); + processBuilder.redirectErrorStream(true); + + Process process = processBuilder.start(); + + List results = readOutput(process.getInputStream()); + assertThat("Results should not be empty", results, is(not(empty()))); + assertThat("Results should contain java version: ", results, hasItem(containsString("java version"))); + + int exitCode = process.waitFor(); + assertEquals("No errors should be detected", 0, exitCode); + } + + @Test + public void givenProcessBuilder_whenModifyEnvironment_thenSuccess() throws IOException, InterruptedException { + ProcessBuilder processBuilder = new ProcessBuilder(); + Map environment = processBuilder.environment(); + environment.forEach((key, value) -> System.out.println(key + value)); + + environment.put("GREETING", "Hola Mundo"); + + List command = getGreetingCommand(); + processBuilder.command(command); + Process process = processBuilder.start(); + + List results = readOutput(process.getInputStream()); + assertThat("Results should not be empty", results, is(not(empty()))); + assertThat("Results should contain a greeting ", results, hasItem(containsString("Hola Mundo"))); + + int exitCode = process.waitFor(); + assertEquals("No errors should be detected", 0, exitCode); + } + + @Test + public void givenProcessBuilder_whenModifyWorkingDir_thenSuccess() throws IOException, InterruptedException { + List command = getDirectoryListingCommand(); + ProcessBuilder processBuilder = new ProcessBuilder(command); + + processBuilder.directory(new File("src")); + Process process = processBuilder.start(); + + List results = readOutput(process.getInputStream()); + assertThat("Results should not be empty", results, is(not(empty()))); + assertThat("Results should contain directory listing: ", results, hasItems(containsString("main"), containsString("test"))); + + int exitCode = process.waitFor(); + assertEquals("No errors should be detected", 0, exitCode); + } + + @Test + public void givenProcessBuilder_whenRedirectStandardOutput_thenSuccessWriting() throws IOException, InterruptedException { + ProcessBuilder processBuilder = new ProcessBuilder("java", "-version"); + + processBuilder.redirectErrorStream(true); + File log = tempFolder.newFile("java-version.log"); + processBuilder.redirectOutput(log); + + Process process = processBuilder.start(); + + assertEquals("If redirected, should be -1 ", -1, process.getInputStream() + .read()); + int exitCode = process.waitFor(); + assertEquals("No errors should be detected", 0, exitCode); + + List lines = Files.lines(log.toPath()) + .collect(Collectors.toList()); + + assertThat("Results should not be empty", lines, is(not(empty()))); + assertThat("Results should contain java version: ", lines, hasItem(containsString("java version"))); + } + + @Test + public void givenProcessBuilder_whenRedirectStandardOutput_thenSuccessAppending() throws IOException, InterruptedException { + ProcessBuilder processBuilder = new ProcessBuilder("java", "-version"); + + File log = tempFolder.newFile("java-version-append.log"); + processBuilder.redirectErrorStream(true); + processBuilder.redirectOutput(Redirect.appendTo(log)); + + Process process = processBuilder.start(); + + assertEquals("If redirected output, should be -1 ", -1, process.getInputStream() + .read()); + + int exitCode = process.waitFor(); + assertEquals("No errors should be detected", 0, exitCode); + + List lines = Files.lines(log.toPath()) + .collect(Collectors.toList()); + + assertThat("Results should not be empty", lines, is(not(empty()))); + assertThat("Results should contain java version: ", lines, hasItem(containsString("java version"))); + } + + @Test + public void givenProcessBuilder_whenStartingPipeline_thenSuccess() throws IOException, InterruptedException { + if (!isWindows()) { + List builders = Arrays.asList( + new ProcessBuilder("find", "src", "-name", "*.java", "-type", "f"), + new ProcessBuilder("wc", "-l")); + + List processes = ProcessBuilder.startPipeline(builders); + Process last = processes.get(processes.size() - 1); + + List output = readOutput(last.getInputStream()); + assertThat("Results should not be empty", output, is(not(empty()))); + } + } + + @Test + public void givenProcessBuilder_whenInheritIO_thenSuccess() throws IOException, InterruptedException { + List command = getEchoCommand(); + ProcessBuilder processBuilder = new ProcessBuilder(command); + + processBuilder.inheritIO(); + Process process = processBuilder.start(); + + int exitCode = process.waitFor(); + assertEquals("No errors should be detected", 0, exitCode); + } + + private List readOutput(InputStream inputStream) throws IOException { + try (BufferedReader output = new BufferedReader(new InputStreamReader(inputStream))) { + return output.lines() + .collect(Collectors.toList()); + } + } + + private List getDirectoryListingCommand() { + return isWindows() ? Arrays.asList("cmd.exe", "/c", "dir") : Arrays.asList("/bin/sh", "-c", "ls"); + } + + private List getGreetingCommand() { + return isWindows() ? Arrays.asList("cmd.exe", "/c", "echo %GREETING%") : Arrays.asList("/bin/bash", "-c", "echo $GREETING"); + } + + private List getEchoCommand() { + return isWindows() ? Arrays.asList("cmd.exe", "/c", "echo hello") : Arrays.asList("/bin/sh", "-c", "echo hello"); + } + + private boolean isWindows() { + return System.getProperty("os.name") + .toLowerCase() + .startsWith("windows"); + } + +} diff --git a/core-java-os/src/test/resources/.gitignore b/core-java-os/src/test/resources/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/core-java-os/src/test/resources/.gitignore @@ -0,0 +1,13 @@ +*.class + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/core-java-security/README.md b/core-java-security/README.md index d3343f79ca..9526b15be5 100644 --- a/core-java-security/README.md +++ b/core-java-security/README.md @@ -8,5 +8,5 @@ - [Encrypting and Decrypting Files in Java](http://www.baeldung.com/java-cipher-input-output-stream) - [Hashing a Password in Java](https://www.baeldung.com/java-password-hashing) - [SSL Handshake Failures](https://www.baeldung.com/java-ssl-handshake-failures) -- [SHA-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java) +- [SHA-256 and SHA3-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java) - [Enabling TLS v1.2 in Java 7](https://www.baeldung.com/java-7-tls-v12) diff --git a/core-java-sun/pom.xml b/core-java-sun/pom.xml index 6099e7a5ac..5f2065016f 100644 --- a/core-java-sun/pom.xml +++ b/core-java-sun/pom.xml @@ -261,8 +261,6 @@ - - 2.9.7 23.0 @@ -275,7 +273,6 @@ 4.01 0.4 1.8.7 - 1.16.12 4.6-b01 1.13 0.6.5 diff --git a/core-java/README.md b/core-java/README.md index d2fd903c10..cbc9251b0b 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -19,7 +19,6 @@ - [Introduction to Java Serialization](http://www.baeldung.com/java-serialization) - [Guide to UUID in Java](http://www.baeldung.com/java-uuid) - [Guide to Escaping Characters in Java RegExps](http://www.baeldung.com/java-regexp-escape-char) -- [Difference between URL and URI](http://www.baeldung.com/java-url-vs-uri) - [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin) - [Quick Guide to Java Stack](http://www.baeldung.com/java-stack) - [Compiling Java *.class Files with javac](http://www.baeldung.com/javac) @@ -30,7 +29,6 @@ - [What is the serialVersionUID?](http://www.baeldung.com/java-serial-version-uid) - [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle) - [Class Loaders in Java](http://www.baeldung.com/java-classloaders) -- [Double-Checked Locking with Singleton](http://www.baeldung.com/java-singleton-double-checked-locking) - [Guide to Java Clock Class](http://www.baeldung.com/java-clock) - [Importance of Main Manifest Attribute in a Self-Executing JAR](http://www.baeldung.com/java-jar-executable-manifest-main-class) - [Java Global Exception Handler](http://www.baeldung.com/java-global-exception-handler) @@ -51,3 +49,5 @@ - [Using Curl in Java](https://www.baeldung.com/java-curl) - [Finding Leap Years in Java](https://www.baeldung.com/java-leap-year) - [Java Bitwise Operators](https://www.baeldung.com/java-bitwise-operators) +- [Guide to Creating and Running a Jar File in Java](https://www.baeldung.com/java-create-jar) +- [Making a JSON POST Request With HttpURLConnection](https://www.baeldung.com/httpurlconnection-post) diff --git a/core-java/pom.xml b/core-java/pom.xml index d21c624997..463b65a4ce 100644 --- a/core-java/pom.xml +++ b/core-java/pom.xml @@ -451,7 +451,6 @@ - 2.9.7 2.8.2 @@ -461,7 +460,6 @@ 1.0.3 0.4 1.8.7 - 1.16.12 4.6-b01 1.13 0.6.5 diff --git a/core-java/src/main/java/com/baeldung/urlconnection/PostJSONWithHttpURLConnection.java b/core-java/src/main/java/com/baeldung/urlconnection/PostJSONWithHttpURLConnection.java new file mode 100644 index 0000000000..38b4a0411d --- /dev/null +++ b/core-java/src/main/java/com/baeldung/urlconnection/PostJSONWithHttpURLConnection.java @@ -0,0 +1,46 @@ +package com.baeldung.urlconnection; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +public class PostJSONWithHttpURLConnection { + + public static void main (String []args) throws IOException{ + //Change the URL with any other publicly accessible POST resource, which accepts JSON request body + URL url = new URL ("https://reqres.in/api/users"); + + HttpURLConnection con = (HttpURLConnection)url.openConnection(); + con.setRequestMethod("POST"); + + con.setRequestProperty("Content-Type", "application/json; utf-8"); + con.setRequestProperty("Accept", "application/json"); + + con.setDoOutput(true); + + //JSON String need to be constructed for the specific resource. + //We may construct complex JSON using any third-party JSON libraries such as jackson or org.json + String jsonInputString = "{\"name\": \"Upendra\", \"job\": \"Programmer\"}"; + + try(OutputStream os = con.getOutputStream()){ + byte[] input = jsonInputString.getBytes("utf-8"); + os.write(input, 0, input.length); + } + + int code = con.getResponseCode(); + System.out.println(code); + + try(BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8"))){ + StringBuilder response = new StringBuilder(); + String responseLine = null; + while ((responseLine = br.readLine()) != null) { + response.append(responseLine.trim()); + } + System.out.println(response.toString()); + } + } + +} diff --git a/core-kotlin-2/README.md b/core-kotlin-2/README.md index ff12555376..4ac1c2c7bb 100644 --- a/core-kotlin-2/README.md +++ b/core-kotlin-2/README.md @@ -1 +1,6 @@ ## Relevant articles: + +- [Void Type in Kotlin](https://www.baeldung.com/kotlin-void-type) +- [How to use Kotlin Range Expressions](https://www.baeldung.com/kotlin-ranges) +- [Split a List into Parts in Kotlin](https://www.baeldung.com/kotlin-split-list-into-parts) +- [String Comparison in Kotlin](https://www.baeldung.com/kotlin-string-comparison) diff --git a/core-kotlin-2/pom.xml b/core-kotlin-2/pom.xml index 81df3cee81..e329611593 100644 --- a/core-kotlin-2/pom.xml +++ b/core-kotlin-2/pom.xml @@ -13,4 +13,66 @@ ../parent-kotlin - + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + org.junit.platform + junit-platform-runner + ${junit.platform.version} + test + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + 1.8 + + + + + + + 1.2.71 + 1.1.1 + 5.2.0 + 3.10.0 + + + \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Annotations.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Annotations.kt new file mode 100644 index 0000000000..a8f83446dc --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Annotations.kt @@ -0,0 +1,7 @@ +package com.baeldung.annotations + +@Target(AnnotationTarget.FIELD) +annotation class Positive + +@Target(AnnotationTarget.FIELD) +annotation class AllowedNames(val names: Array) diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Item.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Item.kt new file mode 100644 index 0000000000..6864fe416e --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Item.kt @@ -0,0 +1,3 @@ +package com.baeldung.annotations + +class Item(@Positive val amount: Float, @AllowedNames(["Alice", "Bob"]) val name: String) \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Main.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Main.kt new file mode 100644 index 0000000000..2b7f2c5590 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Main.kt @@ -0,0 +1,7 @@ +package com.baeldung.annotations + +fun main(args: Array) { + val item = Item(amount = 1.0f, name = "Bob") + val validator = Validator() + println("Is instance valid? ${validator.isValid(item)}") +} diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Validator.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Validator.kt new file mode 100644 index 0000000000..40139048ab --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/annotations/Validator.kt @@ -0,0 +1,38 @@ +package com.baeldung.annotations + +/** + * Naive annotation-based validator. + * @author A.Shcherbakov + */ +class Validator() { + + /** + * Return true if every item's property annotated with @Positive is positive and if + * every item's property annotated with @AllowedNames has a value specified in that annotation. + */ + fun isValid(item: Item): Boolean { + val fields = item::class.java.declaredFields + for (field in fields) { + field.isAccessible = true + for (annotation in field.annotations) { + val value = field.get(item) + if (field.isAnnotationPresent(Positive::class.java)) { + val amount = value as Float + if (amount < 0) { + return false + } + } + if (field.isAnnotationPresent(AllowedNames::class.java)) { + val allowedNames = field.getAnnotation(AllowedNames::class.java)?.names + val name = value as String + allowedNames?.let { + if (!it.contains(name)) { + return false + } + } + } + } + } + return true + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/CharRange.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/CharRange.kt new file mode 100644 index 0000000000..3151674d61 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/CharRange.kt @@ -0,0 +1,13 @@ +package com.baeldung.range + +fun main(args: Array) { + + for (ch in 'a'..'f') { + print(ch) + } + println() + + for (ch in 'f' downTo 'a') { + print(ch) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/Color.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Color.kt new file mode 100644 index 0000000000..ef7adf06b5 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Color.kt @@ -0,0 +1,21 @@ +package com.baeldung.range + +enum class Color(val rgb: Int) { + BLUE(0x0000FF), + GREEN(0x008000), + RED(0xFF0000), + MAGENTA(0xFF00FF), + YELLOW(0xFFFF00); +} + +fun main(args: Array) { + + println(Color.values().toList()); + val red = Color.RED + val yellow = Color.YELLOW + val range = red..yellow + + println(range.contains(Color.MAGENTA)) + println(range.contains(Color.BLUE)) + println(range.contains(Color.GREEN)) +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/CustomColor.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/CustomColor.kt new file mode 100644 index 0000000000..b4fed13b18 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/CustomColor.kt @@ -0,0 +1,56 @@ +package com.baeldung.range + +import java.lang.IllegalStateException + +class CustomColor(val rgb: Int): Comparable { + + override fun compareTo(other: CustomColor): Int { + return this.rgb.compareTo(other.rgb) + } + + operator fun rangeTo(that: CustomColor) = ColorRange(this,that) + + operator fun inc(): CustomColor { + return CustomColor(rgb + 1) + } + + init { + if(rgb < 0x000000 || rgb > 0xFFFFFF){ + throw IllegalStateException("RGB must be between 0 and 16777215") + } + } + + override fun toString(): String { + return "CustomColor(rgb=$rgb)" + } +} +class ColorRange(override val start: CustomColor, + override val endInclusive: CustomColor) : ClosedRange, Iterable{ + + override fun iterator(): Iterator { + return ColorIterator(start, endInclusive) + } +} + +class ColorIterator(val start: CustomColor, val endInclusive: CustomColor) : Iterator { + + var initValue = start + + override fun hasNext(): Boolean { + return initValue <= endInclusive + } + + override fun next(): CustomColor { + return initValue++ + } +} + +fun main(args: Array) { + val a = CustomColor(0xABCDEF) + val b = CustomColor(-1) + val c = CustomColor(0xABCDFF) + + for(color in a..c){ + println(color) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/Filter.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Filter.kt new file mode 100644 index 0000000000..0e611b14cf --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Filter.kt @@ -0,0 +1,18 @@ +package com.baeldung.range + +fun main(args: Array) { + val r = 1..10 + + //Apply filter + val f = r.filter { it -> it % 2 == 0 } + println(f) + + //Map + val m = r.map { it -> it * it } + println(m) + + //Reduce + val rdc = r.reduce { a, b -> a + b } + println(rdc) + +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/FirstLast.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/FirstLast.kt new file mode 100644 index 0000000000..b82f5a8b9b --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/FirstLast.kt @@ -0,0 +1,8 @@ +package com.baeldung.range + +fun main(args: Array) { + + println((1..9).first) + println((1..9 step 2).step) + println((3..9).reversed().last) +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/OtherRangeFunctions.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/OtherRangeFunctions.kt new file mode 100644 index 0000000000..19dcab89b2 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/OtherRangeFunctions.kt @@ -0,0 +1,14 @@ +package com.baeldung.range + +fun main(args: Array) { + + val r = 1..20 + println(r.min()) + println(r.max()) + println(r.sum()) + println(r.average()) + println(r.count()) + + val repeated = listOf(1, 1, 2, 4, 4, 6, 10) + println(repeated.distinct()) +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/Range.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Range.kt new file mode 100644 index 0000000000..c313181599 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Range.kt @@ -0,0 +1,28 @@ +package com.baeldung.range + +fun main(args: Array) { + + for (i in 1..9) { + print(i) + } + println() + + for (i in 9 downTo 1) { + print(i) + } + println() + + for (i in 1.rangeTo(9)) { + print(i) + } + println() + + for (i in 9.downTo(1)) { + print(i) + } + println() + + for (i in 1 until 9) { + print(i) + } +} diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/ReverseRange.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/ReverseRange.kt new file mode 100644 index 0000000000..875cf62200 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/ReverseRange.kt @@ -0,0 +1,14 @@ +package com.baeldung.range + +fun main(args: Array) { + + (1..9).reversed().forEach { + print(it) + } + + println() + + (1..9).reversed().step(3).forEach { + print(it) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/Step.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Step.kt new file mode 100644 index 0000000000..b9c5d48588 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/Step.kt @@ -0,0 +1,15 @@ +package com.baeldung.range + +fun main(args: Array) { + + for(i in 1..9 step 2){ + print(i) + } + + println() + + for (i in 9 downTo 1 step 2){ + print(i) + } + +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/range/UntilRange.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/range/UntilRange.kt new file mode 100644 index 0000000000..2c116a286f --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/range/UntilRange.kt @@ -0,0 +1,8 @@ +package com.baeldung.range + +fun main(args: Array) { + + for (i in 1 until 9) { + print(i) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt b/core-kotlin-2/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt new file mode 100644 index 0000000000..37ad8c65e2 --- /dev/null +++ b/core-kotlin-2/src/main/kotlin/com/baeldung/scope/ScopeFunctions.kt @@ -0,0 +1,25 @@ +package com.baeldung.scope + +data class Student(var studentId: String = "", var name: String = "", var surname: String = "") { +} + +data class Teacher(var teacherId: Int = 0, var name: String = "", var surname: String = "") { + fun setId(anId: Int): Teacher = apply { teacherId = anId } + fun setName(aName: String): Teacher = apply { name = aName } + fun setSurname(aSurname: String): Teacher = apply { surname = aSurname } +} + +data class Headers(val headerInfo: String) + +data class Response(val headers: Headers) + +data class RestClient(val url: String) { + fun getResponse() = Response(Headers("some header info")) +} + +data class BankAccount(val id: Int) { + fun checkAuthorization(username: String) = Unit + fun addPayee(payee: String) = Unit + fun makePayment(paymentDetails: String) = Unit + +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/annotations/ValidationTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/annotations/ValidationTest.kt new file mode 100644 index 0000000000..5c2b6ef47f --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/annotations/ValidationTest.kt @@ -0,0 +1,41 @@ +package com.baeldung.annotations + +import org.junit.Test +import kotlin.test.assertTrue +import kotlin.test.assertFalse + +class ValidationTest { + + @Test + fun whenAmountIsOneAndNameIsAlice_thenTrue() { + assertTrue(Validator().isValid(Item(1f, "Alice"))) + } + + @Test + fun whenAmountIsOneAndNameIsBob_thenTrue() { + assertTrue(Validator().isValid(Item(1f, "Bob"))) + } + + + @Test + fun whenAmountIsMinusOneAndNameIsAlice_thenFalse() { + assertFalse(Validator().isValid(Item(-1f, "Alice"))) + } + + @Test + fun whenAmountIsMinusOneAndNameIsBob_thenFalse() { + assertFalse(Validator().isValid(Item(-1f, "Bob"))) + } + + @Test + fun whenAmountIsOneAndNameIsTom_thenFalse() { + assertFalse(Validator().isValid(Item(1f, "Tom"))) + } + + @Test + fun whenAmountIsMinusOneAndNameIsTom_thenFalse() { + assertFalse(Validator().isValid(Item(-1f, "Tom"))) + } + + +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/CharRangeTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/CharRangeTest.kt new file mode 100644 index 0000000000..0e23f508b6 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/CharRangeTest.kt @@ -0,0 +1,17 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class CharRangeTest { + + @Test + fun testCharRange() { + assertEquals(listOf('a', 'b', 'c'), ('a'..'c').toList()) + } + + @Test + fun testCharDownRange() { + assertEquals(listOf('c', 'b', 'a'), ('c'.downTo('a')).toList()) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/ColorTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/ColorTest.kt new file mode 100644 index 0000000000..4ac3270fcc --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/ColorTest.kt @@ -0,0 +1,20 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class ColorTest { + + @Test + fun testEnumRange() { + + println(Color.values().toList()); + val red = Color.RED + val yellow = Color.YELLOW + val range = red..yellow + + assertTrue { range.contains(Color.MAGENTA) } + assertFalse { range.contains(Color.BLUE) } + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/CustomColorTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/CustomColorTest.kt new file mode 100644 index 0000000000..8c8795ac42 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/CustomColorTest.kt @@ -0,0 +1,41 @@ +package com.baeldung.range + +import org.junit.Test +import java.lang.IllegalStateException +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue + +class CustomColorTest { + + @Test + fun testInvalidConstructor(){ + assertFailsWith(IllegalStateException::class){ + CustomColor(-1) + } + } + + @Test + fun assertHas10Colors(){ + assertTrue { + val a = CustomColor(1) + val b = CustomColor(10) + val range = a..b + for(cc in range){ + println(cc) + } + range.toList().size == 10 + } + } + + @Test + fun assertContains0xCCCCCC(){ + assertTrue { + val a = CustomColor(0xBBBBBB) + val b = CustomColor(0xDDDDDD) + val range = a..b + range.contains(CustomColor(0xCCCCCC)) + } + } + +} + diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/FilterTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/FilterTest.kt new file mode 100644 index 0000000000..d0e2df8860 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/FilterTest.kt @@ -0,0 +1,24 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class FilterTest { + + val r = 1..10 + + @Test + fun filterTest() { + assertEquals(listOf(2, 4, 6, 8, 10), r.filter { it -> it % 2 == 0 }.toList()) + } + + @Test + fun mapTest() { + assertEquals(listOf(1, 4, 9, 16, 25, 36, 49, 64, 81, 100), r.map { it -> it * it }.toList()) + } + + @Test + fun reduceTest() { + assertEquals(55, r.reduce { a, b -> a + b }) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/FirstLastTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/FirstLastTest.kt new file mode 100644 index 0000000000..ca797e9c9b --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/FirstLastTest.kt @@ -0,0 +1,22 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class FirstLastTest { + + @Test + fun testFirst() { + assertEquals(1, (1..9).first) + } + + @Test + fun testLast() { + assertEquals(9, (1..9).last) + } + + @Test + fun testStep() { + assertEquals(2, (1..9 step 2).step) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/OtherRangeFunctionsTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/OtherRangeFunctionsTest.kt new file mode 100644 index 0000000000..d2d36bbfae --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/OtherRangeFunctionsTest.kt @@ -0,0 +1,40 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class OtherRangeFunctionsTest { + + val r = 1..20 + val repeated = listOf(1, 1, 2, 4, 4, 6, 10) + + @Test + fun testMin() { + assertEquals(1, r.min()) + } + + @Test + fun testMax() { + assertEquals(20, r.max()) + } + + @Test + fun testSum() { + assertEquals(210, r.sum()) + } + + @Test + fun testAverage() { + assertEquals(10.5, r.average()) + } + + @Test + fun testCount() { + assertEquals(20, r.count()) + } + + @Test + fun testDistinct() { + assertEquals(listOf(1, 2, 4, 6, 10), repeated.distinct()) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/RangeTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/RangeTest.kt new file mode 100644 index 0000000000..48fa483924 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/RangeTest.kt @@ -0,0 +1,22 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class RangeTest { + + @Test + fun testRange() { + assertEquals(listOf(1,2,3), (1.rangeTo(3).toList())) + } + + @Test + fun testDownTo(){ + assertEquals(listOf(3,2,1), (3.downTo(1).toList())) + } + + @Test + fun testUntil(){ + assertEquals(listOf(1,2), (1.until(3).toList())) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/ReverseRangeTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/ReverseRangeTest.kt new file mode 100644 index 0000000000..7e1c7badb7 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/ReverseRangeTest.kt @@ -0,0 +1,12 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class ReverseRangeTest { + + @Test + fun reversedTest() { + assertEquals(listOf(9, 6, 3), (1..9).reversed().step(3).toList()) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/StepTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/StepTest.kt new file mode 100644 index 0000000000..4570ceeb0a --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/StepTest.kt @@ -0,0 +1,17 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class StepTest { + + @Test + fun testStep() { + assertEquals(listOf(1, 3, 5, 7, 9), (1..9 step 2).toList()) + } + + @Test + fun testStepDown() { + assertEquals(listOf(9, 7, 5, 3, 1), (9 downTo 1 step 2).toList()) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/range/UntilRangeTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/range/UntilRangeTest.kt new file mode 100644 index 0000000000..f941c7f1e6 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/range/UntilRangeTest.kt @@ -0,0 +1,12 @@ +package com.baeldung.range + +import org.junit.Test +import kotlin.test.assertEquals + +class UntilRangeTest { + + @Test + fun testUntil() { + assertEquals(listOf(1, 2, 3, 4), (1 until 5).toList()) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt new file mode 100644 index 0000000000..cb3ed98006 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/scope/ScopeFunctionsUnitTest.kt @@ -0,0 +1,143 @@ +package com.baeldung.scope + +import org.junit.Test +import kotlin.test.assertTrue + + +class ScopeFunctionsUnitTest { + + class Logger { + + var called : Boolean = false + + fun info(message: String) { + called = true + } + + fun wasCalled() = called + } + + @Test + fun shouldTransformWhenLetFunctionUsed() { + val stringBuider = StringBuilder() + val numberOfCharacters = stringBuider.let { + it.append("This is a transformation function.") + it.append("It takes a StringBuilder instance and returns the number of characters in the generated String") + it.length + } + + assertTrue { + numberOfCharacters == 128 + } + } + + @Test + fun shouldHandleNullabilityWhenLetFunctionUsed() { + + val message: String? = "hello there!" + val charactersInMessage = message?.let { + "At this point is safe to reference the variable. Let's print the message: $it" + } ?: "default value" + + assertTrue { + charactersInMessage.equals("At this point is safe to reference the variable. Let's print the message: hello there!") + } + + val aNullMessage = null + val thisIsNull = aNullMessage?.let { + "At this point it would be safe to reference the variable. But it will not really happen because it is null. Let's reference: $it" + } ?: "default value" + + assertTrue { + thisIsNull.equals("default value") + } + } + + @Test + fun shouldInitializeObjectWhenUsingApply() { + val aStudent = Student().apply { + studentId = "1234567" + name = "Mary" + surname = "Smith" + } + + assertTrue { + aStudent.name.equals("Mary") + } + } + + @Test + fun shouldAllowBuilderStyleObjectDesignWhenApplyUsedInClassMethods() { + val teacher = Teacher() + .setId(1000) + .setName("Martha") + .setSurname("Spector") + + assertTrue { + teacher.surname.equals("Spector") + } + } + + @Test + fun shouldAllowSideEffectWhenUsingAlso() { + val restClient = RestClient("http://www.someurl.com") + + val logger = Logger() + + val headers = restClient + .getResponse() + .also { logger.info(it.toString()) } + .headers + + assertTrue { + logger.wasCalled() && headers.headerInfo.equals("some header info") + } + + } + + @Test + fun shouldInitializeFieldWhenAlsoUsed() { + val aStudent = Student().also { it.name = "John"} + + assertTrue { + aStudent.name.equals("John") + } + } + + @Test + fun shouldLogicallyGroupObjectCallsWhenUsingWith() { + val bankAccount = BankAccount(1000) + with (bankAccount) { + checkAuthorization("someone") + addPayee("some payee") + makePayment("payment information") + } + } + + @Test + fun shouldConvertObjectWhenRunUsed() { + val stringBuider = StringBuilder() + val numberOfCharacters = stringBuider.run { + append("This is a transformation function.") + append("It takes a StringBuilder instance and returns the number of characters in the generated String") + length + } + + assertTrue { + numberOfCharacters == 128 + } + } + + @Test + fun shouldHandleNullabilityWhenRunIsUsed() { + val message: String? = "hello there!" + val charactersInMessage = message?.run { + "At this point is safe to reference the variable. Let's print the message: $this" + } ?: "default value" + + assertTrue { + charactersInMessage.equals("At this point is safe to reference the variable. Let's print the message: hello there!") + } + } + +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/com/baeldung/splitting/SplittingTest.kt b/core-kotlin-2/src/test/kotlin/com/baeldung/splitting/SplittingTest.kt new file mode 100644 index 0000000000..a9ddc99992 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/com/baeldung/splitting/SplittingTest.kt @@ -0,0 +1,99 @@ +package com.baeldung.lambda + +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class SplittingTest { + private val evenList = listOf(0, "a", 1, "b", 2, "c"); + + private val unevenList = listOf(0, "a", 1, "b", 2, "c", 3); + + private fun verifyList(resultList: List>) { + assertEquals("[[0, a], [1, b], [2, c]]", resultList.toString()) + } + + private fun verifyPartialList(resultList: List>) { + assertEquals("[[0, a], [1, b], [2, c], [3]]", resultList.toString()) + } + + @Test + fun whenChunked_thenListIsSplit() { + val resultList = evenList.chunked(2) + verifyList(resultList) + } + + @Test + fun whenUnevenChunked_thenListIsSplit() { + val resultList = unevenList.chunked(2) + verifyPartialList(resultList) + } + + @Test + fun whenWindowed_thenListIsSplit() { + val resultList = evenList.windowed(2, 2) + verifyList(resultList) + } + + @Test + fun whenUnevenPartialWindowed_thenListIsSplit() { + val resultList = unevenList.windowed(2, 2, partialWindows = true) + verifyPartialList(resultList) + } + + @Test + fun whenUnevenWindowed_thenListIsSplit() { + val resultList = unevenList.windowed(2, 2, partialWindows = false) + verifyList(resultList) + } + + @Test + fun whenGroupByWithAscendingNumbers_thenListIsSplit() { + val numberList = listOf(1, 2, 3, 4, 5, 6); + val resultList = numberList.groupBy { (it + 1) / 2 } + assertEquals("[[1, 2], [3, 4], [5, 6]]", resultList.values.toString()) + assertEquals("[1, 2, 3]", resultList.keys.toString()) + } + + @Test + fun whenGroupByWithAscendingNumbersUneven_thenListIsSplit() { + val numberList = listOf(1, 2, 3, 4, 5, 6, 7); + val resultList = numberList.groupBy { (it + 1) / 2 }.values + assertEquals("[[1, 2], [3, 4], [5, 6], [7]]", resultList.toString()) + } + + @Test + fun whenGroupByWithRandomNumbers_thenListIsSplitInWrongWay() { + val numberList = listOf(1, 3, 8, 20, 23, 30); + val resultList = numberList.groupBy { (it + 1) / 2 } + assertEquals("[[1], [3], [8], [20], [23], [30]]", resultList.values.toString()) + assertEquals("[1, 2, 4, 10, 12, 15]", resultList.keys.toString()) + } + + @Test + fun whenWithIndexGroupBy_thenListIsSplit() { + val resultList = evenList.withIndex() + .groupBy { it.index / 2 } + .map { it.value.map { it.value } } + verifyList(resultList) + } + + @Test + fun whenWithIndexGroupByUneven_thenListIsSplit() { + val resultList = unevenList.withIndex() + .groupBy { it.index / 2 } + .map { it.value.map { it.value } } + verifyPartialList(resultList) + } + + @Test + fun whenFoldIndexed_thenListIsSplit() { + val resultList = evenList.foldIndexed(ArrayList>(evenList.size / 2)) { index, acc, item -> + if (index % 2 == 0) { + acc.add(ArrayList(2)) + } + acc.last().add(item) + acc + } + verifyList(resultList) + } +} \ No newline at end of file diff --git a/core-kotlin-2/src/test/kotlin/stringcomparison/StringComparisonTest.kt b/core-kotlin-2/src/test/kotlin/stringcomparison/StringComparisonTest.kt new file mode 100644 index 0000000000..45a8dd7e04 --- /dev/null +++ b/core-kotlin-2/src/test/kotlin/stringcomparison/StringComparisonTest.kt @@ -0,0 +1,47 @@ +package stringcomparison + +import org.junit.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class StringComparisonUnitTest { + + @Test + fun `compare using equals operator`() { + val first = "kotlin" + val second = "kotlin" + val firstCapitalized = "KOTLIN" + assertTrue { first == second } + assertFalse { first == firstCapitalized } + } + + @Test + fun `compare using referential equals operator`() { + val first = "kotlin" + val second = "kotlin" + val copyOfFirst = buildString { "kotlin" } + assertTrue { first === second } + assertFalse { first === copyOfFirst } + } + + @Test + fun `compare using equals method`() { + val first = "kotlin" + val second = "kotlin" + val firstCapitalized = "KOTLIN" + assertTrue { first.equals(second) } + assertFalse { first.equals(firstCapitalized) } + assertTrue { first.equals(firstCapitalized, true) } + } + + @Test + fun `compare using compare method`() { + val first = "kotlin" + val second = "kotlin" + val firstCapitalized = "KOTLIN" + assertTrue { first.compareTo(second) == 0 } + assertTrue { first.compareTo(firstCapitalized) == 32 } + assertTrue { firstCapitalized.compareTo(first) == -32 } + assertTrue { first.compareTo(firstCapitalized, true) == 0 } + } +} \ No newline at end of file diff --git a/core-kotlin/README.md b/core-kotlin/README.md index 6ee79b2a2e..73a78eccff 100644 --- a/core-kotlin/README.md +++ b/core-kotlin/README.md @@ -4,7 +4,7 @@ - [A guide to the “when{}” block in Kotlin](http://www.baeldung.com/kotlin-when) - [Comprehensive Guide to Null Safety in Kotlin](http://www.baeldung.com/kotlin-null-safety) - [Kotlin Java Interoperability](http://www.baeldung.com/kotlin-java-interoperability) -- [Difference Between “==” and “===” in Kotlin](http://www.baeldung.com/kotlin-equality-operators) +- [Difference Between “==” and “===” operators in Kotlin](http://www.baeldung.com/kotlin-equality-operators) - [Generics in Kotlin](http://www.baeldung.com/kotlin-generics) - [Introduction to Kotlin Coroutines](http://www.baeldung.com/kotlin-coroutines) - [Destructuring Declarations in Kotlin](http://www.baeldung.com/kotlin-destructuring-declarations) @@ -52,3 +52,7 @@ - [Inline Classes in Kotlin](https://www.baeldung.com/kotlin-inline-classes) - [Creating Java static final Equivalents in Kotlin](https://www.baeldung.com/kotlin-java-static-final) - [Nested forEach in Kotlin](https://www.baeldung.com/kotlin-nested-foreach) +- [Building DSLs in Kotlin](https://www.baeldung.com/kotlin-dsl) +- [Static Methods Behavior in Kotlin](https://www.baeldung.com/kotlin-static-methods) +- [Inline Functions in Kotlin](https://www.baeldung.com/kotlin-inline-functions) +- [Delegation Pattern in Kotlin](https://www.baeldung.com/kotlin-delegation-pattern) diff --git a/core-kotlin/src/main/kotlin/com/baeldung/forEach/forEach.kt b/core-kotlin/src/main/kotlin/com/baeldung/forEach/forEach.kt index ef56009c71..20eda4e64f 100644 --- a/core-kotlin/src/main/kotlin/com/baeldung/forEach/forEach.kt +++ b/core-kotlin/src/main/kotlin/com/baeldung/forEach/forEach.kt @@ -5,6 +5,15 @@ class Country(val name : String, val cities : List) class City(val name : String, val streets : List) +fun City.getStreetsWithCityName() : List { + return streets.map { "$name, $it" }.toList() +} + +fun Country.getCitiesWithCountryName() : List { + return cities.flatMap { it.getStreetsWithCityName() } + .map { "$name, $it" } +} + class World { private val streetsOfAmsterdam = listOf("Herengracht", "Prinsengracht") @@ -45,6 +54,19 @@ class World { } } } + + fun allStreetsFlatMap() { + + countries.flatMap { it.cities} + .flatMap { it.streets} + .forEach { println(it) } + } + + fun allFlatMapTable() { + + countries.flatMap { it.getCitiesWithCountryName() } + .forEach { println(it) } + } } fun main(args : Array) { @@ -56,6 +78,10 @@ fun main(args : Array) { world.allNested() world.allTable() + + world.allStreetsFlatMap() + + world.allFlatMapTable() } diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegation.kt b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegation.kt new file mode 100644 index 0000000000..8e261aacf2 --- /dev/null +++ b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegation.kt @@ -0,0 +1,64 @@ +package com.baeldung.kotlin.delegates + +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock + +interface Producer { + + fun produce(): String +} + +class ProducerImpl : Producer { + + override fun produce() = "ProducerImpl" +} + +class EnhancedProducer(private val delegate: Producer) : Producer by delegate { + + override fun produce() = "${delegate.produce()} and EnhancedProducer" +} + +interface MessageService { + + fun processMessage(message: String): String +} + +class MessageServiceImpl : MessageService { + override fun processMessage(message: String): String { + return "MessageServiceImpl: $message" + } +} + +interface UserService { + + fun processUser(userId: String): String +} + +class UserServiceImpl : UserService { + + override fun processUser(userId: String): String { + return "UserServiceImpl: $userId" + } +} + +class CompositeService : UserService by UserServiceImpl(), MessageService by MessageServiceImpl() + +interface Service { + + val seed: Int + + fun serve(action: (Int) -> Unit) +} + +class ServiceImpl : Service { + + override val seed = 1 + + override fun serve(action: (Int) -> Unit) { + action(seed) + } +} + +class ServiceDecorator : Service by ServiceImpl() { + override val seed = 2 +} \ No newline at end of file diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kotlin/dsl/SqlDsl.kt b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/dsl/SqlDsl.kt new file mode 100644 index 0000000000..5296d301a3 --- /dev/null +++ b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/dsl/SqlDsl.kt @@ -0,0 +1,114 @@ +package com.baeldung.kotlin.dsl + +abstract class Condition { + + fun and(initializer: Condition.() -> Unit) { + addCondition(And().apply(initializer)) + } + + fun or(initializer: Condition.() -> Unit) { + addCondition(Or().apply(initializer)) + } + + infix fun String.eq(value: Any?) { + addCondition(Eq(this, value)) + } + + protected abstract fun addCondition(condition: Condition) +} + +open class CompositeCondition(private val sqlOperator: String) : Condition() { + private val conditions = mutableListOf() + + override fun addCondition(condition: Condition) { + conditions += condition + } + + override fun toString(): String { + return if (conditions.size == 1) { + conditions.first().toString() + } else { + conditions.joinToString(prefix = "(", postfix = ")", separator = " $sqlOperator ") { + "$it" + } + } + } +} + +class And : CompositeCondition("and") + +class Or : CompositeCondition("or") + +class Eq(private val column: String, private val value: Any?) : Condition() { + + init { + if (value != null && value !is Number && value !is String) { + throw IllegalArgumentException("Only , numbers and strings values can be used in the 'where' clause") + } + } + + override fun addCondition(condition: Condition) { + throw IllegalStateException("Can't add a nested condition to the sql 'eq'") + } + + override fun toString(): String { + return when (value) { + null -> "$column is null" + is String -> "$column = '$value'" + else -> "$column = $value" + } + } +} + +class SqlSelectBuilder { + + private val columns = mutableListOf() + private lateinit var table: String + private var condition: Condition? = null + + fun select(vararg columns: String) { + if (columns.isEmpty()) { + throw IllegalArgumentException("At least one column should be defined") + } + if (this.columns.isNotEmpty()) { + throw IllegalStateException("Detected an attempt to re-define columns to fetch. Current columns list: " + + "${this.columns}, new columns list: $columns") + } + this.columns.addAll(columns) + } + + fun from(table: String) { + this.table = table + } + + fun where(initializer: Condition.() -> Unit) { + condition = And().apply(initializer) + } + + fun build(): String { + if (!::table.isInitialized) { + throw IllegalStateException("Failed to build an sql select - target table is undefined") + } + return toString() + } + + override fun toString(): String { + val columnsToFetch = + if (columns.isEmpty()) { + "*" + } else { + columns.joinToString(", ") + } + val conditionString = + if (condition == null) { + "" + } else { + " where $condition" + } + return "select $columnsToFetch from $table$conditionString" + } +} + +fun query(initializer: SqlSelectBuilder.() -> Unit): SqlSelectBuilder { + return SqlSelectBuilder().apply(initializer) +} \ No newline at end of file diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegationTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegationTest.kt new file mode 100644 index 0000000000..e65032acd4 --- /dev/null +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/delegates/InterfaceDelegationTest.kt @@ -0,0 +1,28 @@ +package com.baeldung.kotlin.delegates + +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class InterfaceDelegationTest { + + @Test + fun `when delegated implementation is used then it works as expected`() { + val producer = EnhancedProducer(ProducerImpl()) + assertThat(producer.produce()).isEqualTo("ProducerImpl and EnhancedProducer") + } + + @Test + fun `when composite delegation is used then it works as expected`() { + val service = CompositeService() + assertThat(service.processMessage("message")).isEqualTo("MessageServiceImpl: message") + assertThat(service.processUser("user")).isEqualTo("UserServiceImpl: user") + } + + @Test + fun `when decoration is used then delegate knows nothing about it`() { + val service = ServiceDecorator() + service.serve { + assertThat(it).isEqualTo(1) + } + } +} \ No newline at end of file diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/dsl/SqlDslTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/dsl/SqlDslTest.kt new file mode 100644 index 0000000000..55ae44e4dc --- /dev/null +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/dsl/SqlDslTest.kt @@ -0,0 +1,74 @@ +package com.baeldung.kotlin.dsl + +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import java.lang.Exception + +class SqlDslTest { + + @Test + fun `when no columns are specified then star is used`() { + doTest("select * from table1") { + from ("table1") + } + } + + @Test + fun `when no condition is specified then correct query is built`() { + doTest("select column1, column2 from table1") { + select("column1", "column2") + from ("table1") + } + } + + @Test(expected = Exception::class) + fun `when no table is specified then an exception is thrown`() { + query { + select("column1") + }.build() + } + + @Test + fun `when a list of conditions is specified then it's respected`() { + doTest("select * from table1 where (column3 = 4 and column4 is null)") { + from ("table1") + where { + "column3" eq 4 + "column4" eq null + } + } + } + + @Test + fun `when 'or' conditions are specified then they are respected`() { + doTest("select * from table1 where (column3 = 4 or column4 is null)") { + from ("table1") + where { + or { + "column3" eq 4 + "column4" eq null + } + } + } + } + + @Test + fun `when either 'and' or 'or' conditions are specified then they are respected`() { + doTest("select * from table1 where ((column3 = 4 or column4 is null) and column5 = 42)") { + from ("table1") + where { + and { + or { + "column3" eq 4 + "column4" eq null + } + "column5" eq 42 + } + } + } + } + + private fun doTest(expected: String, sql: SqlSelectBuilder.() -> Unit) { + assertThat(query(sql).build()).isEqualTo(expected) + } +} \ No newline at end of file diff --git a/couchbase/pom.xml b/couchbase/pom.xml index 994b80e7cd..31e6a53388 100644 --- a/couchbase/pom.xml +++ b/couchbase/pom.xml @@ -25,7 +25,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson-version} + ${jackson.version} @@ -70,7 +70,6 @@ 2.5.0 4.3.5.RELEASE 3.5 - 2.9.7 diff --git a/ddd/pom.xml b/ddd/pom.xml index 749e444e52..4ac65ea841 100644 --- a/ddd/pom.xml +++ b/ddd/pom.xml @@ -9,10 +9,10 @@ DDD series examples - org.springframework.boot - spring-boot-starter-parent - 2.0.6.RELEASE - + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 @@ -86,6 +86,7 @@ 1.0.1 2.22.0 + 2.0.6.RELEASE \ No newline at end of file diff --git a/ddd/src/test/java/com/baeldung/ddd/order/OrderTest.java b/ddd/src/test/java/com/baeldung/ddd/order/OrderUnitTest.java similarity index 99% rename from ddd/src/test/java/com/baeldung/ddd/order/OrderTest.java rename to ddd/src/test/java/com/baeldung/ddd/order/OrderUnitTest.java index 431a6a5293..502827960a 100644 --- a/ddd/src/test/java/com/baeldung/ddd/order/OrderTest.java +++ b/ddd/src/test/java/com/baeldung/ddd/order/OrderUnitTest.java @@ -11,7 +11,7 @@ import org.joda.money.Money; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class OrderTest { +class OrderUnitTest { @DisplayName("given order with two items, when calculate total cost, then sum is returned") @Test void test0() throws Exception { diff --git a/ddd/src/test/java/com/baeldung/ddd/order/jpa/ViolateOrderBusinessRulesTest.java b/ddd/src/test/java/com/baeldung/ddd/order/jpa/ViolateOrderBusinessRulesUnitTest.java similarity index 96% rename from ddd/src/test/java/com/baeldung/ddd/order/jpa/ViolateOrderBusinessRulesTest.java rename to ddd/src/test/java/com/baeldung/ddd/order/jpa/ViolateOrderBusinessRulesUnitTest.java index 3eda9250f9..6f1de3276c 100644 --- a/ddd/src/test/java/com/baeldung/ddd/order/jpa/ViolateOrderBusinessRulesTest.java +++ b/ddd/src/test/java/com/baeldung/ddd/order/jpa/ViolateOrderBusinessRulesUnitTest.java @@ -7,7 +7,7 @@ import java.math.BigDecimal; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -public class ViolateOrderBusinessRulesTest { +public class ViolateOrderBusinessRulesUnitTest { @DisplayName("given two non-zero order line items, when create an order with them, it's possible to set total cost to zero") @Test void test() throws Exception { diff --git a/ethereum/pom.xml b/ethereum/pom.xml index c7f82eaf22..baa74b58a5 100644 --- a/ethereum/pom.xml +++ b/ethereum/pom.xml @@ -208,15 +208,12 @@ UTF-8 - 1.8 8.5.4 1.5.0-RELEASE 3.3.1 1.5.6.RELEASE 2.21.0 - 2.9.7 1.3 - 2.9.7 2.3.1 3.1.0 2.4.0 diff --git a/feign/pom.xml b/feign/pom.xml index ea645383c1..d2fa334270 100644 --- a/feign/pom.xml +++ b/feign/pom.xml @@ -56,7 +56,6 @@ 9.4.0 - 1.16.12 1.4.2.RELEASE diff --git a/geotools/pom.xml b/geotools/pom.xml index f2a9a77d2a..17beded326 100644 --- a/geotools/pom.xml +++ b/geotools/pom.xml @@ -33,24 +33,11 @@ - - maven2-repository.dev.java.net - Java.net repository - http://download.java.net/maven/2 - osgeo Open Source Geospatial Foundation Repository http://download.osgeo.org/webdav/geotools/ - - - true - - opengeo - OpenGeo Maven Repository - http://repo.opengeo.org - diff --git a/google-web-toolkit/README.md b/google-web-toolkit/README.md index 65264375bc..3526fe9962 100644 --- a/google-web-toolkit/README.md +++ b/google-web-toolkit/README.md @@ -1,3 +1,2 @@ ### Relevant Articles: - [Introduction to GWT](http://www.baeldung.com/gwt) -- [Quick Use of FilenameFilter](http://www.baeldung.com/java-filename-filter) diff --git a/gradle/README.md b/gradle/README.md index a1f5c74c57..14e460f225 100644 --- a/gradle/README.md +++ b/gradle/README.md @@ -3,5 +3,4 @@ - [Writing Custom Gradle Plugins](http://www.baeldung.com/gradle-create-plugin) - [Creating a Fat Jar in Gradle](http://www.baeldung.com/gradle-fat-jar) - [A Custom Task in Gradle](http://www.baeldung.com/gradle-custom-task) -- [Kotlin Dependency Injection with Kodein](http://www.baeldung.com/kotlin-kodein-dependency-injection) - [Using JUnit 5 with Gradle](https://www.baeldung.com/junit-5-gradle) diff --git a/gson/README.md b/gson/README.md index 4edd7158d4..fec0506488 100644 --- a/gson/README.md +++ b/gson/README.md @@ -10,3 +10,7 @@ - [Save Data to a JSON File with Gson](https://www.baeldung.com/gson-save-file) - [Convert JSON to a Map Using Gson](https://www.baeldung.com/gson-json-to-map) - [Working with Primitive Values in Gson](https://www.baeldung.com/java-gson-primitives) +- [Convert String to JsonObject with Gson](https://www.baeldung.com/gson-string-to-jsonobject) +- [Mapping Multiple JSON Fields to One Java Field](https://www.baeldung.com/json-multiple-fields-single-java-field) +- [Serializing and Deserializing a List with Gson](https://www.baeldung.com/gson-list) + diff --git a/gson/src/main/java/org/baeldung/gson/entities/Animal.java b/gson/src/main/java/org/baeldung/gson/entities/Animal.java new file mode 100644 index 0000000000..2eec5f8704 --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/entities/Animal.java @@ -0,0 +1,5 @@ +package org.baeldung.gson.entities; + +public abstract class Animal { + public String type = "Animal"; +} diff --git a/gson/src/main/java/org/baeldung/gson/entities/Cow.java b/gson/src/main/java/org/baeldung/gson/entities/Cow.java new file mode 100644 index 0000000000..020bcd5860 --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/entities/Cow.java @@ -0,0 +1,19 @@ +package org.baeldung.gson.entities; + +public class Cow extends Animal { + private String breed; + + public Cow() { + breed = "Jersey"; + type = "Cow"; + } + + public String getBreed() { + return breed; + } + + public void setBreed(String breed) { + this.breed = breed; + } +} + diff --git a/gson/src/main/java/org/baeldung/gson/entities/Dog.java b/gson/src/main/java/org/baeldung/gson/entities/Dog.java new file mode 100644 index 0000000000..042d73adcf --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/entities/Dog.java @@ -0,0 +1,18 @@ +package org.baeldung.gson.entities; + +public class Dog extends Animal { + private String petName; + + public Dog() { + petName = "Milo"; + type = "Dog"; + } + + public String getPetName() { + return petName; + } + + public void setPetName(String petName) { + this.petName = petName; + } +} diff --git a/gson/src/main/java/org/baeldung/gson/entities/MyClass.java b/gson/src/main/java/org/baeldung/gson/entities/MyClass.java new file mode 100644 index 0000000000..4e717e72c3 --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/entities/MyClass.java @@ -0,0 +1,49 @@ +package org.baeldung.gson.entities; + +import java.util.Objects; + +public class MyClass { + private int id; + private String name; + + public MyClass(int id, String name) { + this.id = id; + this.name = name; + } + + public MyClass() { } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MyClass myClass = (MyClass) o; + return id == myClass.id && Objects.equals(name, myClass.name); + } + + @Override + public int hashCode() { + + return Objects.hash(id, name); + } +} diff --git a/gson/src/main/java/org/baeldung/gson/entities/Weather.java b/gson/src/main/java/org/baeldung/gson/entities/Weather.java new file mode 100644 index 0000000000..383e9ef41c --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/entities/Weather.java @@ -0,0 +1,40 @@ +package org.baeldung.gson.entities; + +import com.google.gson.annotations.SerializedName; + +public class Weather { + + @SerializedName(value = "location", alternate = "place") + private String location; + + @SerializedName(value = "temp", alternate = "temperature") + private int temp; + + @SerializedName(value = "outlook", alternate = "weather") + private String outlook; + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public int getTemp() { + return temp; + } + + public void setTemp(int temp) { + this.temp = temp; + } + + public String getOutlook() { + return outlook; + } + + public void setOutlook(String outlook) { + this.outlook = outlook; + } + +} diff --git a/gson/src/main/java/org/baeldung/gson/serialization/AnimalDeserializer.java b/gson/src/main/java/org/baeldung/gson/serialization/AnimalDeserializer.java new file mode 100644 index 0000000000..9dcef0e10b --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/serialization/AnimalDeserializer.java @@ -0,0 +1,35 @@ +package org.baeldung.gson.serialization; + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import org.baeldung.gson.entities.Animal; + +public class AnimalDeserializer implements JsonDeserializer { + private String animalTypeElementName; + private Gson gson; + private Map> animalTypeRegistry; + + public AnimalDeserializer(String animalTypeElementName) { + this.animalTypeElementName = animalTypeElementName; + this.gson = new Gson(); + this.animalTypeRegistry = new HashMap<>(); + } + + public void registerBarnType(String animalTypeName, Class animalType) { + animalTypeRegistry.put(animalTypeName, animalType); + } + + public Animal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { + JsonObject animalObject = json.getAsJsonObject(); + JsonElement animalTypeElement = animalObject.get(animalTypeElementName); + + Class animalType = animalTypeRegistry.get(animalTypeElement.getAsString()); + return gson.fromJson(animalObject, animalType); + } +} \ No newline at end of file diff --git a/gson/src/test/java/org/baeldung/gson/advance/GsonAdvanceUnitTest.java b/gson/src/test/java/org/baeldung/gson/advance/GsonAdvanceUnitTest.java new file mode 100644 index 0000000000..5b787f1956 --- /dev/null +++ b/gson/src/test/java/org/baeldung/gson/advance/GsonAdvanceUnitTest.java @@ -0,0 +1,117 @@ +package org.baeldung.gson.advance; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.baeldung.gson.entities.Animal; +import org.baeldung.gson.entities.Cow; +import org.baeldung.gson.entities.Dog; +import org.baeldung.gson.entities.MyClass; +import org.baeldung.gson.serialization.AnimalDeserializer; +import org.junit.Test; + +public class GsonAdvanceUnitTest { + + @Test + public void givenListOfMyClass_whenSerializing_thenCorrect() { + List list = Arrays.asList(new MyClass(1, "name1"), new MyClass(2, "name2")); + + Gson gson = new Gson(); + String jsonString = gson.toJson(list); + String expectedString = "[{\"id\":1,\"name\":\"name1\"},{\"id\":2,\"name\":\"name2\"}]"; + + assertEquals(expectedString, jsonString); + } + + @Test(expected = ClassCastException.class) + public void givenJsonString_whenIncorrectDeserializing_thenThrowClassCastException() { + String inputString = "[{\"id\":1,\"name\":\"name1\"},{\"id\":2,\"name\":\"name2\"}]"; + + Gson gson = new Gson(); + List outputList = gson.fromJson(inputString, ArrayList.class); + + assertEquals(1, outputList.get(0).getId()); + } + + @Test + public void givenJsonString_whenDeserializing_thenReturnListOfMyClass() { + String inputString = "[{\"id\":1,\"name\":\"name1\"},{\"id\":2,\"name\":\"name2\"}]"; + List inputList = Arrays.asList(new MyClass(1, "name1"), new MyClass(2, "name2")); + + Type listOfMyClassObject = new TypeToken>() {}.getType(); + + Gson gson = new Gson(); + List outputList = gson.fromJson(inputString, listOfMyClassObject); + + assertEquals(inputList, outputList); + } + + @Test + public void givenPolymorphicList_whenSerializeWithTypeAdapter_thenCorrect() { + String expectedString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]"; + + List inList = new ArrayList<>(); + inList.add(new Dog()); + inList.add(new Cow()); + + String jsonString = new Gson().toJson(inList); + + assertEquals(expectedString, jsonString); + } + + @Test + public void givenPolymorphicList_whenDeserializeWithTypeAdapter_thenCorrect() { + String inputString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]"; + + AnimalDeserializer deserializer = new AnimalDeserializer("type"); + deserializer.registerBarnType("Dog", Dog.class); + deserializer.registerBarnType("Cow", Cow.class); + Gson gson = new GsonBuilder() + .registerTypeAdapter(Animal.class, deserializer) + .create(); + + List outList = gson.fromJson(inputString, new TypeToken>(){}.getType()); + + assertEquals(2, outList.size()); + assertTrue(outList.get(0) instanceof Dog); + assertTrue(outList.get(1) instanceof Cow); + } + + @Test + public void givenPolymorphicList_whenSerializeWithRuntimeTypeAdapter_thenCorrect() { + String expectedString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]"; + + List inList = new ArrayList<>(); + inList.add(new Dog()); + inList.add(new Cow()); + String jsonString = new Gson().toJson(inList); + + assertEquals(expectedString, jsonString); + } + + @Test + public void givenPolymorphicList_whenDeserializeWithRuntimeTypeAdapter_thenCorrect() { + String inputString = "[{\"petName\":\"Milo\",\"type\":\"Dog\"},{\"breed\":\"Jersey\",\"type\":\"Cow\"}]"; + + Type listOfAnimals = new TypeToken>() {}.getType(); + + RuntimeTypeAdapterFactory adapter = RuntimeTypeAdapterFactory.of(Animal.class, "type") + .registerSubtype(Dog.class) + .registerSubtype(Cow.class); + + Gson gson = new GsonBuilder().registerTypeAdapterFactory(adapter).create(); + + List outList = gson.fromJson(inputString, listOfAnimals); + + assertEquals(2, outList.size()); + assertTrue(outList.get(0) instanceof Dog); + assertTrue(outList.get(1) instanceof Cow); + } +} \ No newline at end of file diff --git a/gson/src/test/java/org/baeldung/gson/advance/RuntimeTypeAdapterFactory.java b/gson/src/test/java/org/baeldung/gson/advance/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000000..739dd889c7 --- /dev/null +++ b/gson/src/test/java/org/baeldung/gson/advance/RuntimeTypeAdapterFactory.java @@ -0,0 +1,265 @@ +package org.baeldung.gson.advance; + +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   {@code
+ *   abstract class Shape {
+ *     int x;
+ *     int y;
+ *   }
+ *   class Circle extends Shape {
+ *     int radius;
+ *   }
+ *   class Rectangle extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Diamond extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Drawing {
+ *     Shape bottomShape;
+ *     Shape topShape;
+ *   }
+ * }
+ *

Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?

   {@code
+ *   {
+ *     "bottomShape": {
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   {@code
+ *   {
+ *     "bottomShape": {
+ *       "type": "Diamond",
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "type": "Circle",
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + * + *

Registering Types

+ * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used.
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory
+ *       = RuntimeTypeAdapterFactory.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   {@code
+ *   shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
+ *   shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
+ *   shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter factory in your application's GSON builder: + *
   {@code
+ *   Gson gson = new GsonBuilder()
+ *       .registerTypeAdapterFactory(shapeAdapterFactory)
+ *       .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining:
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
+ *       .registerSubtype(Rectangle.class)
+ *       .registerSubtype(Circle.class)
+ *       .registerSubtype(Diamond.class);
+ * }
+ */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap>(); + private final Map, String> subtypeToLabel = new LinkedHashMap, String>(); + private final boolean maintainType; + + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName, boolean maintainType) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + this.maintainType = maintainType; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + * {@code maintainType} flag decide if the type will be stored in pojo or not. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName, boolean maintainType) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName, maintainType); + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName, false); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory(baseType, "type", false); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case + * sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + public TypeAdapter create(Gson gson, TypeToken type) { + if (type.getRawType() != baseType) { + return null; + } + + final Map> labelToDelegate + = new LinkedHashMap>(); + final Map, TypeAdapter> subtypeToDelegate + = new LinkedHashMap, TypeAdapter>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override public R read(JsonReader in) throws IOException { + JsonElement jsonElement = Streams.parse(in); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + + if (maintainType) { + Streams.write(jsonObject, out); + return; + } + + JsonObject clone = new JsonObject(); + + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + clone.add(typeFieldName, new JsonPrimitive(label)); + + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + Streams.write(clone, out); + } + }.nullSafe(); + } +} diff --git a/gson/src/test/java/org/baeldung/gson/conversion/JsonObjectConversionsUnitTest.java b/gson/src/test/java/org/baeldung/gson/conversion/JsonObjectConversionsUnitTest.java new file mode 100644 index 0000000000..847ec1b85d --- /dev/null +++ b/gson/src/test/java/org/baeldung/gson/conversion/JsonObjectConversionsUnitTest.java @@ -0,0 +1,33 @@ +package org.baeldung.gson.conversion; + +import com.google.gson.*; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +public class JsonObjectConversionsUnitTest { + + @Test + void whenUsingJsonParser_thenConvertToJsonObject() throws Exception { + // Example 1: Using JsonParser + String json = "{ \"name\": \"Baeldung\", \"java\": true }"; + + JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject(); + + Assert.assertTrue(jsonObject.isJsonObject()); + Assert.assertTrue(jsonObject.get("name").getAsString().equals("Baeldung")); + Assert.assertTrue(jsonObject.get("java").getAsBoolean() == true); + } + + @Test + void whenUsingGsonInstanceFromJson_thenConvertToJsonObject() throws Exception { + // Example 2: Using fromJson + String json = "{ \"name\": \"Baeldung\", \"java\": true }"; + + JsonObject convertedObject = new Gson().fromJson(json, JsonObject.class); + + Assert.assertTrue(convertedObject.isJsonObject()); + Assert.assertTrue(convertedObject.get("name").getAsString().equals("Baeldung")); + Assert.assertTrue(convertedObject.get("java").getAsBoolean() == true); + } + +} diff --git a/gson/src/test/java/org/baeldung/gson/deserialization/GsonAlternateUnitTest.java b/gson/src/test/java/org/baeldung/gson/deserialization/GsonAlternateUnitTest.java new file mode 100644 index 0000000000..f3a5d24e3e --- /dev/null +++ b/gson/src/test/java/org/baeldung/gson/deserialization/GsonAlternateUnitTest.java @@ -0,0 +1,39 @@ +package org.baeldung.gson.deserialization; + +import static org.junit.Assert.assertEquals; + +import org.baeldung.gson.entities.Weather; +import org.junit.Test; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class GsonAlternateUnitTest { + + @Test + public void givenTwoJsonFormats_whenDeserialized_thenWeatherObjectsCreated() throws Exception { + + Gson gson = new GsonBuilder().create(); + + Weather weather = gson.fromJson("{" + + "\"location\": \"London\"," + + "\"temp\": 15," + + "\"weather\": \"Cloudy\"" + + "}", Weather.class); + + assertEquals("London", weather.getLocation()); + assertEquals("Cloudy", weather.getOutlook()); + assertEquals(15, weather.getTemp()); + + weather = gson.fromJson("{" + + "\"place\": \"Lisbon\"," + + "\"temperature\": 35," + + "\"outlook\": \"Sunny\"" + + "}", Weather.class); + + assertEquals("Lisbon", weather.getLocation()); + assertEquals("Sunny", weather.getOutlook()); + assertEquals(35, weather.getTemp()); + + } +} diff --git a/guava-modules/guava-18/README.md b/guava-modules/guava-18/README.md index 9924d7c16f..fd5de4170a 100644 --- a/guava-modules/guava-18/README.md +++ b/guava-modules/guava-18/README.md @@ -4,9 +4,5 @@ ### Relevant Articles: -- [Guava Collections Cookbook](http://www.baeldung.com/guava-collections) -- [Guava Ordering Cookbook](http://www.baeldung.com/guava-order) - [Guava Functional Cookbook](http://www.baeldung.com/guava-functions-predicates) -- [Hamcrest Collections Cookbook](http://www.baeldung.com/hamcrest-collections-arrays) -- [Partition a List in Java](http://www.baeldung.com/java-list-split) - [Guava 18: What’s New?](http://www.baeldung.com/whats-new-in-guava-18) diff --git a/guava-modules/pom.xml b/guava-modules/pom.xml new file mode 100644 index 0000000000..fed9e446f7 --- /dev/null +++ b/guava-modules/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + guava-modules + guava-modules + pom + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + .. + + + + guava-18 + guava-19 + guava-21 + + + diff --git a/guest/spring-boot-app/src/test/java/com/stackify/test/EmployeeControllerTest.java b/guest/spring-boot-app/src/test/java/com/stackify/test/EmployeeControllerUnitTest.java similarity index 97% rename from guest/spring-boot-app/src/test/java/com/stackify/test/EmployeeControllerTest.java rename to guest/spring-boot-app/src/test/java/com/stackify/test/EmployeeControllerUnitTest.java index 2711a77ebd..9808546e82 100644 --- a/guest/spring-boot-app/src/test/java/com/stackify/test/EmployeeControllerTest.java +++ b/guest/spring-boot-app/src/test/java/com/stackify/test/EmployeeControllerUnitTest.java @@ -21,7 +21,7 @@ import com.stackify.Application; @RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) @WebAppConfiguration -public class EmployeeControllerTest { +public class EmployeeControllerUnitTest { private static final String CONTENT_TYPE = "application/json;charset=UTF-8"; diff --git a/guice/README.md b/guice/README.md index d1bd1ff883..77c788c363 100644 --- a/guice/README.md +++ b/guice/README.md @@ -2,3 +2,4 @@ ### Relevant Articles - [Guide to Google Guice](http://www.baeldung.com/guice) +- [Guice vs Spring – Dependency Injection](https://www.baeldung.com/guice-spring-dependency-injection) diff --git a/httpclient/README.md b/httpclient/README.md index 93e0f3c9e1..87fb38706d 100644 --- a/httpclient/README.md +++ b/httpclient/README.md @@ -12,13 +12,12 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [HttpClient 4 – Cancel / Abort Request](http://www.baeldung.com/httpclient-cancel-request) - [HttpClient 4 Cookbook](http://www.baeldung.com/httpclient4) - [Unshorten URLs with HttpClient](http://www.baeldung.com/unshorten-url-httpclient) -- [HttpClient with SSL](http://www.baeldung.com/httpclient-ssl) - [HttpClient 4 – Follow Redirects for POST](http://www.baeldung.com/httpclient-redirect-on-http-post) -- [HttpClient – Set Custom Header](http://www.baeldung.com/httpclient-custom-http-header) +- [Custom HTTP Header with the HttpClient](http://www.baeldung.com/httpclient-custom-http-header) - [HttpClient Basic Authentication](http://www.baeldung.com/httpclient-4-basic-authentication) - [Multipart Upload with HttpClient 4](http://www.baeldung.com/httpclient-multipart-upload) - [HttpAsyncClient Tutorial](http://www.baeldung.com/httpasyncclient-tutorial) - [HttpClient 4 Tutorial](http://www.baeldung.com/httpclient-guide) - [Advanced HttpClient Configuration](http://www.baeldung.com/httpclient-advanced-config) - [HttpClient 4 – Do Not Follow Redirects](http://www.baeldung.com/httpclient-stop-follow-redirect) -- [HttpClient 4 – Setting a Custom User-Agent](http://www.baeldung.com/httpclient-user-agent-header) +- [Custom User-Agent in HttpClient 4](http://www.baeldung.com/httpclient-user-agent-header) diff --git a/jackson-2/.gitignore b/jackson-2/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/jackson-2/.gitignore @@ -0,0 +1,13 @@ +*.class + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/jackson-2/README.md b/jackson-2/README.md new file mode 100644 index 0000000000..ec147f5fd9 --- /dev/null +++ b/jackson-2/README.md @@ -0,0 +1,9 @@ +========= + +## Jackson Cookbooks and Examples + +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + +### Relevant Articles: +- [Mapping Multiple JSON Fields to a Single Java Field](https://www.baeldung.com/json-multiple-fields-single-java-field) diff --git a/jackson-2/pom.xml b/jackson-2/pom.xml new file mode 100644 index 0000000000..ddbcb81dcc --- /dev/null +++ b/jackson-2/pom.xml @@ -0,0 +1,52 @@ + + 4.0.0 + jackson-2 + 0.1-SNAPSHOT + jackson-2 + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + jackson-2 + + + src/main/resources + true + + + + + + + + 3.11.0 + + + diff --git a/jackson-2/src/main/java/com/baeldung/jackson/entities/Weather.java b/jackson-2/src/main/java/com/baeldung/jackson/entities/Weather.java new file mode 100644 index 0000000000..4a8cea052f --- /dev/null +++ b/jackson-2/src/main/java/com/baeldung/jackson/entities/Weather.java @@ -0,0 +1,44 @@ +package com.baeldung.jackson.entities; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Weather { + + @JsonProperty("location") + @JsonAlias("place") + private String location; + + @JsonProperty("temp") + @JsonAlias("temperature") + private int temp; + + @JsonProperty("outlook") + @JsonAlias("weather") + private String outlook; + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public int getTemp() { + return temp; + } + + public void setTemp(int temp) { + this.temp = temp; + } + + public String getOutlook() { + return outlook; + } + + public void setOutlook(String outlook) { + this.outlook = outlook; + } + +} diff --git a/jackson-2/src/main/resources/logback.xml b/jackson-2/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/jackson-2/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/jackson-2/src/test/java/com/baeldung/jackson/deserialization/jsonalias/JsonAliasUnitTest.java b/jackson-2/src/test/java/com/baeldung/jackson/deserialization/jsonalias/JsonAliasUnitTest.java new file mode 100644 index 0000000000..b5940a7bd7 --- /dev/null +++ b/jackson-2/src/test/java/com/baeldung/jackson/deserialization/jsonalias/JsonAliasUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.jackson.deserialization.jsonalias; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.baeldung.jackson.entities.Weather; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class JsonAliasUnitTest { + + @Test + public void givenTwoJsonFormats_whenDeserialized_thenWeatherObjectsCreated() throws Exception { + + ObjectMapper mapper = new ObjectMapper(); + + Weather weather = mapper.readValue("{" + + "\"location\": \"London\"," + + "\"temp\": 15," + + "\"weather\": \"Cloudy\"" + + "}", Weather.class); + + assertEquals("London", weather.getLocation()); + assertEquals("Cloudy", weather.getOutlook()); + assertEquals(15, weather.getTemp()); + + weather = mapper.readValue("{" + + "\"place\": \"Lisbon\"," + + "\"temperature\": 35," + + "\"outlook\": \"Sunny\"" + + "}", Weather.class); + + assertEquals("Lisbon", weather.getLocation()); + assertEquals("Sunny", weather.getOutlook()); + assertEquals(35, weather.getTemp()); + + } +} diff --git a/jackson/README.md b/jackson/README.md index e201a06727..e9cf6f212c 100644 --- a/jackson/README.md +++ b/jackson/README.md @@ -10,14 +10,14 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Jackson – Unmarshall to Collection/Array](http://www.baeldung.com/jackson-collection-array) - [Jackson Unmarshalling json with Unknown Properties](http://www.baeldung.com/jackson-deserialize-json-unknown-properties) - [Jackson – Custom Serializer](http://www.baeldung.com/jackson-custom-serialization) -- [Jackson – Custom Deserializer](http://www.baeldung.com/jackson-deserialization) +- [Getting Started with Custom Deserialization in Jackson](http://www.baeldung.com/jackson-deserialization) - [Jackson Exceptions – Problems and Solutions](http://www.baeldung.com/jackson-exception) - [Jackson Date](http://www.baeldung.com/jackson-serialize-dates) - [Jackson – Bidirectional Relationships](http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion) - [Jackson JSON Tutorial](http://www.baeldung.com/jackson) - [Jackson – Working with Maps and nulls](http://www.baeldung.com/jackson-map-null-values-or-null-key) - [Jackson – Decide What Fields Get Serialized/Deserializaed](http://www.baeldung.com/jackson-field-serializable-deserializable-or-not) -- [A Guide to Jackson Annotations](http://www.baeldung.com/jackson-annotations) +- [Jackson Annotation Examples](http://www.baeldung.com/jackson-annotations) - [Working with Tree Model Nodes in Jackson](http://www.baeldung.com/jackson-json-node-tree-model) - [Jackson vs Gson](http://www.baeldung.com/jackson-vs-gson) - [Intro to the Jackson ObjectMapper](http://www.baeldung.com/jackson-object-mapper-tutorial) @@ -25,7 +25,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [More Jackson Annotations](http://www.baeldung.com/jackson-advanced-annotations) - [Inheritance with Jackson](http://www.baeldung.com/jackson-inheritance) - [Guide to @JsonFormat in Jackson](http://www.baeldung.com/jackson-jsonformat) -- [A Guide to Optional with Jackson](http://www.baeldung.com/jackson-optional) +- [Using Optional with Jackson](http://www.baeldung.com/jackson-optional) - [Map Serialization and Deserialization with Jackson](http://www.baeldung.com/jackson-map) - [Jackson Streaming API](http://www.baeldung.com/jackson-streaming-api) - [Jackson – JsonMappingException (No serializer found for class)](http://www.baeldung.com/jackson-jsonmappingexception) @@ -38,3 +38,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Mapping Nested Values with Jackson](http://www.baeldung.com/jackson-nested-values) - [Convert XML to JSON Using Jackson](https://www.baeldung.com/jackson-convert-xml-json) - [Deserialize Immutable Objects with Jackson](https://www.baeldung.com/jackson-deserialize-immutable-objects) +- [Mapping a Dynamic JSON Object with Jackson](https://www.baeldung.com/jackson-mapping-dynamic-object) + diff --git a/jackson/pom.xml b/jackson/pom.xml index e941ababc5..948248d255 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -117,8 +117,6 @@ - - 2.9.7 3.8 2.10 diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jacksoninject/Author.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jacksoninject/Author.java deleted file mode 100644 index db8b594509..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jacksoninject/Author.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.baeldung.jackson.deserialization.jacksoninject; - -import com.baeldung.jackson.domain.Item; - -import java.util.ArrayList; -import java.util.List; - -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author() { - } - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java index c4daf68bd6..d9748e2997 100644 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java +++ b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java @@ -1,24 +1,14 @@ package com.baeldung.jackson.deserialization.jsonanysetter; -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; - import java.util.HashMap; import java.util.Map; +import com.fasterxml.jackson.annotation.JsonAnySetter; + public class Inventory { - private Map stock = new HashMap<>(); - private Map countryDeliveryCost = new HashMap<>(); - @JsonIgnore - public Map getStock() { - return stock; - } - public Map getCountryDeliveryCost() { return countryDeliveryCost; } diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsoncreator/Author.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsoncreator/Author.java deleted file mode 100644 index d48c95b255..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsoncreator/Author.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.jackson.deserialization.jsoncreator; - -import com.baeldung.jackson.domain.Person; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.ArrayList; -import java.util.List; - -public class Author extends Person { - - List items = new ArrayList<>(); - - @JsonCreator - public Author(@JsonProperty("christianName") String firstName, @JsonProperty("surname") String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Author.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Author.java deleted file mode 100644 index 62e108facb..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Author.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.jackson.deserialization.jsondeserialize; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; - -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java index dc0d0ee623..1e411da64e 100644 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java +++ b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java @@ -1,12 +1,16 @@ package com.baeldung.jackson.deserialization.jsondeserialize; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; - import java.math.BigDecimal; import java.util.Date; +import java.util.UUID; -public class Book extends Item { +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +public class Book { + + private UUID id; + private String title; + private float price; private String ISBN; @JsonDeserialize(using = CustomDateDeserializer.class) @@ -16,8 +20,9 @@ public class Book extends Item { public Book() { } - public Book(String title, Author author) { - super(title, author); + public Book(String title) { + this.id = UUID.randomUUID(); + this.title = title; } public String getISBN() { @@ -43,4 +48,28 @@ public class Book extends Item { public void setPages(BigDecimal pages) { this.pages = pages; } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public float getPrice() { + return price; + } + + public void setPrice(float price) { + this.price = price; + } } diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Item.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Item.java deleted file mode 100644 index fc27a586ac..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Item.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.baeldung.jackson.deserialization.jsondeserialize; - -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonsetter/Author.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonsetter/Author.java deleted file mode 100644 index 3f9ae70a88..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonsetter/Author.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.baeldung.jackson.deserialization.jsonsetter; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSetter; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author() { - } - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - @JsonIgnore - public List getItems() { - return items; - } - - @JsonSetter("publications") - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Author.java b/jackson/src/main/java/com/baeldung/jackson/domain/Author.java deleted file mode 100644 index 9000c00f21..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Author.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Book.java b/jackson/src/main/java/com/baeldung/jackson/domain/Book.java deleted file mode 100644 index a5963e33ba..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Book.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.math.BigDecimal; -import java.util.Date; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Book extends Item { - - private String ISBN; - private Date published; - private BigDecimal pages; - - public Book() { - } - - public Book(String title, Author author) { - super(title, author); - } - - public String getISBN() { - return ISBN; - } - - public void setISBN(String ISBN) { - this.ISBN = ISBN; - } - - public Date getPublished() { - return published; - } - - public void setPublished(Date published) { - this.published = published; - } - - public BigDecimal getPages() { - return pages; - } - - public void setPages(BigDecimal pages) { - this.pages = pages; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Course.java b/jackson/src/main/java/com/baeldung/jackson/domain/Course.java deleted file mode 100644 index 672b0bc250..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Course.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Customer.java b/jackson/src/main/java/com/baeldung/jackson/domain/Customer.java deleted file mode 100644 index 1e03ff9a13..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Customer.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.jackson.domain; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Customer extends Person { - - private String configuration; - - public Customer(String firstName, String lastName) { - super(firstName, lastName); - } - - public String getConfiguration() { - return configuration; - } - - public void setConfiguration(String configuration) { - this.configuration = configuration; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Inventory.java b/jackson/src/main/java/com/baeldung/jackson/domain/Inventory.java deleted file mode 100644 index 41b7dc51da..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Inventory.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.util.HashMap; -import java.util.Map; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Inventory { - - private Map stock; - - private Map countryDeliveryCost = new HashMap<>(); - - public Map getStock() { - return stock; - } - - public void setStock(Map stock) { - this.stock = stock; - } - - public Map getCountryDeliveryCost() { - return countryDeliveryCost; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Item.java b/jackson/src/main/java/com/baeldung/jackson/domain/Item.java deleted file mode 100644 index d9d1350a8e..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Item.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Order.java b/jackson/src/main/java/com/baeldung/jackson/domain/Order.java deleted file mode 100644 index 91f87f74df..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Order.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.baeldung.jackson.domain; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Order { - - private UUID id; - private Type type; - private int internalAudit; - - public static class Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public Order(int internalAudit) { - this(); - this.type = new Type(); - this.type.id = 20; - this.type.name = "Order"; - this.internalAudit = internalAudit; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/domain/Person.java b/jackson/src/main/java/com/baeldung/jackson/domain/Person.java index 785efff755..f11ba41113 100644 --- a/jackson/src/main/java/com/baeldung/jackson/domain/Person.java +++ b/jackson/src/main/java/com/baeldung/jackson/domain/Person.java @@ -1,24 +1,12 @@ package com.baeldung.jackson.domain; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ public class Person { - private UUID id; private String firstName; private String lastName; - - public Person() { - } - + public Person(String firstName, String lastName) { - this.id = UUID.randomUUID(); + super(); this.firstName = firstName; this.lastName = lastName; } @@ -38,8 +26,5 @@ public class Person { public void setLastName(String lastName) { this.lastName = lastName; } - - public UUID getId() { - return id; - } } + diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonautodetect/Order.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonautodetect/Order.java deleted file mode 100644 index f2ff5eeb08..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonautodetect/Order.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonautodetect; - -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonAutoDetect(fieldVisibility = Visibility.ANY) -public class Order { - - private UUID id; - private Type type; - private int internalAudit; - - public static class Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public Order(int internalAudit) { - this(); - this.type = new Type(); - this.type.id = 20; - this.type.name = "Order"; - this.internalAudit = internalAudit; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Author.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Author.java deleted file mode 100644 index a7801493bf..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Author.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignore; - -import com.baeldung.jackson.domain.Item; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Person.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Person.java deleted file mode 100644 index 0037d83148..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignore/Person.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignore; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Person { - - @JsonIgnore - private UUID id; - private String firstName; - private String lastName; - - public Person() { - } - - public Person(String firstName, String lastName) { - this.id = UUID.randomUUID(); - this.firstName = firstName; - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public UUID getId() { - return id; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoreproperties/Course.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoreproperties/Course.java deleted file mode 100644 index 70b4dd9842..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoreproperties/Course.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignoreproperties; - -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonIgnoreProperties({ "medium" }) -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoretype/Order.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoretype/Order.java deleted file mode 100644 index 0d8867933f..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsonignoretype/Order.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignoretype; - -import com.fasterxml.jackson.annotation.JsonIgnoreType; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Order { - - private UUID id; - private Type type; - - @JsonIgnoreType - public static class Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsoninclude/Author.java b/jackson/src/main/java/com/baeldung/jackson/inclusion/jsoninclude/Author.java deleted file mode 100644 index 30cb2735c2..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/inclusion/jsoninclude/Author.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.baeldung.jackson.inclusion.jsoninclude; - -import com.baeldung.jackson.domain.Person; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonInclude; - -import java.util.ArrayList; -import java.util.List; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonInclude(NON_NULL) -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Course.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Course.java deleted file mode 100644 index a44492b9f7..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Course.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.baeldung.jackson.miscellaneous.custom; - -import com.baeldung.jackson.domain.Author; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@CustomCourseAnnotation -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/CustomCourseAnnotation.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/CustomCourseAnnotation.java deleted file mode 100644 index d7f72ca6ec..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/CustomCourseAnnotation.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.baeldung.jackson.miscellaneous.custom; - -import com.fasterxml.jackson.annotation.*; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotationsInside -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({ "title", "price", "id", "duration", "authors", "level" }) -@JsonIgnoreProperties({ "prerequisite" }) -public @interface CustomCourseAnnotation { -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Item.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Item.java deleted file mode 100644 index 6625283dec..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/custom/Item.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.baeldung.jackson.miscellaneous.custom; - -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/disable/Author.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/disable/Author.java deleted file mode 100644 index 0638e32925..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/disable/Author.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.baeldung.jackson.miscellaneous.disable; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({ "lastName", "items", "firstName", "id" }) -public class Author extends Person { - - @JsonIgnore - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/Author.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/Author.java deleted file mode 100644 index 26e3e4b647..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/Author.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.baeldung.jackson.miscellaneous.mixin; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/IgnoreListMixIn.java b/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/IgnoreListMixIn.java deleted file mode 100644 index 418c09c251..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/miscellaneous/mixin/IgnoreListMixIn.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.baeldung.jackson.miscellaneous.mixin; - -import com.fasterxml.jackson.annotation.JsonIgnoreType; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonIgnoreType -public class IgnoreListMixIn { -} diff --git a/jackson/src/main/java/com/baeldung/jackson/polymorphism/Order.java b/jackson/src/main/java/com/baeldung/jackson/polymorphism/Order.java deleted file mode 100644 index 1813148b2b..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/polymorphism/Order.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.baeldung.jackson.polymorphism; - -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeName; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Order { - - private UUID id; - private Type type; - private int internalAudit; - - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "ordertype") - @JsonSubTypes({ @JsonSubTypes.Type(value = InternalType.class, name = "internal") }) - public static class Type { - public long id; - public String name; - } - - @JsonTypeName("internal") - public static class InternalType extends Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public Order(int internalAudit) { - this(); - this.type = new Type(); - this.type.id = 20; - this.type.name = "Order"; - this.internalAudit = internalAudit; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonanygetter/Inventory.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonanygetter/Inventory.java deleted file mode 100644 index 52f586d93b..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonanygetter/Inventory.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.baeldung.jackson.serialization.jsonanygetter; - -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonIgnore; - -import java.util.HashMap; -import java.util.Map; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Inventory { - - private String location; - - private Map stock = new HashMap<>(); - - private Map countryDeliveryCost = new HashMap<>(); - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - @JsonIgnore - public Map getStock() { - return stock; - } - - @JsonAnyGetter - public Map getCountryDeliveryCost() { - return countryDeliveryCost; - } - -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsongetter/Author.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsongetter/Author.java deleted file mode 100644 index 8d89fefce7..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsongetter/Author.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.jackson.serialization.jsongetter; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; -import com.fasterxml.jackson.annotation.JsonGetter; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - @JsonGetter("publications") - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Author.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Author.java deleted file mode 100644 index dadf893cf9..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Author.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.baeldung.jackson.serialization.jsonpropertyorder; - -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonPropertyOrder({ "items", "firstName", "lastName", "id" }) -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Person.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Person.java deleted file mode 100644 index 519e48aada..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonpropertyorder/Person.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.baeldung.jackson.serialization.jsonpropertyorder; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Person { - - private UUID id; - private String firstName; - private String lastName; - - public Person(String firstName, String lastName) { - this.id = UUID.randomUUID(); - this.firstName = firstName; - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public UUID getId() { - return id; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrawvalue/Customer.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrawvalue/Customer.java deleted file mode 100644 index f19c5314d2..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrawvalue/Customer.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.jackson.serialization.jsonrawvalue; - -import com.baeldung.jackson.domain.Person; -import com.fasterxml.jackson.annotation.JsonRawValue; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Customer extends Person { - - @JsonRawValue - private String configuration; - - public Customer(String firstName, String lastName) { - super(firstName, lastName); - } - - public String getConfiguration() { - return configuration; - } - - public void setConfiguration(String configuration) { - this.configuration = configuration; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrootname/Author.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrootname/Author.java deleted file mode 100644 index c6ebfd10fb..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonrootname/Author.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.jackson.serialization.jsonrootname; - -import com.baeldung.jackson.domain.Item; -import com.baeldung.jackson.domain.Person; -import com.fasterxml.jackson.annotation.JsonRootName; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonRootName("writer") -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Author.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Author.java deleted file mode 100644 index 5a6e90d712..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Author.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.jackson.serialization.jsonserialize; - -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Book.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Book.java deleted file mode 100644 index 0ecc4e72ce..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Book.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.baeldung.jackson.serialization.jsonserialize; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -import java.math.BigDecimal; -import java.util.Date; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Book extends Item { - - private String ISBN; - - @JsonSerialize(using = CustomDateSerializer.class) - private Date published; - private BigDecimal pages; - - public Book() { - } - - public Book(String title, Author author) { - super(title, author); - } - - public String getISBN() { - return ISBN; - } - - public void setISBN(String ISBN) { - this.ISBN = ISBN; - } - - public Date getPublished() { - return published; - } - - public void setPublished(Date published) { - this.published = published; - } - - public BigDecimal getPages() { - return pages; - } - - public void setPages(BigDecimal pages) { - this.pages = pages; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/CustomDateSerializer.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/CustomDateSerializer.java deleted file mode 100644 index 131f4f3695..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/CustomDateSerializer.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.baeldung.jackson.serialization.jsonserialize; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; - -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class CustomDateSerializer extends StdSerializer { - - private static SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - - public CustomDateSerializer() { - this(null); - } - - public CustomDateSerializer(Class t) { - super(t); - } - - @Override - public void serialize(Date value, JsonGenerator gen, SerializerProvider arg2) throws IOException, JsonProcessingException { - gen.writeString(formatter.format(value)); - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Item.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Item.java deleted file mode 100644 index 56cfa85793..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonserialize/Item.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.baeldung.jackson.serialization.jsonserialize; - -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonvalue/Course.java b/jackson/src/main/java/com/baeldung/jackson/serialization/jsonvalue/Course.java deleted file mode 100644 index a3fdc2d8eb..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/serialization/jsonvalue/Course.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.baeldung.jackson.serialization.jsonvalue; - -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonValue; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - @JsonValue - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/annotation/AliasBean.java b/jackson/src/test/java/com/baeldung/jackson/annotation/AliasBean.java new file mode 100644 index 0000000000..1842b2b6f5 --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/annotation/AliasBean.java @@ -0,0 +1,31 @@ +package com.baeldung.jackson.annotation; + +import com.fasterxml.jackson.annotation.JsonAlias; + +public class AliasBean { + + @JsonAlias({ "fName", "f_name" }) + private String firstName; + + private String lastName; + + public AliasBean() { + + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/jacksoninject/JacksonInjectUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/jacksoninject/JacksonInjectUnitTest.java deleted file mode 100644 index 96dbff6f3c..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/jacksoninject/JacksonInjectUnitTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.baeldung.jackson.deserialization.jacksoninject; - -import com.fasterxml.jackson.databind.InjectableValues; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JacksonInjectUnitTest { - - @Test - public void whenDeserializingUsingJacksonInject_thenCorrect() throws IOException { - - UUID id = UUID.fromString("9616dc8c-bad3-11e6-a4a6-cec0c932ce01"); - - // arrange - String authorJson = "{\"firstName\": \"Alex\", \"lastName\": \"Theedom\"}"; - - // act - InjectableValues inject = new InjectableValues.Std().addValue(UUID.class, id); - Author author = new ObjectMapper().reader(inject) - .forType(Author.class) - .readValue(authorJson); - - // assert - assertThat(author.getId()).isEqualTo(id); - - /* - { - "firstName": "Alex", - "lastName": "Theedom", - "publications": [] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonanysetter/JsonAnySetterUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonanysetter/JsonAnySetterUnitTest.java deleted file mode 100644 index 2e1f94bc3c..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonanysetter/JsonAnySetterUnitTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.baeldung.jackson.deserialization.jsonanysetter; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonAnySetterUnitTest { - - @Test - public void whenDeserializingUsingJsonAnySetter_thenCorrect() throws IOException { - - // arrange - String json = "{\"USA\":10.00,\"UK\":15.00,\"China\":23.00,\"Brazil\":12.00,\"France\":8.00,\"Russia\":18.00}"; - - // act - Inventory inventory = new ObjectMapper().readerFor(Inventory.class) - .readValue(json); - - // assert - assertThat(from(json).getMap(".") - .get("USA")).isEqualTo(inventory.getCountryDeliveryCost() - .get("USA")); - assertThat(from(json).getMap(".") - .get("UK")).isEqualTo(inventory.getCountryDeliveryCost() - .get("UK")); - assertThat(from(json).getMap(".") - .get("China")).isEqualTo(inventory.getCountryDeliveryCost() - .get("China")); - assertThat(from(json).getMap(".") - .get("Brazil")).isEqualTo(inventory.getCountryDeliveryCost() - .get("Brazil")); - assertThat(from(json).getMap(".") - .get("France")).isEqualTo(inventory.getCountryDeliveryCost() - .get("France")); - assertThat(from(json).getMap(".") - .get("Russia")).isEqualTo(inventory.getCountryDeliveryCost() - .get("Russia")); - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsoncreator/JsonCreatorUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/jsoncreator/JsonCreatorUnitTest.java deleted file mode 100644 index cc245dab66..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsoncreator/JsonCreatorUnitTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.baeldung.jackson.deserialization.jsoncreator; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonCreatorUnitTest { - - @Test - public void whenDeserializingUsingJsonCreator_thenCorrect() throws IOException { - - // arrange - String authorJson = "{" + " \"christianName\": \"Alex\"," + " \"surname\": \"Theedom\"" + "}"; - - // act - final Author author = new ObjectMapper().readerFor(Author.class) - .readValue(authorJson); - - // assert - assertThat(from(authorJson).getString("christianName")).isEqualTo(author.getFirstName()); - assertThat(from(authorJson).getString("surname")).isEqualTo(author.getLastName()); - - /* - { - "christianName": "Alex", - "surname": "Theedom" - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsondeserialize/JsonDeserializeUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/jsondeserialize/JsonDeserializeUnitTest.java deleted file mode 100644 index 1bcde998d6..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsondeserialize/JsonDeserializeUnitTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.baeldung.jackson.deserialization.jsondeserialize; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; -import java.text.SimpleDateFormat; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonDeserializeUnitTest { - - @Test - public void whenDeserializingUsingJsonDeserialize_thenCorrect() throws IOException { - - // arrange - String bookJson = "{\"id\":\"957c43f2-fa2e-42f9-bf75-6e3d5bb6960a\",\"title\":\"Effective Java\",\"authors\":[{\"id\":\"9bcd817d-0141-42e6-8f04-e5aaab0980b6\",\"firstName\":\"Joshua\",\"lastName\":\"Bloch\"}],\"price\":0,\"published\":\"25-12-2017 13:30:25\",\"pages\":null,\"isbn\":null}"; - - // act - Book book = new ObjectMapper().readerFor(Book.class) - .readValue(bookJson); - - // assert - SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - assertThat(from(bookJson).getString("published")).isEqualTo(df.format(book.getPublished())); - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonsetter/JsonSetterUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonsetter/JsonSetterUnitTest.java deleted file mode 100644 index 4379fe376c..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/jsonsetter/JsonSetterUnitTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.baeldung.jackson.deserialization.jsonsetter; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonSetterUnitTest { - - @Test - public void whenDeserializingUsingJsonSetter_thenCorrect() throws IOException { - - // arrange - String json = "{\"firstName\":\"Alex\",\"lastName\":\"Theedom\",\"publications\":[{\"title\":\"Professional Java EE Design Patterns\"}]}"; - - // act - Author author = new ObjectMapper().readerFor(Author.class) - .readValue(json); - - // assert - assertThat(from(json).getList("publications") - .size()).isEqualTo(author.getItems() - .size()); - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/Address.java b/jackson/src/test/java/com/baeldung/jackson/dtos/Address.java new file mode 100644 index 0000000000..985851f456 --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/dtos/Address.java @@ -0,0 +1,33 @@ +package com.baeldung.jackson.dtos; + +public class Address { + + String streetNumber; + String streetName; + String city; + + public String getStreetNumber() { + return streetNumber; + } + + public void setStreetNumber(String streetNumber) { + this.streetNumber = streetNumber; + } + + public String getStreetName() { + return streetName; + } + + public void setStreetName(String streetName) { + this.streetName = streetName; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + +} diff --git a/jackson/src/test/java/com/baeldung/jackson/dtos/Person.java b/jackson/src/test/java/com/baeldung/jackson/dtos/Person.java new file mode 100644 index 0000000000..13093cdcad --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/dtos/Person.java @@ -0,0 +1,47 @@ +package com.baeldung.jackson.dtos; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +@JacksonXmlRootElement(localName = "person") +public final class Person { + private String firstName; + private String lastName; + private List phoneNumbers = new ArrayList<>(); + private List
address = new ArrayList<>(); + + public List
getAddress() { + return address; + } + + public void setAddress(List
address) { + this.address = address; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public List getPhoneNumbers() { + return phoneNumbers; + } + + public void setPhoneNumbers(List phoneNumbers) { + this.phoneNumbers = phoneNumbers; + } + +} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/exception/UserWithRootNamespace.java b/jackson/src/test/java/com/baeldung/jackson/exception/UserWithRootNamespace.java new file mode 100644 index 0000000000..bf8c85efba --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/exception/UserWithRootNamespace.java @@ -0,0 +1,18 @@ +package com.baeldung.jackson.exception; + +import com.fasterxml.jackson.annotation.JsonRootName; + +@JsonRootName(value = "user", namespace="users") +public class UserWithRootNamespace { + public int id; + public String name; + + public UserWithRootNamespace() { + super(); + } + + public UserWithRootNamespace(final int id, final String name) { + this.id = id; + this.name = name; + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/Author.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/Author.java deleted file mode 100644 index 3d5a9c907c..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/Author.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.jackson.general.jsonfilter; - -import com.baeldung.jackson.domain.Person; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonFilter; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonFilter("authorFilter") -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/JsonFilterUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/JsonFilterUnitTest.java deleted file mode 100644 index 6fcc57faa7..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonfilter/JsonFilterUnitTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.baeldung.jackson.general.jsonfilter; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ser.FilterProvider; -import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; -import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonFilterUnitTest { - - @Test - public void whenSerializingUsingJsonFilter_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - FilterProvider filters = new SimpleFilterProvider().addFilter("authorFilter", SimpleBeanPropertyFilter.filterOutAllExcept("lastName")); - - // act - String result = new ObjectMapper().writer(filters) - .writeValueAsString(author); - - // assert - assertThat(from(result).getList("items")).isNull(); - - /* - { - "lastName": "Theedom" - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/Book.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/Book.java deleted file mode 100644 index e2eb4aa48a..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/Book.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung.jackson.general.jsonformat; - -import com.baeldung.jackson.domain.Author; -import com.baeldung.jackson.domain.Item; -import com.fasterxml.jackson.annotation.JsonFormat; - -import java.math.BigDecimal; -import java.util.Date; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Book extends Item { - - private String ISBN; - - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy HH:mm:ss") - private Date published; - private BigDecimal pages; - - public Book() { - } - - public Book(String title, Author author) { - super(title, author); - } - - public String getISBN() { - return ISBN; - } - - public void setISBN(String ISBN) { - this.ISBN = ISBN; - } - - public Date getPublished() { - return published; - } - - public void setPublished(Date published) { - this.published = published; - } - - public BigDecimal getPages() { - return pages; - } - - public void setPages(BigDecimal pages) { - this.pages = pages; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/JsonFormatUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/JsonFormatUnitTest.java deleted file mode 100644 index 1fe217cef6..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonformat/JsonFormatUnitTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.baeldung.jackson.general.jsonformat; - -import com.baeldung.jackson.domain.Author; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonFormatUnitTest { - - @Test - public void whenSerializingUsingJsonFormat_thenCorrect() throws JsonProcessingException, ParseException { - - // arrange - SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); - - String toParse = "20-12-2014 14:30:00"; - Date date = df.parse(toParse); - - Book book = new Book("Design Patterns: Elements of Reusable Object-oriented Software", new Author("The", "GoF")); - book.setPublished(date); - - // act - String result = new ObjectMapper().writeValueAsString(book); - - // assert - assertThat(from(result).getString("published")).isEqualTo(toParse); - - /* - { - "id": "762b39be-fd5b-489e-8688-aeb3b9bbf019", - "title": "Design Patterns: Elements of Reusable Object-oriented Software", - "authors": [ - { - "id": "6941b780-0f54-4259-adcb-85523c8f25f4", - "firstName": "The", - "lastName": "GoF", - "items": [] - } - ], - "price": 0, - "published": "20-12-2014 02:30:00", - "pages": null, - "isbn": null - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Author.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Author.java deleted file mode 100644 index 1f36b95b2a..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Author.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.baeldung.jackson.general.jsonidentityinfo; - -import com.fasterxml.jackson.annotation.JsonIdentityInfo; -import com.fasterxml.jackson.annotation.ObjectIdGenerators; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Course.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Course.java deleted file mode 100644 index 80dd9c275e..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Course.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.baeldung.jackson.general.jsonidentityinfo; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Item.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Item.java deleted file mode 100644 index bad6562122..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Item.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.baeldung.jackson.general.jsonidentityinfo; - -import com.fasterxml.jackson.annotation.JsonIdentityInfo; -import com.fasterxml.jackson.annotation.ObjectIdGenerators; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/JsonIdentityInfoUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/JsonIdentityInfoUnitTest.java deleted file mode 100644 index 014f1a8f69..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/JsonIdentityInfoUnitTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.baeldung.jackson.general.jsonidentityinfo; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.util.Collections; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonIdentityInfoUnitTest { - - @Test - public void whenSerializingUsingJsonIdentityInfo_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - Course course = new Course("Java EE Introduction", author); - author.setItems(Collections.singletonList(course)); - course.setAuthors(Collections.singletonList(author)); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getString("items[0].authors")).isNotNull(); - - /* - Authors are included. - { - "id": "1b408bf9-5946-4a14-a112-fde2953a7fe7", - "firstName": "Alex", - "lastName": "Theedom", - "items": [ - { - "id": "5ed30530-f0a5-42eb-b786-be2c655da968", - "title": "Java EE Introduction", - "authors": [ - "1b408bf9-5946-4a14-a112-fde2953a7fe7" - ], - "price": 0, - "duration": 0, - "medium": null, - "level": null, - "prerequisite": null - } - ] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Person.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Person.java deleted file mode 100644 index ea80814124..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonidentityinfo/Person.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.baeldung.jackson.general.jsonidentityinfo; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Person { - - private UUID id; - private String firstName; - private String lastName; - - public Person() { - } - - public Person(String firstName, String lastName) { - this.id = UUID.randomUUID(); - this.firstName = firstName; - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public UUID getId() { - return id; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Author.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Author.java deleted file mode 100644 index 01552df729..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Author.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.jackson.general.jsonproperty; - -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Book.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Book.java deleted file mode 100644 index 100d9634f5..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Book.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.baeldung.jackson.general.jsonproperty; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.math.BigDecimal; -import java.util.Date; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Book extends Item { - - private String ISBN; - private Date published; - private BigDecimal pages; - private String binding; - - public Book() { - } - - public Book(String title, Author author) { - super(title, author); - } - - public String getISBN() { - return ISBN; - } - - public void setISBN(String ISBN) { - this.ISBN = ISBN; - } - - public Date getPublished() { - return published; - } - - public void setPublished(Date published) { - this.published = published; - } - - public BigDecimal getPages() { - return pages; - } - - public void setPages(BigDecimal pages) { - this.pages = pages; - } - - @JsonProperty("binding") - public String coverBinding() { - return binding; - } - - @JsonProperty("binding") - public void configureBinding(String binding) { - this.binding = binding; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Item.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Item.java deleted file mode 100644 index d7ee430d51..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/Item.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.baeldung.jackson.general.jsonproperty; - -import com.baeldung.jackson.domain.Person; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/JsonPropertyUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/JsonPropertyUnitTest.java deleted file mode 100644 index 0b88e7fc47..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonproperty/JsonPropertyUnitTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.baeldung.jackson.general.jsonproperty; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonPropertyUnitTest { - - @Test - public void whenSerializingUsingJsonProperty_thenCorrect() throws JsonProcessingException { - - // arrange - Book book = new Book("Design Patterns: Elements of Reusable Object-oriented Software", new Author("The", "GoF")); - book.configureBinding("Hardback"); - - // act - String result = new ObjectMapper().writeValueAsString(book); - - // assert - assertThat(from(result).getString("binding")).isEqualTo("Hardback"); - - /* - { - "id": "cd941587-d1ae-4c2a-9a36-29533bf50411", - "title": "Design Patterns: Elements of Reusable Object-oriented Software", - "authors": [ - { - "id": "c8e26318-2f5b-4fa2-9fdc-6e99be021fca", - "firstName": "The", - "lastName": "GoF", - "items": [] - } - ], - "price": 0, - "published": null, - "pages": null, - "isbn": null, - "binding": "Hardback" - } - */ - - } - - @Test - public void whenDeserializingUsingJsonProperty_thenCorrect() throws IOException { - - // arrange - String result = "{\"id\":\"cd941587-d1ae-4c2a-9a36-29533bf50411\",\"title\":\"Design Patterns: Elements of Reusable Object-oriented Software\",\"authors\":[{\"id\":\"c8e26318-2f5b-4fa2-9fdc-6e99be021fca\",\"firstName\":\"The\",\"lastName\":\"GoF\"}],\"binding\":\"Hardback\"}"; - - // act - Book book = new ObjectMapper().readerFor(Book.class) - .readValue(result); - - // assert - assertThat(book.coverBinding()).isEqualTo("Hardback"); - - } - -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/JsonUnwrappedUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/JsonUnwrappedUnitTest.java deleted file mode 100644 index 5130e037d5..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/JsonUnwrappedUnitTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.baeldung.jackson.general.jsonunwrapped; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonUnwrappedUnitTest { - - @Test - public void whenSerializingUsingJsonUnwrapped_thenCorrect() throws JsonProcessingException { - - // arrange - Order.Type preorderType = new Order.Type(); - preorderType.id = 10; - preorderType.name = "pre-order"; - - Order order = new Order(preorderType); - - // act - String result = new ObjectMapper().writeValueAsString(order); - - // assert - assertThat(from(result).getInt("id")).isEqualTo(10); - assertThat(from(result).getString("name")).isEqualTo("pre-order"); - - /* - { - "id": 10, - "name": "pre-order" - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/Order.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/Order.java deleted file mode 100644 index b1c5b832c3..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonunwrapped/Order.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.baeldung.jackson.general.jsonunwrapped; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Order { - - private UUID id; - - @JsonUnwrapped - private Type type; - private int internalAudit; - - public static class Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public Order(int internalAudit) { - this(); - this.type = new Type(); - this.type.id = 20; - this.type.name = "Order"; - this.internalAudit = internalAudit; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/JsonViewUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonview/JsonViewUnitTest.java deleted file mode 100644 index ab609008ce..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/JsonViewUnitTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.baeldung.jackson.general.jsonview; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonViewUnitTest { - - @Test - public void whenSerializingUsingJsonView_andInternalView_thenCorrect() throws JsonProcessingException { - - // arrange - Order order = new Order(120); - - // act - String result = new ObjectMapper().writerWithView(Views.Internal.class) - .writeValueAsString(order); - - // assert - assertThat(from(result).getUUID("id")).isNotNull(); - assertThat(from(result).getObject("type", Order.Type.class)).isNotNull(); - assertThat(from(result).getInt("internalAudit")).isEqualTo(120); - - /* - { - "id": "33806388-795b-4812-b90a-60292111bc5c", - "type": { - "id": 20, - "name": "Order" - }, - "internalAudit": 120 - } - */ - - } - - @Test - public void whenSerializingUsingJsonView_andPublicView_thenCorrect() throws JsonProcessingException { - - // arrange - Order order = new Order(120); - - // act - String result = new ObjectMapper().writerWithView(Views.Public.class) - .writeValueAsString(order); - - // assert - assertThat(from(result).getUUID("id")).isNotNull(); - assertThat(from(result).getObject("type", Order.Type.class)).isNotNull(); - assertThat(result).doesNotContain("internalAudit"); - - /* - { - "id": "5184d5fc-e359-4cdf-93fa-4054025bef4e", - "type": { - "id": 20, - "name": "Order" - } - } - */ - - } - -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Order.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Order.java deleted file mode 100644 index 69adf1b59d..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Order.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.baeldung.jackson.general.jsonview; - -import com.fasterxml.jackson.annotation.JsonView; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Order { - - @JsonView(Views.Public.class) - private UUID id; - - @JsonView(Views.Public.class) - private Type type; - - @JsonView(Views.Internal.class) - private int internalAudit; - - public static class Type { - public long id; - public String name; - } - - public Order() { - this.id = UUID.randomUUID(); - } - - public Order(Type type) { - this(); - this.type = type; - } - - public Order(int internalAudit) { - this(); - this.type = new Type(); - this.type.id = 20; - this.type.name = "Order"; - this.internalAudit = internalAudit; - } - - public UUID getId() { - return id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Views.java b/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Views.java deleted file mode 100644 index b55997554d..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/jsonview/Views.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.jackson.general.jsonview; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Views { - public static class Public { - } - - public static class Internal extends Public { - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/reference/Author.java b/jackson/src/test/java/com/baeldung/jackson/general/reference/Author.java deleted file mode 100644 index 02dd9470d7..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/reference/Author.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.baeldung.jackson.general.reference; - -import com.fasterxml.jackson.annotation.JsonManagedReference; - -import java.util.ArrayList; -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Author extends Person { - - private List items = new ArrayList<>(); - - public Author(String firstName, String lastName) { - super(firstName, lastName); - } - - @JsonManagedReference - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/reference/Course.java b/jackson/src/test/java/com/baeldung/jackson/general/reference/Course.java deleted file mode 100644 index 251d25a517..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/reference/Course.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.baeldung.jackson.general.reference; - -import java.util.List; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Course extends Item { - - public enum Medium { - CLASSROOM, ONLINE - } - - public enum Level { - BEGINNER("Beginner", 1), INTERMEDIATE("Intermediate", 2), ADVANCED("Advanced", 3); - - private String name; - private int number; - - Level(String name, int number) { - this.name = name; - this.number = number; - } - - public String getName() { - return name; - } - } - - private float duration; - private Medium medium; - private Level level; - private List prerequisite; - - public Course(String title, Author author) { - super(title, author); - } - - public float getDuration() { - return duration; - } - - public void setDuration(float duration) { - this.duration = duration; - } - - public Medium getMedium() { - return medium; - } - - public void setMedium(Medium medium) { - this.medium = medium; - } - - public Level getLevel() { - return level; - } - - public void setLevel(Level level) { - this.level = level; - } - - public List getPrerequisite() { - return prerequisite; - } - - public void setPrerequisite(List prerequisite) { - this.prerequisite = prerequisite; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/reference/Item.java b/jackson/src/test/java/com/baeldung/jackson/general/reference/Item.java deleted file mode 100644 index 5dd66a8ca3..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/reference/Item.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.baeldung.jackson.general.reference; - -import com.fasterxml.jackson.annotation.JsonBackReference; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Item { - - private UUID id; - private String title; - - @JsonBackReference - private List authors = new ArrayList<>(); - private float price; - - public Item() { - } - - public Item(String title, Author author) { - this.id = UUID.randomUUID(); - this.title = title; - this.authors.add(author); - } - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public float getPrice() { - return price; - } - - public void setPrice(float price) { - this.price = price; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/reference/Person.java b/jackson/src/test/java/com/baeldung/jackson/general/reference/Person.java deleted file mode 100644 index 95c0b35b8b..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/reference/Person.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.baeldung.jackson.general.reference; - -import java.util.UUID; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class Person { - - private UUID id; - private String firstName; - private String lastName; - - public Person() { - } - - public Person(String firstName, String lastName) { - this.id = UUID.randomUUID(); - this.firstName = firstName; - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public UUID getId() { - return id; - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/general/reference/ReferenceUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/general/reference/ReferenceUnitTest.java deleted file mode 100644 index 7a52a69656..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/general/reference/ReferenceUnitTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.baeldung.jackson.general.reference; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.util.Collections; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class ReferenceUnitTest { - - @Test - public void whenSerializingUsingReference_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - Course course = new Course("Java EE Introduction", author); - author.setItems(Collections.singletonList(course)); - course.setAuthors(Collections.singletonList(author)); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getString("items[0].authors")).isNull(); - - /* - Without references defined it throws StackOverflowError. - Authors excluded. - - { - "id": "9c45d9b3-4888-4c24-8b74-65ef35627cd7", - "firstName": "Alex", - "lastName": "Theedom", - "items": [ - { - "id": "f8309629-d178-4d67-93a4-b513ec4a7f47", - "title": "Java EE Introduction", - "price": 0, - "duration": 0, - "medium": null, - "level": null, - "prerequisite": null - } - ] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonautodetect/JsonAutoDetectUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonautodetect/JsonAutoDetectUnitTest.java deleted file mode 100644 index a3e29776a9..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonautodetect/JsonAutoDetectUnitTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonautodetect; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonAutoDetectUnitTest { - - @Test - public void whenSerializingUsingJsonAutoDetect_thenCorrect() throws JsonProcessingException { - - // arrange - Order order = new Order(1234567890); - - // act - String result = new ObjectMapper().writeValueAsString(order); - - // assert - assertThat(from(result).getInt("internalAudit")).isEqualTo(1234567890); - - /* - With @JsonAutoDetect - { - "id": "c94774d9-de8f-4244-85d5-624bd3a4567a", - "type": { - "id": 20, - "name": "Order" - }, - "internalAudit": 1234567890 - } - - Without @JsonAutoDetect - { - "id": "c94774d9-de8f-4244-85d5-624bd3a4567a", - "type": { - "id": 20, - "name": "Order" - } - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignore/JsonIgnoreUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignore/JsonIgnoreUnitTest.java deleted file mode 100644 index 89e3c15f04..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignore/JsonIgnoreUnitTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignore; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonIgnoreUnitTest { - - @Test - public void whenSerializingUsingJsonIgnore_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getString("firstName")).isEqualTo("Alex"); - assertThat(from(result).getString("lastName")).isEqualTo("Theedom"); - assertThat(from(result).getString("id")).isNull(); - - /* - { - "firstName": "Alex", - "lastName": "Theedom", - "items": [] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoreproperties/JsonIgnorePropertiesUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoreproperties/JsonIgnorePropertiesUnitTest.java deleted file mode 100644 index be20d242c9..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoreproperties/JsonIgnorePropertiesUnitTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignoreproperties; - -import com.baeldung.jackson.domain.Author; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonIgnorePropertiesUnitTest { - - @Test - public void whenSerializingUsingJsonIgnoreProperties_thenCorrect() throws JsonProcessingException { - - // arrange - Course course = new Course("Spring Security", new Author("Eugen", "Paraschiv")); - course.setMedium(Course.Medium.ONLINE); - - // act - String result = new ObjectMapper().writeValueAsString(course); - - // assert - assertThat(from(result).getString("medium")).isNull(); - - /* - { - "id": "ef0c8d2b-b088-409e-905c-95ac88dc0ed0", - "title": "Spring Security", - "authors": [ - { - "id": "47a4f498-b0f3-4daf-909f-d2c35a0fe3c2", - "firstName": "Eugen", - "lastName": "Paraschiv", - "items": [] - } - ], - "price": 0, - "duration": 0, - "level": null, - "prerequisite": null - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoretype/JsonIgnoreTypeUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoretype/JsonIgnoreTypeUnitTest.java deleted file mode 100644 index e8917ff526..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsonignoretype/JsonIgnoreTypeUnitTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.baeldung.jackson.inclusion.jsonignoretype; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonIgnoreTypeUnitTest { - - @Test - public void whenSerializingUsingJsonIgnoreType_thenCorrect() throws JsonProcessingException { - - // arrange - Order.Type type = new Order.Type(); - type.id = 10; - type.name = "Pre-order"; - - Order order = new Order(type); - - // act - String result = new ObjectMapper().writeValueAsString(order); - - // assert - assertThat(from(result).getString("id")).isNotNull(); - assertThat(from(result).getString("type")).isNull(); - - /* - {"id":"ac2428da-523e-443c-a18a-4ea4d2791fea"} - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsoninclude/JsonIncludeUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/inclusion/jsoninclude/JsonIncludeUnitTest.java deleted file mode 100644 index ca4c4b751a..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/inclusion/jsoninclude/JsonIncludeUnitTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.baeldung.jackson.inclusion.jsoninclude; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonIncludeUnitTest { - - @Test - public void whenSerializingUsingJsonInclude_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", null); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getString("firstName")).isEqualTo("Alex"); - assertThat(result).doesNotContain("lastName"); - - /* - { - "id": "e8bb4802-6e0c-4fa5-9f68-c233272399cd", - "firstName": "Alex", - "items": [] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/custom/CustomUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/miscellaneous/custom/CustomUnitTest.java deleted file mode 100644 index 8f90c02875..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/custom/CustomUnitTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.baeldung.jackson.miscellaneous.custom; - -import com.baeldung.jackson.domain.Author; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class CustomUnitTest { - - @Test - public void whenSerializingUsingCustom_thenCorrect() throws JsonProcessingException { - - // arrange - Course course = new Course("Spring Security", new Author("Eugen", "Paraschiv")); - course.setMedium(Course.Medium.ONLINE); - - // act - String result = new ObjectMapper().writeValueAsString(course); - - // assert - assertThat(from(result).getString("title")).isEqualTo("Spring Security"); - - /* - { - "title": "Spring Security", - "price": 0, - "id": "7dfd4db9-1175-432f-a53b-687423f7bb9b", - "duration": 0, - "authors": [ - { - "id": "da0738f6-033c-4974-8d87-92820e5ccf27", - "firstName": "Eugen", - "lastName": "Paraschiv", - "items": [] - } - ], - "medium": "ONLINE" - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/disable/DisableUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/miscellaneous/disable/DisableUnitTest.java deleted file mode 100644 index f9bc14291e..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/disable/DisableUnitTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.baeldung.jackson.miscellaneous.disable; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class DisableUnitTest { - - @Test - public void whenSerializingUsingDisable_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - ObjectMapper mapper = new ObjectMapper(); - String result = mapper.writeValueAsString(author); - - // assert - assertThat(from(result).getList("items")).isNull(); - - /* - { - "lastName": "Theedom", - "firstName": "Alex", - "id": "de4afbb4-b24d-45c8-bb00-fd6b9acb42f1" - } - */ - - // act - mapper = new ObjectMapper(); - mapper.disable(MapperFeature.USE_ANNOTATIONS); - result = mapper.writeValueAsString(author); - - // assert - assertThat(from(result).getList("items")).isNotNull(); - - /* - { - "id": "81e6ed72-6b27-4fe9-a36f-e3171c5b55ef", - "firstName": "Alex", - "lastName": "Theedom", - "items": [] - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/mixin/MixInUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/miscellaneous/mixin/MixInUnitTest.java deleted file mode 100644 index 732cda58d0..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/miscellaneous/mixin/MixInUnitTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.baeldung.jackson.miscellaneous.mixin; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.util.List; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class MixInUnitTest { - - @Test - public void whenSerializingUsingMixIn_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getList("items")).isNotNull(); - - /* - { - "id": "f848b076-00a4-444a-a50b-328595dd9bf5", - "firstName": "Alex", - "lastName": "Theedom", - "items": [] - } - */ - - ObjectMapper mapper = new ObjectMapper(); - mapper.addMixIn(List.class, IgnoreListMixIn.class); - - result = mapper.writeValueAsString(author); - - // assert - assertThat(from(result).getList("items")).isNull(); - - /* - { - "id": "9ffefb7d-e56f-447c-9009-e92e142f8347", - "firstName": "Alex", - "lastName": "Theedom" - } - */ - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/polymorphism/PolymorphismUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/polymorphism/PolymorphismUnitTest.java deleted file mode 100644 index e922cf9976..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/polymorphism/PolymorphismUnitTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.baeldung.jackson.polymorphism; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.io.IOException; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class PolymorphismUnitTest { - - @Test - public void whenSerializingUsingPolymorphism_thenCorrect() throws JsonProcessingException { - - // arrange - Order.InternalType internalType = new Order.InternalType(); - internalType.id = 250; - internalType.name = "staff"; - - Order order = new Order(internalType); - - // act - String result = new ObjectMapper().writeValueAsString(order); - - // assert - assertThat(from(result).getString("type.ordertype")).isEqualTo("internal"); - - /* - { - "id": "7fc898e3-b4e7-41b0-8ffa-664cf3663f2e", - "type": { - "ordertype": "internal", - "id": 250, - "name": "staff" - } - } - */ - - } - - @Test - public void whenDeserializingPolymorphic_thenCorrect() throws IOException { - - // arrange - String orderJson = "{\"type\":{\"ordertype\":\"internal\",\"id\":100,\"name\":\"directors\"}}"; - - // act - Order order = new ObjectMapper().readerFor(Order.class) - .readValue(orderJson); - - // assert - assertThat(from(orderJson).getString("type.ordertype")).isEqualTo("internal"); - assertThat(((Order.InternalType) order.getType()).name).isEqualTo("directors"); - assertThat(((Order.InternalType) order.getType()).id).isEqualTo(100); - assertThat(order.getType() - .getClass()).isEqualTo(Order.InternalType.class); - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonanygetter/JsonAnyGetterUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonanygetter/JsonAnyGetterUnitTest.java deleted file mode 100644 index 7a786e0bd6..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonanygetter/JsonAnyGetterUnitTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.jackson.serialization.jsonanygetter; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.util.Map; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonAnyGetterUnitTest { - - @Test - public void whenSerializingUsingJsonAnyGetter_thenCorrect() throws JsonProcessingException { - - // arrange - Inventory inventory = new Inventory(); - Map countryDeliveryCost = inventory.getCountryDeliveryCost(); - inventory.setLocation("France"); - - countryDeliveryCost.put("USA", 10.00f); - countryDeliveryCost.put("UK", 15.00f); - - // act - String result = new ObjectMapper().writeValueAsString(inventory); - - // assert - assertThat(from(result).getString("location")).isEqualTo("France"); - assertThat(from(result).getFloat("USA")).isEqualTo(10.00f); - assertThat(from(result).getFloat("UK")).isEqualTo(15.00f); - - /* - { - "location": "France", - "USA": 10, - "UK": 15 - } - */ - - } - -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsongetter/JsonGetterUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsongetter/JsonGetterUnitTest.java deleted file mode 100644 index 4bc9c51e83..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsongetter/JsonGetterUnitTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.baeldung.jackson.serialization.jsongetter; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonGetterUnitTest { - - @Test - public void whenSerializingUsingJsonGetter_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(from(result).getList("publications")).isNotNull(); - assertThat(from(result).getList("items")).isNull(); - - /* - { - "firstName": "Alex", - "lastName": "Theedom", - "publications": [] - } - */ - - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonpropertyorder/JsonPropertyOrderUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonpropertyorder/JsonPropertyOrderUnitTest.java deleted file mode 100644 index 77ef85ed73..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonpropertyorder/JsonPropertyOrderUnitTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.baeldung.jackson.serialization.jsonpropertyorder; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonPropertyOrderUnitTest { - - @Test - public void whenSerializingUsingJsonPropertyOrder_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - String result = new ObjectMapper().writeValueAsString(author); - - // assert - assertThat(result, matchesJsonSchemaInClasspath("author-jsonpropertyorder-schema.json")); - - // NOTE: property order is not enforced by the JSON specification. - - /* - { - "items": [], - "firstName": "Alex", - "lastName": "Theedom", - "id": "fd277638-9b6e-49f7-81c1-bc52f165245b" - } - */ - - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrawvalue/JsonRawValueUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrawvalue/JsonRawValueUnitTest.java deleted file mode 100644 index f0f0913aee..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrawvalue/JsonRawValueUnitTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.baeldung.jackson.serialization.jsonrawvalue; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonRawValueUnitTest { - - @Test - public void whenSerializingUsingJsonRawValue_thenCorrect() throws JsonProcessingException { - - // arrange - String customerConfig = "{\"colour\":\"red\",\"device\":\"mobile\",\"orientation\":\"landscape\"}"; - Customer customer = new Customer("Alex", "Theedom"); - customer.setConfiguration("{\"colour\":\"red\",\"device\":\"mobile\",\"orientation\":\"landscape\"}"); - - // act - String result = new ObjectMapper().writeValueAsString(customer); - - // assert - assertThat(result.contains(customerConfig)); - - /* - { - "firstName": "Alex", - "lastName": "Theedom", - "publications": [] - } - */ - - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrootname/JsonRootNameUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrootname/JsonRootNameUnitTest.java deleted file mode 100644 index cb54e63079..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonrootname/JsonRootNameUnitTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.baeldung.jackson.serialization.jsonrootname; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import org.junit.Test; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonRootNameUnitTest { - - @Test - public void whenSerializingUsingJsonRootName_thenCorrect() throws JsonProcessingException { - - // arrange - Author author = new Author("Alex", "Theedom"); - - // act - ObjectMapper mapper = new ObjectMapper(); - mapper.enable(SerializationFeature.WRAP_ROOT_VALUE); - String result = mapper.writeValueAsString(author); - - // assert - assertThat(from(result).getString("writer.firstName")).isEqualTo("Alex"); - assertThat(from(result).getString("author.firstName")).isNull(); - - /* - { - "writer": { - "id": "0f50dca6-3dd7-4801-a334-fd1614276389", - "firstName": "Alex", - "lastName": "Theedom", - "items": [] - } - } - */ - - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonserialize/JsonSerializeUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonserialize/JsonSerializeUnitTest.java deleted file mode 100644 index cca018e78d..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonserialize/JsonSerializeUnitTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.baeldung.jackson.serialization.jsonserialize; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import java.text.ParseException; -import java.text.SimpleDateFormat; - -import static io.restassured.path.json.JsonPath.from; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonSerializeUnitTest { - - @Test - public void whenSerializingUsingJsonSerialize_thenCorrect() throws JsonProcessingException, ParseException { - - // arrange - Author joshuaBloch = new Author("Joshua", "Bloch"); - Book book = new Book("Effective Java", joshuaBloch); - - SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - String toParse = "25-12-2017 13:30:25"; - book.setPublished(df.parse(toParse)); - - // act - String result = new ObjectMapper().writeValueAsString(book); - - // assert - assertThat(from(result).getString("published")).isEqualTo(toParse); - - /* - { - "id": "957c43f2-fa2e-42f9-bf75-6e3d5bb6960a", - "title": "Effective Java", - "authors": [ - { - "id": "9bcd817d-0141-42e6-8f04-e5aaab0980b6", - "firstName": "Joshua", - "lastName": "Bloch", - "items": [] - } - ], - "price": 0, - "published": "25-12-2017 13:30:25", - "pages": null, - "isbn": null - } - */ - - } -} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonvalue/JsonValueUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/jsonvalue/JsonValueUnitTest.java deleted file mode 100644 index 465daf13f5..0000000000 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/jsonvalue/JsonValueUnitTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.jackson.serialization.jsonvalue; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code github.com/readlearncode - * - * @author Alex Theedom www.readlearncode.com - * @version 1.0 - */ -public class JsonValueUnitTest { - - @Test - public void whenSerializingUsingJsonValue_thenCorrect() throws JsonProcessingException { - - // act - String result = new ObjectMapper().writeValueAsString(Course.Level.ADVANCED); - - // assert - assertThat(result).isEqualTo("\"Advanced\""); - - } -} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java index 935777bad1..ee11f8f20e 100644 --- a/jackson/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java +++ b/jackson/src/test/java/com/baeldung/jackson/test/JacksonAnnotationUnitTest.java @@ -14,6 +14,7 @@ import java.util.TimeZone; import org.junit.Test; +import com.baeldung.jackson.annotation.AliasBean; import com.baeldung.jackson.annotation.BeanWithCreator; import com.baeldung.jackson.annotation.BeanWithCustomAnnotation; import com.baeldung.jackson.annotation.BeanWithFilter; @@ -36,6 +37,7 @@ import com.baeldung.jackson.date.EventWithSerializer; import com.baeldung.jackson.dtos.MyMixInForIgnoreType; import com.baeldung.jackson.dtos.withEnum.DistanceEnumWithValue; import com.baeldung.jackson.exception.UserWithRoot; +import com.baeldung.jackson.exception.UserWithRootNamespace; import com.baeldung.jackson.jsonview.Item; import com.baeldung.jackson.jsonview.Views; import com.fasterxml.jackson.core.JsonProcessingException; @@ -46,6 +48,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; public class JacksonAnnotationUnitTest { @@ -372,5 +375,45 @@ public class JacksonAnnotationUnitTest { assertThat(result, containsString("1")); assertThat(result, containsString("name")); } + + @Test + public void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException { + + // arrange + String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}"; + + // act + AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json); + + // assert + assertThat(aliasBean.getFirstName(), is("John")); + } + + @Test + public void whenSerializingUsingXMLRootNameWithNameSpace_thenCorrect() throws JsonProcessingException { + + // arrange + UserWithRootNamespace author = new UserWithRootNamespace(1, "John"); + + // act + ObjectMapper mapper = new XmlMapper(); + mapper = mapper.enable(SerializationFeature.WRAP_ROOT_VALUE).enable(SerializationFeature.INDENT_OUTPUT); + String result = mapper.writeValueAsString(author); + + // assert + assertThat(result, containsString("")); + + /* + + 3006b44a-cf62-4cfe-b3d8-30dc6c46ea96 + 1 + John + + + */ + + } + + } diff --git a/jackson/src/test/java/com/baeldung/jackson/xml/XMLSerializeDeserializeUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/xml/XMLSerializeDeserializeUnitTest.java index 0e2a52e75c..1d430e9758 100644 --- a/jackson/src/test/java/com/baeldung/jackson/xml/XMLSerializeDeserializeUnitTest.java +++ b/jackson/src/test/java/com/baeldung/jackson/xml/XMLSerializeDeserializeUnitTest.java @@ -2,19 +2,25 @@ package com.baeldung.jackson.xml; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; import org.junit.Test; +import com.baeldung.jackson.dtos.Address; +import com.baeldung.jackson.dtos.Person; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.dataformat.xml.XmlMapper; -import com.fasterxml.jackson.annotation.JsonProperty; public class XMLSerializeDeserializeUnitTest { @@ -49,24 +55,76 @@ public class XMLSerializeDeserializeUnitTest { assertTrue(value.getX() == 1 && value.getY() == 2); } - @Test + @Test public void whenJavaGotFromXmlStrWithCapitalElem_thenCorrect() throws IOException { XmlMapper xmlMapper = new XmlMapper(); - SimpleBeanForCapitalizedFields value = xmlMapper. - readValue("12", - SimpleBeanForCapitalizedFields.class); + SimpleBeanForCapitalizedFields value = xmlMapper.readValue("12", SimpleBeanForCapitalizedFields.class); assertTrue(value.getX() == 1 && value.getY() == 2); } @Test public void whenJavaSerializedToXmlFileWithCapitalizedField_thenCorrect() throws IOException { XmlMapper xmlMapper = new XmlMapper(); - xmlMapper.writeValue(new File("target/simple_bean_capitalized.xml"), - new SimpleBeanForCapitalizedFields()); + xmlMapper.writeValue(new File("target/simple_bean_capitalized.xml"), new SimpleBeanForCapitalizedFields()); File file = new File("target/simple_bean_capitalized.xml"); assertNotNull(file); } + @Test + public void whenJavaDeserializedFromXmlFile_thenCorrect() throws IOException { + XmlMapper xmlMapper = new XmlMapper(); + + String xml = "RohanDaye99110347319911033478
1Name1City1
2Name2City2
"; + Person value = xmlMapper.readValue(xml, Person.class); + + assertTrue(value.getAddress() + .get(0) + .getCity() + .equalsIgnoreCase("city1") + && value.getAddress() + .get(1) + .getCity() + .equalsIgnoreCase("city2")); + } + + @Test + public void whenJavaSerializedToXmlFile_thenSuccess() throws IOException { + XmlMapper xmlMapper = new XmlMapper(); + + String expectedXml = "RohanDaye99110347319911033478
1Name1City1
2Name2City2
"; + + Person person = new Person(); + + person.setFirstName("Rohan"); + person.setLastName("Daye"); + + List ph = new ArrayList<>(); + ph.add("9911034731"); + ph.add("9911033478"); + person.setPhoneNumbers(ph); + + List
addresses = new ArrayList<>(); + + Address address1 = new Address(); + address1.setStreetNumber("1"); + address1.setStreetName("Name1"); + address1.setCity("City1"); + + Address address2 = new Address(); + address2.setStreetNumber("2"); + address2.setStreetName("Name2"); + address2.setCity("City2"); + + addresses.add(address1); + addresses.add(address2); + + person.setAddress(addresses); + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + xmlMapper.writeValue(byteArrayOutputStream, person); + assertEquals(expectedXml, byteArrayOutputStream.toString()); + } + private static String inputStreamToString(InputStream is) throws IOException { BufferedReader br; StringBuilder sb = new StringBuilder(); @@ -103,10 +161,10 @@ class SimpleBean { } -class SimpleBeanForCapitalizedFields { - @JsonProperty("X") - private int x = 1; - private int y = 2; +class SimpleBeanForCapitalizedFields { + @JsonProperty("X") + private int x = 1; + private int y = 2; public int getX() { return x; diff --git a/java-collections-maps-2/pom.xml b/java-collections-maps-2/pom.xml new file mode 100644 index 0000000000..b025c5e32d --- /dev/null +++ b/java-collections-maps-2/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + java-collections-maps-2 + 0.1.0-SNAPSHOT + java-collections-maps-2 + jar + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + org.eclipse.collections + eclipse-collections + ${eclipse-collections.version} + + + net.sf.trove4j + trove4j + 3.0.2 + + + it.unimi.dsi + fastutil + 8.1.0 + + + colt + colt + 1.2.0 + + + + + 8.2.0 + + + \ No newline at end of file diff --git a/java-collections-maps-2/src/main/java/com/baeldung/map/PrimitiveMaps.java b/java-collections-maps-2/src/main/java/com/baeldung/map/PrimitiveMaps.java new file mode 100644 index 0000000000..d835950c68 --- /dev/null +++ b/java-collections-maps-2/src/main/java/com/baeldung/map/PrimitiveMaps.java @@ -0,0 +1,69 @@ +package com.baeldung.map; + +import cern.colt.map.AbstractIntDoubleMap; +import cern.colt.map.OpenIntDoubleHashMap; +import gnu.trove.map.TDoubleIntMap; +import gnu.trove.map.hash.TDoubleIntHashMap; +import it.unimi.dsi.fastutil.ints.Int2BooleanMap; +import it.unimi.dsi.fastutil.ints.Int2BooleanOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2BooleanSortedMap; +import it.unimi.dsi.fastutil.ints.Int2BooleanSortedMaps; +import org.eclipse.collections.api.map.primitive.ImmutableIntIntMap; +import org.eclipse.collections.api.map.primitive.MutableIntIntMap; +import org.eclipse.collections.api.map.primitive.MutableObjectDoubleMap; +import org.eclipse.collections.impl.factory.primitive.IntIntMaps; +import org.eclipse.collections.impl.factory.primitive.ObjectDoubleMaps; + +public class PrimitiveMaps { + + public static void main(String[] args) { + + eclipseCollectionsMap(); + troveMap(); + coltMap(); + fastutilMap(); + } + + private static void fastutilMap() { + Int2BooleanMap int2BooleanMap = new Int2BooleanOpenHashMap(); + int2BooleanMap.put(1, true); + int2BooleanMap.put(7, false); + int2BooleanMap.put(4, true); + + boolean value = int2BooleanMap.get(1); + + Int2BooleanSortedMap int2BooleanSorted = Int2BooleanSortedMaps.EMPTY_MAP; + } + + private static void coltMap() { + AbstractIntDoubleMap map = new OpenIntDoubleHashMap(); + map.put(1, 4.5); + double value = map.get(1); + } + + private static void eclipseCollectionsMap() { + MutableIntIntMap mutableIntIntMap = IntIntMaps.mutable.empty(); + mutableIntIntMap.addToValue(1, 1); + + ImmutableIntIntMap immutableIntIntMap = IntIntMaps.immutable.empty(); + + MutableObjectDoubleMap dObject = ObjectDoubleMaps.mutable.empty(); + dObject.addToValue("price", 150.5); + dObject.addToValue("quality", 4.4); + dObject.addToValue("stability", 0.8); + } + + private static void troveMap() { + double[] doubles = new double[] {1.2, 4.5, 0.3}; + int[] ints = new int[] {1, 4, 0}; + + TDoubleIntMap doubleIntMap = new TDoubleIntHashMap(doubles, ints); + + doubleIntMap.put(1.2, 22); + doubleIntMap.put(4.5, 16); + + doubleIntMap.adjustValue(1.2, 1); + doubleIntMap.adjustValue(4.5, 4); + doubleIntMap.adjustValue(0.3, 7); + } +} diff --git a/java-collections-maps/README.md b/java-collections-maps/README.md index 5d65e961de..2eeb2c8843 100644 --- a/java-collections-maps/README.md +++ b/java-collections-maps/README.md @@ -20,3 +20,4 @@ - [Comparing Two HashMaps in Java](https://www.baeldung.com/java-compare-hashmaps) - [Immutable Map Implementations in Java](https://www.baeldung.com/java-immutable-maps) - [Map to String Conversion in Java](https://www.baeldung.com/java-map-to-string-conversion) +- [Guide to Apache Commons MultiValuedMap](https://www.baeldung.com/apache-commons-multi-valued-map) diff --git a/java-collections-maps/src/test/java/com/baeldung/java/map/MultiValuedMapUnitTest.java b/java-collections-maps/src/test/java/com/baeldung/java/map/MultiValuedMapUnitTest.java index b02b67f685..b3aaf8925f 100644 --- a/java-collections-maps/src/test/java/com/baeldung/java/map/MultiValuedMapUnitTest.java +++ b/java-collections-maps/src/test/java/com/baeldung/java/map/MultiValuedMapUnitTest.java @@ -9,8 +9,10 @@ import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import org.apache.commons.collections4.MultiMapUtils; +import org.apache.commons.collections4.MultiSet; import org.apache.commons.collections4.MultiValuedMap; import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; import org.apache.commons.collections4.multimap.HashSetValuedHashMap; @@ -65,25 +67,28 @@ public class MultiValuedMapUnitTest { @Test public void givenMultiValuesMap_whenUsingKeysMethod_thenReturningAllKeys() { MultiValuedMap map = new ArrayListValuedHashMap<>(); - map.put("fruits", "apple"); map.put("fruits", "orange"); map.put("vehicles", "car"); map.put("vehicles", "bike"); - assertThat(((Collection) map.keys())).contains("fruits", "vehicles"); + MultiSet keys = map.keys(); + + assertThat((keys)).contains("fruits", "vehicles"); + } @Test public void givenMultiValuesMap_whenUsingKeySetMethod_thenReturningAllKeys() { MultiValuedMap map = new ArrayListValuedHashMap<>(); - map.put("fruits", "apple"); map.put("fruits", "orange"); map.put("vehicles", "car"); map.put("vehicles", "bike"); - assertThat((Collection) map.keySet()).contains("fruits", "vehicles"); + Set keys = map.keySet(); + + assertThat(keys).contains("fruits", "vehicles"); } diff --git a/java-dates-2/.gitignore b/java-dates-2/.gitignore new file mode 100644 index 0000000000..6471aabbcf --- /dev/null +++ b/java-dates-2/.gitignore @@ -0,0 +1,29 @@ +*.class + +0.* + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* +.resourceCache + +# Packaged files # +*.jar +*.war +*.ear + +# Files generated by integration tests +*.txt +backup-pom.xml +/bin/ +/temp + +#IntelliJ specific +.idea/ +*.iml + +#jenv +.java-version \ No newline at end of file diff --git a/java-dates-2/pom.xml b/java-dates-2/pom.xml new file mode 100644 index 0000000000..c2464ed47f --- /dev/null +++ b/java-dates-2/pom.xml @@ -0,0 +1,55 @@ + + 4.0.0 + com.baeldung + java-dates-2 + 0.1.0-SNAPSHOT + jar + java-dates-2 + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + java-dates-2 + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + + 3.6.1 + 1.9 + 1.9 + + diff --git a/java-dates-2/src/test/java/com/baeldung/xmlgregoriancalendar/XmlGregorianCalendarConverterUnitTest.java b/java-dates-2/src/test/java/com/baeldung/xmlgregoriancalendar/XmlGregorianCalendarConverterUnitTest.java new file mode 100644 index 0000000000..b221c04199 --- /dev/null +++ b/java-dates-2/src/test/java/com/baeldung/xmlgregoriancalendar/XmlGregorianCalendarConverterUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.xmlgregoriancalendar; + +import org.junit.Test; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; +import java.time.LocalDate; + +import static org.assertj.core.api.Assertions.assertThat; + +public class XmlGregorianCalendarConverterUnitTest { + + @Test + public void fromLocalDateToXMLGregorianCalendar() throws DatatypeConfigurationException { + LocalDate localDate = LocalDate.of(2017, 4, 25); + XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(localDate.toString()); + + assertThat(xmlGregorianCalendar.getYear()).isEqualTo(localDate.getYear()); + assertThat(xmlGregorianCalendar.getMonth()).isEqualTo(localDate.getMonthValue()); + assertThat(xmlGregorianCalendar.getDay()).isEqualTo(localDate.getDayOfMonth()); + assertThat(xmlGregorianCalendar.getTimezone()).isEqualTo(DatatypeConstants.FIELD_UNDEFINED); + } + + @Test + public void fromXMLGregorianCalendarToLocalDate() throws DatatypeConfigurationException { + XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar("2017-04-25"); + LocalDate localDate = LocalDate.of(xmlGregorianCalendar.getYear(), xmlGregorianCalendar.getMonth(), xmlGregorianCalendar.getDay()); + + assertThat(localDate.getYear()).isEqualTo(xmlGregorianCalendar.getYear()); + assertThat(localDate.getMonthValue()).isEqualTo(xmlGregorianCalendar.getMonth()); + assertThat(localDate.getDayOfMonth()).isEqualTo(xmlGregorianCalendar.getDay()); + } + +} diff --git a/java-dates/pom.xml b/java-dates/pom.xml index 8dd5ad675e..d4f690d894 100644 --- a/java-dates/pom.xml +++ b/java-dates/pom.xml @@ -76,7 +76,6 @@ 3.5 - 1.16.12 2.10 3.6.1 diff --git a/java-ee-8-security-api/pom.xml b/java-ee-8-security-api/pom.xml index ad33c74ad3..0cce84e5f2 100644 --- a/java-ee-8-security-api/pom.xml +++ b/java-ee-8-security-api/pom.xml @@ -58,6 +58,13 @@ + + app-auth-basic-store-db + app-auth-form-store-ldap + app-auth-custom-form-store-custom + app-auth-custom-no-store + + 9080 9443 @@ -70,11 +77,4 @@ 3.2.2 - - app-auth-basic-store-db - app-auth-form-store-ldap - app-auth-custom-form-store-custom - app-auth-custom-no-store - - diff --git a/java-lite/pom.xml b/java-lite/pom.xml index b261e521a1..ce6e838d92 100644 --- a/java-lite/pom.xml +++ b/java-lite/pom.xml @@ -95,7 +95,6 @@ 1.15 5.1.45 1.7.0 - 2.9.7 1.15 diff --git a/java-streams-2/README.md b/java-streams-2/README.md new file mode 100644 index 0000000000..83ef97686f --- /dev/null +++ b/java-streams-2/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: +- [Guide to Stream.reduce()](https://www.baeldung.com/java-stream-reduce) + diff --git a/java-streams-2/pom.xml b/java-streams-2/pom.xml new file mode 100644 index 0000000000..cd89a1a80f --- /dev/null +++ b/java-streams-2/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + com.baeldung.javastreams2 + javastreams2 + 1.0 + jar + + + org.openjdk.jmh + jmh-core + 1.21 + + + org.openjdk.jmh + jmh-generator-annprocess + 1.21 + + + junit + junit + 4.12 + test + jar + + + org.assertj + assertj-core + 3.11.1 + test + + + Stream Reduce + + UTF-8 + 1.8 + 1.8 + + \ No newline at end of file diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java b/java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java new file mode 100644 index 0000000000..79c557524d --- /dev/null +++ b/java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java @@ -0,0 +1,39 @@ +package com.baeldung.reduce.application; + +import com.baeldung.reduce.entities.User; +import com.baeldung.reduce.utilities.NumberUtils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Application { + + public static void main(String[] args) { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result1 = numbers.stream().reduce(0, (subtotal, element) -> subtotal + element); + System.out.println(result1); + + int result2 = numbers.stream().reduce(0, Integer::sum); + System.out.println(result2); + + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result3 = letters.stream().reduce("", (partialString, element) -> partialString + element); + System.out.println(result3); + + String result4 = letters.stream().reduce("", String::concat); + System.out.println(result4); + + String result5 = letters.stream().reduce("", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase()); + System.out.println(result5); + + List users = Arrays.asList(new User("John", 30), new User("Julie", 35)); + int result6 = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + System.out.println(result6); + + String result7 = letters.parallelStream().reduce("", String::concat); + System.out.println(result7); + + int result8 = users.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + System.out.println(result8); + } +} diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java b/java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java new file mode 100644 index 0000000000..af4a9276a9 --- /dev/null +++ b/java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java @@ -0,0 +1,52 @@ +package com.baeldung.reduce.benchmarks; + +import com.baeldung.reduce.entities.User; +import java.util.ArrayList; +import java.util.List; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Thread) +@BenchmarkMode(Mode.AverageTime) +public class JMHStreamReduceBenchMark { + + private final List userList = createUsers(); + + public static void main(String[] args) throws RunnerException { + + Options options = new OptionsBuilder() + .include(JMHStreamReduceBenchMark.class.getSimpleName()).threads(1) + .forks(1).shouldFailOnError(true).shouldDoGC(true) + .jvmArgs("-server").build(); + new Runner(options).run(); + } + + private List createUsers() { + List users = new ArrayList<>(); + for (int i = 0; i <= 1000000; i++) { + users.add(new User("John" + i, i)); + } + return users; + } + + @Benchmark + public Integer executeReduceOnParallelizedStream() { + return this.userList + .parallelStream() + .reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + } + + @Benchmark + public Integer executeReduceOnSequentialStream() { + return this.userList + .stream() + .reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + } +} diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java b/java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java new file mode 100644 index 0000000000..a17c6a02b6 --- /dev/null +++ b/java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java @@ -0,0 +1,25 @@ +package com.baeldung.reduce.entities; + +public class User { + + private final String name; + private final int age; + + public User(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + @Override + public String toString() { + return "User{" + "name=" + name + ", age=" + age + '}'; + } +} diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java b/java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java new file mode 100644 index 0000000000..a7a4b8df29 --- /dev/null +++ b/java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java @@ -0,0 +1,52 @@ +package com.baeldung.reduce.utilities; + +import java.util.List; +import java.util.function.BiFunction; +import java.util.logging.Level; +import java.util.logging.Logger; + +public abstract class NumberUtils { + + private static final Logger LOGGER = Logger.getLogger(NumberUtils.class.getName()); + + public static int divideListElements(List values, Integer divider) { + return values.stream() + .reduce(0, (a, b) -> { + try { + return a / divider + b / divider; + } catch (ArithmeticException e) { + LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero"); + } + return 0; + }); + } + + public static int divideListElementsWithExtractedTryCatchBlock(List values, int divider) { + return values.stream().reduce(0, (a, b) -> divide(a, divider) + divide(b, divider)); + } + + public static int divideListElementsWithApplyFunctionMethod(List values, int divider) { + BiFunction division = (a, b) -> a / b; + return values.stream().reduce(0, (a, b) -> applyFunction(division, a, divider) + applyFunction(division, b, divider)); + } + + private static int divide(int value, int factor) { + int result = 0; + try { + result = value / factor; + } catch (ArithmeticException e) { + LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero"); + } + return result; + } + + private static int applyFunction(BiFunction function, int a, int b) { + try { + return function.apply(a, b); + } + catch(Exception e) { + LOGGER.log(Level.INFO, "Exception thrown!"); + } + return 0; + } +} diff --git a/java-streams-2/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java b/java-streams-2/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java new file mode 100644 index 0000000000..564d614017 --- /dev/null +++ b/java-streams-2/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java @@ -0,0 +1,79 @@ +package com.baeldung.reduce.tests; + +import com.baeldung.reduce.entities.User; +import com.baeldung.reduce.utilities.NumberUtils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; + +public class StreamReduceUnitTest { + + @Test + public void givenIntegerList_whenReduceWithSumAccumulatorLambda_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result = numbers.stream().reduce(0, (subtotal, element) -> subtotal + element); + assertThat(result).isEqualTo(21); + } + + @Test + public void givenIntegerList_whenReduceWithSumAccumulatorMethodReference_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result = numbers.stream().reduce(0, Integer::sum); + assertThat(result).isEqualTo(21); + } + + @Test + public void givenStringList_whenReduceWithConcatenatorAccumulatorLambda_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.stream().reduce("", (partialString, element) -> partialString + element); + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenStringList_whenReduceWithConcatenatorAccumulatorMethodReference_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.stream().reduce("", String::concat); + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenStringList_whenReduceWithUppercaseConcatenatorAccumulator_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.stream().reduce("", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase()); + assertThat(result).isEqualTo("ABCDE"); + } + + @Test + public void givenUserList_whenReduceWithAgeAccumulatorAndSumCombiner_thenCorrect() { + List users = Arrays.asList(new User("John", 30), new User("Julie", 35)); + int result = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + assertThat(result).isEqualTo(65); + } + + @Test + public void givenStringList_whenReduceWithParallelStream_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.parallelStream().reduce("", String::concat); + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenNumberUtilsClass_whenCalledDivideListElements_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + assertThat(NumberUtils.divideListElements(numbers, 1)).isEqualTo(21); + } + + @Test + public void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlock_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 1)).isEqualTo(21); + } + + @Test + public void givenStream_whneCalleddivideListElementsWithApplyFunctionMethod_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + assertThat(NumberUtils.divideListElementsWithApplyFunctionMethod(numbers, 1)).isEqualTo(21); + } +} diff --git a/java-streams/README.md b/java-streams/README.md index 15ea1c742a..e294e5aee1 100644 --- a/java-streams/README.md +++ b/java-streams/README.md @@ -3,7 +3,7 @@ ## Java Streams Cookbooks and Examples ### Relevant Articles: -- [Java 8 Streams Advanced](http://www.baeldung.com/java-8-streams) +- [The Java 8 Stream API Tutorial](http://www.baeldung.com/java-8-streams) - [Introduction to Java 8 Streams](http://www.baeldung.com/java-8-streams-introduction) - [Java 8 and Infinite Streams](http://www.baeldung.com/java-inifinite-streams) - [Java 8 Stream findFirst() vs. findAny()](http://www.baeldung.com/java-stream-findfirst-vs-findany) @@ -17,3 +17,4 @@ - [Java Stream Filter with Lambda Expression](https://www.baeldung.com/java-stream-filter-lambda) - [Counting Matches on a Stream Filter](https://www.baeldung.com/java-stream-filter-count) - [Java 8 Streams peek() API](https://www.baeldung.com/java-streams-peek-api) +- [Working With Maps Using Streams](https://www.baeldung.com/java-maps-streams) diff --git a/java-streams/pom.xml b/java-streams/pom.xml index 0de1a424d6..00384eeead 100644 --- a/java-streams/pom.xml +++ b/java-streams/pom.xml @@ -108,7 +108,6 @@ 1.21 3.5 - 1.16.12 0.9.0 1.15 0.6.5 diff --git a/java-streams/src/main/java/com/baeldung/reduce/application/Application.java b/java-streams/src/main/java/com/baeldung/reduce/application/Application.java new file mode 100644 index 0000000000..b101c86780 --- /dev/null +++ b/java-streams/src/main/java/com/baeldung/reduce/application/Application.java @@ -0,0 +1,70 @@ +package com.baeldung.reduce.application; + +import com.baeldung.reduce.entities.User; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Warmup; + +public class Application { + + public static void main(String[] args) throws Exception { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result1 = numbers.stream().reduce(0, (subtotal, element) -> subtotal + element); + System.out.println(result1); + + int result2 = numbers.stream().reduce(0, Integer::sum); + System.out.println(result2); + + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result3 = letters.stream().reduce("", (partialString, element) -> partialString + element); + System.out.println(result3); + + String result4 = letters.stream().reduce("", String::concat); + System.out.println(result4); + + String result5 = letters.stream().reduce("", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase()); + System.out.println(result5); + + List users = Arrays.asList(new User("John", 30), new User("Julie", 35)); + int result6 = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + System.out.println(result6); + + String result7 = letters.parallelStream().reduce("", String::concat); + System.out.println(result7); + + int result8 = users.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + System.out.println(result8); + + org.openjdk.jmh.Main.main(args); + + } + + @Benchmark + @Fork(value = 1, warmups = 2) + @Warmup(iterations = 2) + @BenchmarkMode(Mode.AverageTime) + public void executeReduceOnParallelizedStream() { + List userList = new ArrayList<>(); + for (int i = 0; i <= 1000000; i++) { + userList.add(new User("John" + i, i)); + } + userList.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + } + + @Benchmark + @Fork(value = 1, warmups = 2) + @Warmup(iterations = 2) + @BenchmarkMode(Mode.AverageTime) + public void executeReduceOnSequentialStream() { + List userList = new ArrayList<>(); + for (int i = 0; i <= 1000000; i++) { + userList.add(new User("John" + i, i)); + } + userList.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + } +} diff --git a/java-streams/src/main/java/com/baeldung/reduce/entities/User.java b/java-streams/src/main/java/com/baeldung/reduce/entities/User.java new file mode 100644 index 0000000000..a17c6a02b6 --- /dev/null +++ b/java-streams/src/main/java/com/baeldung/reduce/entities/User.java @@ -0,0 +1,25 @@ +package com.baeldung.reduce.entities; + +public class User { + + private final String name; + private final int age; + + public User(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + @Override + public String toString() { + return "User{" + "name=" + name + ", age=" + age + '}'; + } +} diff --git a/java-streams/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java b/java-streams/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java new file mode 100644 index 0000000000..8b4af2cbe2 --- /dev/null +++ b/java-streams/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java @@ -0,0 +1,52 @@ +package com.baeldung.reduce.utilities; + +import java.util.List; +import java.util.function.BiFunction; +import java.util.logging.Level; +import java.util.logging.Logger; + +public abstract class NumberUtils { + + private static final Logger LOGGER = Logger.getLogger(NumberUtils.class.getName()); + + public static int divideListElements(List values, Integer divider) { + return values.stream() + .reduce(0, (a, b) -> { + try { + return a / divider + b / divider; + } catch (ArithmeticException e) { + LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero"); + } + return 0; + }); + } + + public static int divideListElementsWithExtractedTryCatchBlock(List values, int divider) { + return values.stream().reduce(0, (a, b) -> divide(a, divider) + divide(b, divider)); + } + + public static int divideListElementsWithApplyFunctionMethod(List values, int divider) { + BiFunction division = (a, b) -> a / b; + return values.stream().reduce(0, (a, b) -> applyFunction(division, a, divider) + applyFunction(division, b, divider)); + } + + private static int divide(int value, int factor) { + int result = 0; + try { + result = value / factor; + } catch (ArithmeticException e) { + LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero"); + } + return result; + } + + private static int applyFunction(BiFunction function, int a, int b) { + try { + return function.apply(a, b); + } + catch(Exception e) { + LOGGER.log(Level.INFO, "Exception occurred!"); + } + return 0; + } +} diff --git a/java-streams/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java b/java-streams/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java new file mode 100644 index 0000000000..8e2ff7bf22 --- /dev/null +++ b/java-streams/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java @@ -0,0 +1,79 @@ +package com.baeldung.reduce.tests; + +import com.baeldung.reduce.entities.User; +import com.baeldung.reduce.utilities.NumberUtils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; + +public class StreamReduceUnitTest { + + @Test + public void givenIntegerList_whenReduceWithSumAccumulatorLambda_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result = numbers.stream().reduce(0, (a, b) -> a + b); + assertThat(result).isEqualTo(21); + } + + @Test + public void givenIntegerList_whenReduceWithSumAccumulatorMethodReference_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result = numbers.stream().reduce(0, Integer::sum); + assertThat(result).isEqualTo(21); + } + + @Test + public void givenStringList_whenReduceWithConcatenatorAccumulatorLambda_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.stream().reduce("", (a, b) -> a + b); + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenStringList_whenReduceWithConcatenatorAccumulatorMethodReference_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.stream().reduce("", String::concat); + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenStringList_whenReduceWithUppercaseConcatenatorAccumulator_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.stream().reduce("", (a, b) -> a.toUpperCase() + b.toUpperCase()); + assertThat(result).isEqualTo("ABCDE"); + } + + @Test + public void givenUserList_whenReduceWithAgeAccumulatorAndSumCombiner_thenCorrect() { + List users = Arrays.asList(new User("John", 30), new User("Julie", 35)); + int result = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum); + assertThat(result).isEqualTo(65); + } + + @Test + public void givenStringList_whenReduceWithParallelStream_thenCorrect() { + List letters = Arrays.asList("a", "b", "c", "d", "e"); + String result = letters.parallelStream().reduce("", String::concat); + assertThat(result).isEqualTo("abcde"); + } + + @Test + public void givenNumberUtilsClass_whenCalledDivideListElements_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + assertThat(NumberUtils.divideListElements(numbers, 1)).isEqualTo(21); + } + + @Test + public void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlock_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 1)).isEqualTo(21); + } + + @Test + public void givenStream_whneCalleddivideListElementsWithApplyFunctionMethod_thenCorrect() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + assertThat(NumberUtils.divideListElementsWithApplyFunctionMethod(numbers, 1)).isEqualTo(21); + } +} diff --git a/java-strings/README.md b/java-strings/README.md index 1ab5e098f6..b342f53918 100644 --- a/java-strings/README.md +++ b/java-strings/README.md @@ -22,7 +22,7 @@ - [Check if a String is a Palindrome](http://www.baeldung.com/java-palindrome) - [Comparing Strings in Java](http://www.baeldung.com/java-compare-strings) - [Check If a String Is Numeric in Java](http://www.baeldung.com/java-check-string-number) -- [Why Use char[] Array Over a String for Storing Passwords in Java?](http://www.baeldung.com/java-storing-passwords) +- [Use char[] Array Over a String for Manipulating Passwords in Java?](http://www.baeldung.com/java-storing-passwords) - [Convert a String to Title Case](http://www.baeldung.com/java-string-title-case) - [Compact Strings in Java 9](http://www.baeldung.com/java-9-compact-string) - [Java Check a String for Lowercase/Uppercase Letter, Special Character and Digit](https://www.baeldung.com/java-lowercase-uppercase-special-character-digit-regex) @@ -53,3 +53,4 @@ - [Java String Interview Questions and Answers](https://www.baeldung.com/java-string-interview-questions) - [Check if a String is a Pangram in Java](https://www.baeldung.com/java-string-pangram) - [Check If a String Contains Multiple Keywords](https://www.baeldung.com/string-contains-multiple-words) +- [Common String Operations in Java](https://www.baeldung.com/java-string-operations) diff --git a/javax-servlets/src/main/java/com/baeldung/filters/EmptyParamFilter.java b/javax-servlets/src/main/java/com/baeldung/filters/EmptyParamFilter.java new file mode 100644 index 0000000000..b0b5392237 --- /dev/null +++ b/javax-servlets/src/main/java/com/baeldung/filters/EmptyParamFilter.java @@ -0,0 +1,35 @@ +package com.baeldung.filters; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import java.io.IOException; + +@WebFilter(urlPatterns = "/uppercase") +public class EmptyParamFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, + FilterChain filterChain) throws IOException, ServletException { + String inputString = servletRequest.getParameter("input"); + + if (inputString != null && inputString.matches("[A-Za-z0-9]+")) { + filterChain.doFilter(servletRequest, servletResponse); + } else { + servletResponse.getWriter().println("Missing input parameter"); + } + } + + @Override + public void destroy() { + } + +} diff --git a/javax-servlets/src/main/java/com/baeldung/listeners/AppListener.java b/javax-servlets/src/main/java/com/baeldung/listeners/AppListener.java new file mode 100644 index 0000000000..ed16dd1654 --- /dev/null +++ b/javax-servlets/src/main/java/com/baeldung/listeners/AppListener.java @@ -0,0 +1,21 @@ +package com.baeldung.listeners; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; + +@WebListener +public class AppListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent event) { + ServletContext context = event.getServletContext(); + context.setAttribute("counter", 0); + } + + @Override + public void contextDestroyed(ServletContextEvent event) { + + } +} diff --git a/javax-servlets/src/main/java/com/baeldung/listeners/RequestListener.java b/javax-servlets/src/main/java/com/baeldung/listeners/RequestListener.java new file mode 100644 index 0000000000..7f0c37b666 --- /dev/null +++ b/javax-servlets/src/main/java/com/baeldung/listeners/RequestListener.java @@ -0,0 +1,24 @@ +package com.baeldung.listeners; + +import javax.servlet.ServletContext; +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.annotation.WebListener; +import javax.servlet.http.HttpServletRequest; + +@WebListener +public class RequestListener implements ServletRequestListener { + + @Override + public void requestInitialized(ServletRequestEvent event) { + } + + @Override + public void requestDestroyed(ServletRequestEvent event) { + HttpServletRequest request = (HttpServletRequest)event.getServletRequest(); + if (!request.getServletPath().equals("/counter")) { + ServletContext context = event.getServletContext(); + context.setAttribute("counter", (int)context.getAttribute("counter") + 1); + } + } +} diff --git a/javax-servlets/src/main/java/com/baeldung/servlets/CounterServlet.java b/javax-servlets/src/main/java/com/baeldung/servlets/CounterServlet.java new file mode 100644 index 0000000000..a11f084db2 --- /dev/null +++ b/javax-servlets/src/main/java/com/baeldung/servlets/CounterServlet.java @@ -0,0 +1,21 @@ +package com.baeldung.servlets; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +@WebServlet(urlPatterns = "/counter", name = "counterServlet") +public class CounterServlet extends HttpServlet { + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + PrintWriter out = response.getWriter(); + + int count = (int)request.getServletContext().getAttribute("counter"); + + out.println("Request counter: " + count); + } + +} diff --git a/javax-servlets/src/main/java/com/baeldung/servlets/UppercaseServlet.java b/javax-servlets/src/main/java/com/baeldung/servlets/UppercaseServlet.java new file mode 100644 index 0000000000..766ec2e6ff --- /dev/null +++ b/javax-servlets/src/main/java/com/baeldung/servlets/UppercaseServlet.java @@ -0,0 +1,20 @@ +package com.baeldung.servlets; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +@WebServlet(urlPatterns = "/uppercase", name = "uppercaseServlet") +public class UppercaseServlet extends HttpServlet { + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + String inputString = request.getParameter("input").toUpperCase(); + + PrintWriter out = response.getWriter(); + + out.println(inputString); + } +} diff --git a/javaxval/pom.xml b/javaxval/pom.xml index f31aa0dc77..7ecddc0ca8 100644 --- a/javaxval/pom.xml +++ b/javaxval/pom.xml @@ -55,8 +55,7 @@ 2.0.1.Final 6.0.13.Final 3.0.0 - 5.0.2.RELEASE - 4.12 + 5.0.2.RELEASE 3.11.1 diff --git a/jhipster-5/bookstore-monolith/.editorconfig b/jhipster-5/bookstore-monolith/.editorconfig new file mode 100644 index 0000000000..a79c052f53 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.editorconfig @@ -0,0 +1,24 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] + +# Change these settings to your own preference +indent_style = space +indent_size = 4 + +# We recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[package.json] +indent_style = space +indent_size = 2 diff --git a/jhipster-5/bookstore-monolith/.gitattributes b/jhipster-5/bookstore-monolith/.gitattributes new file mode 100644 index 0000000000..c013844d10 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.gitattributes @@ -0,0 +1,148 @@ +# This file is inspired by https://github.com/alexkaratarakis/gitattributes +# +# Auto detect text files and perform LF normalization +# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ +* text=auto + +# The above will handle all files NOT found below +# These files are text and should be normalized (Convert crlf => lf) + +*.bat text eol=crlf +*.coffee text +*.css text +*.cql text +*.df text +*.ejs text +*.html text +*.java text +*.js text +*.json text +*.less text +*.properties text +*.sass text +*.scss text +*.sh text eol=lf +*.sql text +*.txt text +*.ts text +*.xml text +*.yaml text +*.yml text + +# Documents +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain +*.markdown text +*.md text +*.adoc text +*.textile text +*.mustache text +*.csv text +*.tab text +*.tsv text +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +*COPYRIGHT* text +INSTALL text +license text +LICENSE text +NEWS text +readme text +*README* text +TODO text + +# Graphics +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.tif binary +*.tiff binary +*.ico binary +# SVG treated as an asset (binary) by default. If you want to treat it as text, +# comment-out the following line and uncomment the line after. +*.svg binary +#*.svg text +*.eps binary + +# These files are binary and should be left untouched +# (binary is a macro for -text -diff) +*.class binary +*.jar binary +*.war binary + +## LINTERS +.csslintrc text +.eslintrc text +.jscsrc text +.jshintrc text +.jshintignore text +.stylelintrc text + +## CONFIGS +*.conf text +*.config text +.editorconfig text +.gitattributes text +.gitconfig text +.gitignore text +.htaccess text +*.npmignore text + +## HEROKU +Procfile text +.slugignore text + +## AUDIO +*.kar binary +*.m4a binary +*.mid binary +*.midi binary +*.mp3 binary +*.ogg binary +*.ra binary + +## VIDEO +*.3gpp binary +*.3gp binary +*.as binary +*.asf binary +*.asx binary +*.fla binary +*.flv binary +*.m4v binary +*.mng binary +*.mov binary +*.mp4 binary +*.mpeg binary +*.mpg binary +*.swc binary +*.swf binary +*.webm binary + +## ARCHIVES +*.7z binary +*.gz binary +*.rar binary +*.tar binary +*.zip binary + +## FONTS +*.ttf binary +*.eot binary +*.otf binary +*.woff binary +*.woff2 binary diff --git a/jhipster-5/bookstore-monolith/.gitignore b/jhipster-5/bookstore-monolith/.gitignore new file mode 100644 index 0000000000..f1f6845d33 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.gitignore @@ -0,0 +1,145 @@ +###################### +# Project Specific +###################### +/src/main/webapp/content/css/main.css +/target/www/** +/src/test/javascript/coverage/ + +###################### +# Node +###################### +/node/ +node_tmp/ +node_modules/ +npm-debug.log.* +/.awcache/* +/.cache-loader/* + +###################### +# SASS +###################### +.sass-cache/ + +###################### +# Eclipse +###################### +*.pydevproject +.project +.metadata +tmp/ +tmp/**/* +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath +.factorypath +/src/main/resources/rebel.xml + +# External tool builders +.externalToolBuilders/** + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + +###################### +# Intellij +###################### +.idea/ +*.iml +*.iws +*.ipr +*.ids +*.orig +classes/ +out/ + +###################### +# Visual Studio Code +###################### +.vscode/ + +###################### +# Maven +###################### +/log/ +/target/ + +###################### +# Gradle +###################### +.gradle/ +/build/ + +###################### +# Package Files +###################### +*.jar +*.war +*.ear +*.db + +###################### +# Windows +###################### +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + +###################### +# Mac OSX +###################### +.DS_Store +.svn + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes + +###################### +# Directories +###################### +/bin/ +/deploy/ + +###################### +# Logs +###################### +*.log* + +###################### +# Others +###################### +*.class +*.*~ +*~ +.merge_file* + +###################### +# Gradle Wrapper +###################### +!gradle/wrapper/gradle-wrapper.jar + +###################### +# Maven Wrapper +###################### +!.mvn/wrapper/maven-wrapper.jar + +###################### +# ESLint +###################### +.eslintcache diff --git a/jhipster-5/bookstore-monolith/.huskyrc b/jhipster-5/bookstore-monolith/.huskyrc new file mode 100644 index 0000000000..9e18d87674 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.huskyrc @@ -0,0 +1,5 @@ +{ + "hooks": { + "pre-commit": "lint-staged" + } +} diff --git a/jhipster-5/bookstore-monolith/.jhipster/Book.json b/jhipster-5/bookstore-monolith/.jhipster/Book.json new file mode 100644 index 0000000000..4c5bd1fa52 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.jhipster/Book.json @@ -0,0 +1,54 @@ +{ + "fluentMethods": true, + "clientRootFolder": "", + "relationships": [], + "fields": [ + { + "fieldName": "title", + "fieldType": "String", + "fieldValidateRules": [ + "required" + ] + }, + { + "fieldName": "author", + "fieldType": "String", + "fieldValidateRules": [ + "required" + ] + }, + { + "fieldName": "published", + "fieldType": "LocalDate", + "fieldValidateRules": [ + "required" + ] + }, + { + "fieldName": "quantity", + "fieldType": "Integer", + "fieldValidateRules": [ + "required", + "min" + ], + "fieldValidateRulesMin": 0 + }, + { + "fieldName": "price", + "fieldType": "Double", + "fieldValidateRules": [ + "required", + "min" + ], + "fieldValidateRulesMin": 0 + } + ], + "changelogDate": "20190319124041", + "dto": "mapstruct", + "searchEngine": false, + "service": "serviceImpl", + "entityTableName": "book", + "databaseType": "sql", + "jpaMetamodelFiltering": false, + "pagination": "no" +} diff --git a/jhipster-5/bookstore-monolith/.mvn/wrapper/MavenWrapperDownloader.java b/jhipster-5/bookstore-monolith/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000000..8fe1fab5a2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,110 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.jar b/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000..01e6799737 Binary files /dev/null and b/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.jar differ diff --git a/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.properties b/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..cd0d451ccd --- /dev/null +++ b/jhipster-5/bookstore-monolith/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/jhipster-5/bookstore-monolith/.prettierignore b/jhipster-5/bookstore-monolith/.prettierignore new file mode 100644 index 0000000000..151fcf7916 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.prettierignore @@ -0,0 +1,3 @@ +node_modules +target +package-lock.json diff --git a/jhipster-5/bookstore-monolith/.prettierrc b/jhipster-5/bookstore-monolith/.prettierrc new file mode 100644 index 0000000000..6fd4aa1267 --- /dev/null +++ b/jhipster-5/bookstore-monolith/.prettierrc @@ -0,0 +1,12 @@ +# Prettier configuration + +printWidth: 140 +singleQuote: true +tabWidth: 4 +useTabs: false + +# js and ts rules: +arrowParens: avoid + +# jsx and tsx rules: +jsxBracketSameLine: false diff --git a/jhipster-5/bookstore-monolith/.yo-rc.json b/jhipster-5/bookstore-monolith/.yo-rc.json new file mode 100644 index 0000000000..d852aeeddc --- /dev/null +++ b/jhipster-5/bookstore-monolith/.yo-rc.json @@ -0,0 +1,34 @@ +{ + "generator-jhipster": { + "promptValues": { + "packageName": "com.baeldung.jhipster5" + }, + "jhipsterVersion": "5.8.2", + "applicationType": "monolith", + "baseName": "Bookstore", + "packageName": "com.baeldung.jhipster5", + "packageFolder": "com/baeldung/jhipster5", + "serverPort": "8080", + "authenticationType": "jwt", + "cacheProvider": "no", + "websocket": false, + "databaseType": "sql", + "devDatabaseType": "h2Memory", + "prodDatabaseType": "mysql", + "searchEngine": false, + "messageBroker": false, + "serviceDiscoveryType": false, + "buildTool": "maven", + "enableSwaggerCodegen": false, + "jwtSecretKey": "NDJmOTVlZjI2NzhlZDRjNmVkNTM1NDE2NjkyNDljZDJiNzBlMjI5YmZjMjY3MzdjZmZlMjI3NjE4OTRkNzc5MWYzNDNlYWMzYmJjOWRmMjc5ZWQyZTZmOWZkOTMxZWZhNWE1MTVmM2U2NjFmYjhlNDc2Y2Q3NzliMGY0YzFkNmI=", + "clientFramework": "angularX", + "useSass": true, + "clientPackageManager": "npm", + "testFrameworks": [], + "jhiPrefix": "jhi", + "entitySuffix": "", + "dtoSuffix": "DTO", + "otherModules": [], + "enableTranslation": false + } +} diff --git a/jhipster-5/bookstore-monolith/README.md b/jhipster-5/bookstore-monolith/README.md new file mode 100644 index 0000000000..1387b82163 --- /dev/null +++ b/jhipster-5/bookstore-monolith/README.md @@ -0,0 +1,179 @@ +# Bookstore + +This application was generated using JHipster 5.8.2, you can find documentation and help at [https://www.jhipster.tech/documentation-archive/v5.8.2](https://www.jhipster.tech/documentation-archive/v5.8.2). + +## Development + +Before you can build this project, you must install and configure the following dependencies on your machine: + +1. [Node.js][]: We use Node to run a development web server and build the project. + Depending on your system, you can install Node either from source or as a pre-packaged bundle. + +After installing Node, you should be able to run the following command to install development tools. +You will only need to run this command when dependencies change in [package.json](package.json). + + npm install + +We use npm scripts and [Webpack][] as our build system. + +Run the following commands in two separate terminals to create a blissful development experience where your browser +auto-refreshes when files change on your hard drive. + + ./mvnw + npm start + +Npm is also used to manage CSS and JavaScript dependencies used in this application. You can upgrade dependencies by +specifying a newer version in [package.json](package.json). You can also run `npm update` and `npm install` to manage dependencies. +Add the `help` flag on any command to see how you can use it. For example, `npm help update`. + +The `npm run` command will list all of the scripts available to run for this project. + +### Service workers + +Service workers are commented by default, to enable them please uncomment the following code. + +- The service worker registering script in index.html + +```html + +``` + +Note: workbox creates the respective service worker and dynamically generate the `service-worker.js` + +### Managing dependencies + +For example, to add [Leaflet][] library as a runtime dependency of your application, you would run following command: + + npm install --save --save-exact leaflet + +To benefit from TypeScript type definitions from [DefinitelyTyped][] repository in development, you would run following command: + + npm install --save-dev --save-exact @types/leaflet + +Then you would import the JS and CSS files specified in library's installation instructions so that [Webpack][] knows about them: +Edit [src/main/webapp/app/vendor.ts](src/main/webapp/app/vendor.ts) file: + +``` +import 'leaflet/dist/leaflet.js'; +``` + +Edit [src/main/webapp/content/css/vendor.css](src/main/webapp/content/css/vendor.css) file: + +``` +@import '~leaflet/dist/leaflet.css'; +``` + +Note: there are still few other things remaining to do for Leaflet that we won't detail here. + +For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][]. + +### Using angular-cli + +You can also use [Angular CLI][] to generate some custom client code. + +For example, the following command: + + ng generate component my-component + +will generate few files: + + create src/main/webapp/app/my-component/my-component.component.html + create src/main/webapp/app/my-component/my-component.component.ts + update src/main/webapp/app/app.module.ts + +## Building for production + +To optimize the Bookstore application for production, run: + + ./mvnw -Pprod clean package + +This will concatenate and minify the client CSS and JavaScript files. It will also modify `index.html` so it references these new files. +To ensure everything worked, run: + + java -jar target/*.war + +Then navigate to [http://localhost:8080](http://localhost:8080) in your browser. + +Refer to [Using JHipster in production][] for more details. + +## Testing + +To launch your application's tests, run: + + ./mvnw clean test + +### Client tests + +Unit tests are run by [Jest][] and written with [Jasmine][]. They're located in [src/test/javascript/](src/test/javascript/) and can be run with: + + npm test + +For more information, refer to the [Running tests page][]. + +### Code quality + +Sonar is used to analyse code quality. You can start a local Sonar server (accessible on http://localhost:9001) with: + +``` +docker-compose -f src/main/docker/sonar.yml up -d +``` + +Then, run a Sonar analysis: + +``` +./mvnw -Pprod clean test sonar:sonar +``` + +For more information, refer to the [Code quality page][]. + +## Using Docker to simplify development (optional) + +You can use Docker to improve your JHipster development experience. A number of docker-compose configuration are available in the [src/main/docker](src/main/docker) folder to launch required third party services. + +For example, to start a mysql database in a docker container, run: + + docker-compose -f src/main/docker/mysql.yml up -d + +To stop it and remove the container, run: + + docker-compose -f src/main/docker/mysql.yml down + +You can also fully dockerize your application and all the services that it depends on. +To achieve this, first build a docker image of your app by running: + + ./mvnw package -Pprod verify jib:dockerBuild + +Then run: + + docker-compose -f src/main/docker/app.yml up -d + +For more information refer to [Using Docker and Docker-Compose][], this page also contains information on the docker-compose sub-generator (`jhipster docker-compose`), which is able to generate docker configurations for one or several JHipster applications. + +## Continuous Integration (optional) + +To configure CI for your project, run the ci-cd sub-generator (`jhipster ci-cd`), this will let you generate configuration files for a number of Continuous Integration systems. Consult the [Setting up Continuous Integration][] page for more information. + +[jhipster homepage and latest documentation]: https://www.jhipster.tech +[jhipster 5.8.2 archive]: https://www.jhipster.tech/documentation-archive/v5.8.2 +[using jhipster in development]: https://www.jhipster.tech/documentation-archive/v5.8.2/development/ +[using docker and docker-compose]: https://www.jhipster.tech/documentation-archive/v5.8.2/docker-compose +[using jhipster in production]: https://www.jhipster.tech/documentation-archive/v5.8.2/production/ +[running tests page]: https://www.jhipster.tech/documentation-archive/v5.8.2/running-tests/ +[code quality page]: https://www.jhipster.tech/documentation-archive/v5.8.2/code-quality/ +[setting up continuous integration]: https://www.jhipster.tech/documentation-archive/v5.8.2/setting-up-ci/ +[node.js]: https://nodejs.org/ +[yarn]: https://yarnpkg.org/ +[webpack]: https://webpack.github.io/ +[angular cli]: https://cli.angular.io/ +[browsersync]: http://www.browsersync.io/ +[jest]: https://facebook.github.io/jest/ +[jasmine]: http://jasmine.github.io/2.0/introduction.html +[protractor]: https://angular.github.io/protractor/ +[leaflet]: http://leafletjs.com/ +[definitelytyped]: http://definitelytyped.org/ diff --git a/jhipster-5/bookstore-monolith/angular.json b/jhipster-5/bookstore-monolith/angular.json new file mode 100644 index 0000000000..61791db9fb --- /dev/null +++ b/jhipster-5/bookstore-monolith/angular.json @@ -0,0 +1,39 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "bookstore": { + "root": "", + "sourceRoot": "src/main/webapp", + "projectType": "application", + "architect": {} + } + }, + "defaultProject": "bookstore", + "cli": { + "packageManager": "npm" + }, + "schematics": { + "@schematics/angular:component": { + "inlineStyle": true, + "inlineTemplate": false, + "spec": false, + "prefix": "jhi", + "styleExt": "scss" + }, + "@schematics/angular:directive": { + "spec": false, + "prefix": "jhi" + }, + "@schematics/angular:guard": { + "spec": false + }, + "@schematics/angular:pipe": { + "spec": false + }, + "@schematics/angular:service": { + "spec": false + } + } +} diff --git a/jhipster-5/bookstore-monolith/mvnw b/jhipster-5/bookstore-monolith/mvnw new file mode 100755 index 0000000000..5551fde8e7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/mvnw @@ -0,0 +1,286 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + wget "$jarUrl" -O "$wrapperJarPath" + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + curl -o "$wrapperJarPath" "$jarUrl" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/jhipster-5/bookstore-monolith/mvnw.cmd b/jhipster-5/bookstore-monolith/mvnw.cmd new file mode 100644 index 0000000000..e5cfb0ae9e --- /dev/null +++ b/jhipster-5/bookstore-monolith/mvnw.cmd @@ -0,0 +1,161 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" +FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/jhipster-5/bookstore-monolith/package-lock.json b/jhipster-5/bookstore-monolith/package-lock.json new file mode 100644 index 0000000000..6e2a8dc526 --- /dev/null +++ b/jhipster-5/bookstore-monolith/package-lock.json @@ -0,0 +1,18244 @@ +{ + "name": "bookstore", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.13.1.tgz", + "integrity": "sha512-QDmIbqde75ZZSEFbw6Q6kQWq4cY6C7D67yujXw6XTyubDNAs1tyXJyxTIB8vjSlEKwRizTTDd/B0ZXVcke3Mvw==", + "dev": true, + "requires": { + "@angular-devkit/core": "7.3.1", + "rxjs": "6.3.3" + }, + "dependencies": { + "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" + } + } + } + }, + "@angular-devkit/core": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-7.3.1.tgz", + "integrity": "sha512-56XDWWfIzOAkEk69lBLgmCYybPUA4yjunhmMlCk7vVdb7gbQUyzNjFD04Uj0GjlejatAQ5F76tRwygD9C+3RXQ==", + "dev": true, + "requires": { + "ajv": "6.7.0", + "chokidar": "2.0.4", + "fast-json-stable-stringify": "2.0.0", + "rxjs": "6.3.3", + "source-map": "0.7.3" + }, + "dependencies": { + "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" + } + } + } + }, + "@angular-devkit/schematics": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-7.3.1.tgz", + "integrity": "sha512-cd7usiasfSgw75INz72/VssrLr9tiVRYfo1TEdvr9ww0GuQbuQpB33xbV8W135eAV8+wzQ3Ce8ohaDHibvj6Yg==", + "dev": true, + "requires": { + "@angular-devkit/core": "7.3.1", + "rxjs": "6.3.3" + }, + "dependencies": { + "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" + } + } + } + }, + "@angular/cli": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-7.3.1.tgz", + "integrity": "sha512-8EvXYRhTqTaTk5PKv7VZxIWJiyG51R9RC9gtpRFx4bbnurqBHdEUxGMmaRsGT8QDbfvVsWnuakE0eeW1CrfZAQ==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.13.1", + "@angular-devkit/core": "7.3.1", + "@angular-devkit/schematics": "7.3.1", + "@schematics/angular": "7.3.1", + "@schematics/update": "0.13.1", + "@yarnpkg/lockfile": "1.1.0", + "ini": "1.3.5", + "inquirer": "6.2.1", + "npm-package-arg": "6.1.0", + "opn": "5.4.0", + "pacote": "9.4.0", + "semver": "5.6.0", + "symbol-observable": "1.2.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "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 + }, + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "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 + }, + "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" + } + }, + "inquirer": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz", + "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==", + "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": "^5.0.0", + "through": "^2.3.6" + } + }, + "opn": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", + "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==", + "dev": true, + "requires": { + "is-wsl": "^1.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" + } + }, + "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" + } + } + } + }, + "@angular/common": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-7.2.4.tgz", + "integrity": "sha512-3/i8RtnLTx/90gJHk5maE8zwsSiHgHvLItaa0qVfNlWiU0eCId/PL6TgDkut5vN9SQYL0oxhxFaVd35HmwsmuQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/compiler": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-7.2.4.tgz", + "integrity": "sha512-+zyMzPCL45ePEV9nrnYJvhAVgp2Y19bDaq0f0YdZAqAjgDqHzXGGR6wX8GueyJWmUYWx5vwK6Apla4HwDrYA1w==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/compiler-cli": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-7.2.4.tgz", + "integrity": "sha512-UhLosSeuwFIfaGqGcYOh9WSOuzEpeuhIRAOt81MeqOQEqkoreUjfxrQq8XWNkdqsPZHtiptF5ZwXlMBxlj9jJg==", + "dev": true, + "requires": { + "canonical-path": "1.0.0", + "chokidar": "^1.4.2", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.7.2", + "magic-string": "^0.25.0", + "minimist": "^1.2.0", + "reflect-metadata": "^0.1.2", + "shelljs": "^0.8.1", + "source-map": "^0.6.1", + "tslib": "^1.9.0", + "yargs": "9.0.1" + }, + "dependencies": { + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "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 + }, + "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" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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 + } + } + }, + "@angular/core": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-7.2.4.tgz", + "integrity": "sha512-kfAxhIxl89PmB7y81FR/RAv0yWRFcEYxEnTwV+o8jKGfemAXtQ0g/Vh+lJR0SD/TBgFilMxotN1mhwH4A8GShw==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/forms": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-7.2.4.tgz", + "integrity": "sha512-DAtOrdlTRsgvmZrsvczCAkY8dhTwZb5DXBmPuSXh0UR9lvEiCgNHGbwEiIiIkAHpw1wSeXZrq0qyy/oJRvf18g==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/platform-browser": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-7.2.4.tgz", + "integrity": "sha512-Klt8aKR5SP9bqfMfpSY5vQOY7AQEs8JGuZOk5Bfc2dUtYT2IEIvK2IqO8v2rcFRVO13HOPUxl328efyHqLgI7g==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.4.tgz", + "integrity": "sha512-J/xWlmaYOPUoCHZ5TiIRiyYa4uRMtCz3aGdBfY8k/NWtNo8SCYaS3aut7Sk4RS5rK8aAVi+aYFlY5YOrlW+Hbg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/router": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-7.2.4.tgz", + "integrity": "sha512-T8Uqf2H1SV1MQI38WwYJ4aa+4NNnvlp2Tp/rkfg6tKcp/cLkKqE6OOfiy9lmW+i/624v8tMgYoBMOUNBjAG23g==", + "requires": { + "tslib": "^1.9.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.3.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.3.4.tgz", + "integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helpers": "^7.2.0", + "@babel/parser": "^7.3.4", + "@babel/template": "^7.2.2", + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.3.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "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 + } + } + }, + "@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-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-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/helpers": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.3.1.tgz", + "integrity": "sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==", + "dev": true, + "requires": { + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.5", + "@babel/types": "^7.3.0" + } + }, + "@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" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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 + }, + "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" + } + } + } + }, + "@babel/parser": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", + "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==", + "dev": true + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/runtime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", + "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.12.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", + "dev": true + } + } + }, + "@babel/template": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", + "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.2.2", + "@babel/types": "^7.2.2" + } + }, + "@babel/traverse": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + }, + "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" + } + }, + "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 + } + } + }, + "@babel/types": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "@cnakazawa/watch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", + "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@fortawesome/angular-fontawesome": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.3.0.tgz", + "integrity": "sha512-wXvyPI7GidoNiqeMz2re9iemUMFH4zBmuv94CfXlaanQ8+kMP/fYs/k69PLVN1KsebQY4kRA9GHmc1U1ndBkJg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@fortawesome/fontawesome-common-types": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.15.tgz", + "integrity": "sha512-ATBRyKJw1d2ko+0DWN9+BXau0EK3I/Q6pPzPv3LhJD7r052YFAkAdfb1Bd7ZqhBsJrdse/S7jKxWUOZ61qBD4g==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.14.tgz", + "integrity": "sha512-T1qCqkwm9PuvK53J64D1ovfrOTa1kG+SrHNj5cFst/rrskhCnbxpRdbqFIdc/thmXC0ebBX8nOUyja2/mrxe4g==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.14" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.7.1.tgz", + "integrity": "sha512-5V/Q+JoPzuiIHW2JwmZGvE9bHguvNJKa7611DPo51uIvYv9LweX/SnDF+HC23X2W5T3myHhnGi+EZJTmidAmyg==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.14" + } + }, + "@iamstarkov/listr-update-renderer": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@iamstarkov/listr-update-renderer/-/listr-update-renderer-0.4.1.tgz", + "integrity": "sha512-IJyxQWsYDEkf8C8QthBn5N8tIUR9V9je6j3sMIpAkonaadjbvxmRC6RAhpa3RKxndhNnU2M6iNbtJwd7usQYIA==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + } + } + }, + "@jest/console": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.3.0.tgz", + "integrity": "sha512-NaCty/OOei6rSDcbPdMiCbYCI0KGFGPgGO6B09lwWt5QTxnkuhKYET9El5u5z1GAcSxkQmSMtM63e24YabCWqA==", + "dev": true, + "requires": { + "@jest/source-map": "^24.3.0", + "@types/node": "*", + "chalk": "^2.0.1", + "slash": "^2.0.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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" + } + } + } + }, + "@jest/core": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.5.0.tgz", + "integrity": "sha512-RDZArRzAs51YS7dXG1pbXbWGxK53rvUu8mCDYsgqqqQ6uSOaTjcVyBl2Jce0exT2rSLk38ca7az7t2f3b0/oYQ==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/reporters": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.5.0", + "jest-config": "^24.5.0", + "jest-haste-map": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-resolve-dependencies": "^24.5.0", + "jest-runner": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-snapshot": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "jest-watcher": "^24.5.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "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 + }, + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.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" + } + }, + "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" + } + } + } + }, + "@jest/environment": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.5.0.tgz", + "integrity": "sha512-tzUHR9SHjMXwM8QmfHb/EJNbF0fjbH4ieefJBvtwO8YErLTrecc1ROj0uo2VnIT6SlpEGZnvdCK6VgKYBo8LsA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^24.5.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/node": "*", + "jest-mock": "^24.5.0" + } + }, + "@jest/fake-timers": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.5.0.tgz", + "integrity": "sha512-i59KVt3QBz9d+4Qr4QxsKgsIg+NjfuCjSOWj3RQhjF5JNy+eVJDhANQ4WzulzNCHd72srMAykwtRn5NYDGVraw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "@types/node": "*", + "jest-message-util": "^24.5.0", + "jest-mock": "^24.5.0" + } + }, + "@jest/reporters": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.5.0.tgz", + "integrity": "sha512-vfpceiaKtGgnuC3ss5czWOihKOUSyjJA4M4udm6nH8xgqsuQYcyDCi4nMMcBKsHXWgz9/V5G7iisnZGfOh1w6Q==", + "dev": true, + "requires": { + "@jest/environment": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-api": "^2.1.1", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-source-maps": "^3.0.1", + "jest-haste-map": "^24.5.0", + "jest-resolve": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-util": "^24.5.0", + "jest-worker": "^24.4.0", + "node-notifier": "^5.2.1", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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 + }, + "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" + } + } + } + }, + "@jest/source-map": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.3.0.tgz", + "integrity": "sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + }, + "dependencies": { + "callsites": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", + "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", + "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 + } + } + }, + "@jest/test-result": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.5.0.tgz", + "integrity": "sha512-u66j2vBfa8Bli1+o3rCaVnVYa9O8CAFZeqiqLVhnarXtreSXG33YQ6vNYBogT7+nYiFNOohTU21BKiHlgmxD5A==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/types": "^24.5.0", + "@types/istanbul-lib-coverage": "^1.1.0" + } + }, + "@jest/transform": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.5.0.tgz", + "integrity": "sha512-XSsDz1gdR/QMmB8UCKlweAReQsZrD/DK7FuDlNo/pE8EcKMrfi2kqLRk8h8Gy/PDzgqJj64jNEzOce9pR8oj1w==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.5.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-util": "^24.5.0", + "micromatch": "^3.1.10", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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 + }, + "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" + } + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + } + } + }, + "@jest/types": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.5.0.tgz", + "integrity": "sha512-kN7RFzNMf2R8UDadPOl6ReyI+MT8xfqRuAnuVL+i4gwjv/zubdDK+EDeLHYwq1j0CSSR2W/MmgaRlMZJzXdmVA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^1.1.0", + "@types/yargs": "^12.0.9" + } + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@ng-bootstrap/ng-bootstrap": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-4.0.2.tgz", + "integrity": "sha512-SBsN8ORvj/WXpZGSyR2+CRkg6GCtax5+fsLKt9ImHKUVWwePVqRxiGlnxXqwNPHQ46vOdd7nDN9cwE7dfbGaAQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@ngtools/webpack": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-7.3.1.tgz", + "integrity": "sha512-EGQRjgDf5XP+Fm1MdZNRFiPd9e1vhl11BhjkwqkAsewic4eoz6fqXfj/Osz1hQy8xU+2dPPf/byQ/+nY3E02Zg==", + "dev": true, + "requires": { + "@angular-devkit/core": "7.3.1", + "enhanced-resolve": "4.1.0", + "rxjs": "6.3.3", + "tree-kill": "1.2.1", + "webpack-sources": "1.3.0" + }, + "dependencies": { + "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" + } + } + } + }, + "@ngx-translate/core": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-11.0.1.tgz", + "integrity": "sha512-nBCa1ZD9fAUY/3eskP3Lql2fNg8OMrYIej1/5GRsfcutx9tG/5fZLCv9m6UCw1aS+u4uK/vXjv1ctG/FdMvaWg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@ngx-translate/http-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-4.0.0.tgz", + "integrity": "sha512-x8LumqydWD7eX9yQTAVeoCM9gFUIGVTUjZqbxdAUavAA3qVnk9wCQux7iHLPXpydl8vyQmLoPQR+fFU+DUDOMA==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "@samverschueren/stream-to-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", + "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "dev": true, + "requires": { + "any-observable": "^0.3.0" + } + }, + "@schematics/angular": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-7.3.1.tgz", + "integrity": "sha512-0Ne8APPlTAjKg5CSZqluwCuW/5yPjr3ALCWzqwPxN0suE745usThtasBmqrjw0RMIt8nRqRgtg54Z7lCPO9ZFg==", + "dev": true, + "requires": { + "@angular-devkit/core": "7.3.1", + "@angular-devkit/schematics": "7.3.1", + "typescript": "3.2.4" + } + }, + "@schematics/update": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.13.1.tgz", + "integrity": "sha512-EHOqolT/d/jRGuVTCUESLpk8JNpuaPlsVHfeK7Kdp/t0wSEnmtOelZX4+leS25lGXDaDUF3138ntjrZR4n6bGw==", + "dev": true, + "requires": { + "@angular-devkit/core": "7.3.1", + "@angular-devkit/schematics": "7.3.1", + "@yarnpkg/lockfile": "1.1.0", + "ini": "1.3.5", + "pacote": "9.4.0", + "rxjs": "6.3.3", + "semver": "5.6.0", + "semver-intersect": "1.4.0" + }, + "dependencies": { + "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" + } + } + } + }, + "@types/babel__core": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.0.tgz", + "integrity": "sha512-wJTeJRt7BToFx3USrCDs2BhEi4ijBInTQjOIukj6a/5tEkwpFMVZ+1ppgmE+Q/FQyc5P/VWUbx7I9NELrKruHA==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.0.2.tgz", + "integrity": "sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.6.tgz", + "integrity": "sha512-XYVgHF2sQ0YblLRMLNPB3CkFMewzFmlDsH/TneZFHUXDlABQgh88uOxuez7ZcXxayLFrqLwtDH1t+FmlFwNZxw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/istanbul-lib-coverage": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz", + "integrity": "sha512-ohkhb9LehJy+PA40rDtGAji61NCgdtKLAlFoYp4cnuuQEswwdK3vz9SOIkkyc3wrk8dzjphQApNs56yyXLStaQ==", + "dev": true + }, + "@types/jest": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.0.tgz", + "integrity": "sha512-kOafJnUTnMd7/OfEO/x3I47EHswNjn+dbz9qk3mtonr1RvKT+1FGVxnxAx08I9K8Tl7j9hpoJRE7OCf+t10fng==", + "dev": true + }, + "@types/node": { + "version": "10.12.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.24.tgz", + "integrity": "sha512-GWWbvt+z9G5otRBW8rssOFgRY87J9N/qbhqfjMZ+gUuL6zoL+Hm6gP/8qQBG4jjimqdaNLCehcVapZ/Fs2WjCQ==", + "dev": true + }, + "@types/q": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "dev": true + }, + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/yargs": { + "version": "12.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.10.tgz", + "integrity": "sha512-WsVzTPshvCSbHThUduGGxbmnwcpkgSctHGHTqzWyFg4lYAuV5qXlyFPOsP3OWqCINfmg/8VXP+zJaa4OxEsBQQ==", + "dev": true + }, + "@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 + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", + "dev": true + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", + "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", + "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" + }, + "dependencies": { + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "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 + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "dev": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "ajv": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz", + "integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==", + "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.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz", + "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", + "dev": true + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "angular-router-loader": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/angular-router-loader/-/angular-router-loader-0.8.5.tgz", + "integrity": "sha512-8wggCTKGgzB1o8co3Wvj+p9pKN7T7q3C477lEz3NLjvPVzUti8rv9i45Di+4aO/k+HvzGh3s8QdNlXU2Bl4avQ==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2" + } + }, + "angular2-template-loader": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/angular2-template-loader/-/angular2-template-loader-0.6.2.tgz", + "integrity": "sha1-wNROkP/w+sleiyPwQ6zaf9HFHXw=", + "dev": true, + "requires": { + "loader-utils": "^0.2.15" + }, + "dependencies": { + "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 + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "ansi": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", + "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=", + "dev": true + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, + "any-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", + "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "dev": true + }, + "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" + } + }, + "app-root-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.1.0.tgz", + "integrity": "sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo=", + "dev": true + }, + "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 + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "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" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, + "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-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "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 + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "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 + }, + "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 + }, + "ast-types": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz", + "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "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.2", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.2.tgz", + "integrity": "sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg==", + "dev": true + }, + "async-each-series": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz", + "integrity": "sha1-dhfBkXQB/Yykooqtzj266Yr+tDI=", + "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 + }, + "autoprefixer": { + "version": "9.4.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.4.7.tgz", + "integrity": "sha512-qS5wW6aXHkm53Y4z73tFGsUhmZu4aMPV9iHXYlF0c/wxjknXNHuj/1cIQb+6YH692DbJGGWcckAXX+VxKvahMA==", + "dev": true, + "requires": { + "browserslist": "^4.4.1", + "caniuse-lite": "^1.0.30000932", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.14", + "postcss-value-parser": "^3.3.1" + } + }, + "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 + }, + "axios": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.17.1.tgz", + "integrity": "sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=", + "dev": true, + "requires": { + "follow-redirects": "^1.2.5", + "is-buffer": "^1.1.5" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "babel-extract-comments": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", + "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", + "dev": true, + "requires": { + "babylon": "^6.18.0" + } + }, + "babel-jest": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.5.0.tgz", + "integrity": "sha512-0fKCXyRwxFTJL0UXDJiT2xYxO9Lu2vBd9n+cC+eDjESzcVG3s2DRGAxbzJX21fceB1WYoBjAh8pQ83dKcl003g==", + "dev": true, + "requires": { + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.3.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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" + } + } + } + }, + "babel-plugin-istanbul": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", + "integrity": "sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ==", + "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.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": "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.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + } + } + }, + "babel-plugin-jest-hoist": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.3.0.tgz", + "integrity": "sha512-nWh4N1mVH55Tzhx2isvUN5ebM5CDUvIpXPZYMRazQughie/EqGnbR+czzoQlhUmJG9pPJmYDRhvocotb2THl1w==", + "dev": true, + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "babel-polyfill": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", + "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", + "requires": { + "babel-runtime": "^6.22.0", + "core-js": "^2.4.0", + "regenerator-runtime": "^0.10.0" + } + }, + "babel-preset-jest": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.3.0.tgz", + "integrity": "sha512-VGTV2QYBa/Kn3WCOKdfS31j9qomaXSgJqi65B6o05/1GsJyj9LVhSljM9ro4S+IBGj/ENhNBuH9bpqzztKAQSw==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.3.0" + } + }, + "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=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "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" + } + } + } + }, + "base62": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/base62/-/base62-1.2.8.tgz", + "integrity": "sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA==", + "dev": true + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "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 + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "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" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz", + "integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==", + "dev": true + }, + "binaryextensions": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.2.tgz", + "integrity": "sha512-xVNN69YGDghOqCCtA6FI7avYrr02mTJjOgB0/f1VPD3pJC8QEvjTKWc4epDx8AqxxA75NI0QpVM2gPJXUbE4Tg==", + "dev": true + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "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 + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "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 + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "bootstrap": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.2.1.tgz", + "integrity": "sha512-tt/7vIv3Gm2mnd/WeDx36nfGGHleil0Wg8IeB7eMrVkY0fZ5iTaBisSh8oNANc2IBsCc6vCgCNTIM/IEN0+50Q==" + }, + "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-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "browser-sync": { + "version": "2.26.3", + "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.26.3.tgz", + "integrity": "sha512-VLzpjCA4uXqfzkwqWtMM6hvPm2PNHp2RcmzBXcbi6C9WpkUhhFb8SVAr4CFrCsFxDg+oY6HalOjn8F+egyvhag==", + "dev": true, + "requires": { + "browser-sync-client": "^2.26.2", + "browser-sync-ui": "^2.26.2", + "bs-recipes": "1.3.4", + "bs-snippet-injector": "^2.0.1", + "chokidar": "^2.0.4", + "connect": "3.6.6", + "connect-history-api-fallback": "^1", + "dev-ip": "^1.0.1", + "easy-extender": "^2.3.4", + "eazy-logger": "^3", + "etag": "^1.8.1", + "fresh": "^0.5.2", + "fs-extra": "3.0.1", + "http-proxy": "1.15.2", + "immutable": "^3", + "localtunnel": "1.9.1", + "micromatch": "2.3.11", + "opn": "5.3.0", + "portscanner": "2.1.1", + "qs": "6.2.3", + "raw-body": "^2.3.2", + "resp-modifier": "6.0.2", + "rx": "4.1.0", + "send": "0.16.2", + "serve-index": "1.9.1", + "serve-static": "1.13.2", + "server-destroy": "1.0.1", + "socket.io": "2.1.1", + "ua-parser-js": "0.7.17", + "yargs": "6.4.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 + }, + "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" + } + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "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" + } + }, + "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" + } + }, + "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-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" + } + }, + "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" + } + }, + "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" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "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" + } + }, + "opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.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" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^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-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.4.0.tgz", + "integrity": "sha1-gW4ahm1VmMzzTlWW3c4i2S2kkNQ=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^4.1.0" + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + } + } + } + }, + "browser-sync-client": { + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.26.2.tgz", + "integrity": "sha512-FEuVJD41fI24HJ30XOT2RyF5WcnEtdJhhTqeyDlnMk/8Ox9MZw109rvk9pdfRWye4soZLe+xcAo9tHSMxvgAdw==", + "dev": true, + "requires": { + "etag": "1.8.1", + "fresh": "0.5.2", + "mitt": "^1.1.3", + "rxjs": "^5.5.6" + }, + "dependencies": { + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + } + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + } + } + }, + "browser-sync-ui": { + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.26.2.tgz", + "integrity": "sha512-LF7GMWo8ELOE0eAlxuRCfnGQT1ZxKP9flCfGgZdXFc6BwmoqaJHlYe7MmVvykKkXjolRXTz8ztXAKGVqNwJ3EQ==", + "dev": true, + "requires": { + "async-each-series": "0.1.1", + "connect-history-api-fallback": "^1", + "immutable": "^3", + "server-destroy": "1.0.1", + "socket.io-client": "^2.0.4", + "stream-throttle": "^0.1.3" + } + }, + "browser-sync-webpack-plugin": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/browser-sync-webpack-plugin/-/browser-sync-webpack-plugin-2.2.2.tgz", + "integrity": "sha512-x92kl8LdBi4dp6YVXYqrSoDkOCOLCeBOrYSY0h9Sk1VcCDSoZC1Vc62eae6TfC2ljN4/L+aYlkzE46kirHzbgA==", + "dev": true, + "requires": { + "lodash": "^4" + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://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": "https://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.5.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.5.1.tgz", + "integrity": "sha512-/pPw5IAUyqaQXGuD5vS8tcbudyPZ241jk1W5pQBsGDfcjNQt7p8qxZhgMNuygDShte1PibLFexecWUPgmVLfrg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000949", + "electron-to-chromium": "^1.3.116", + "node-releases": "^1.1.11" + } + }, + "bs-recipes": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz", + "integrity": "sha1-DS1NSKcYyMBEdp/cT4lZLci2lYU=", + "dev": true + }, + "bs-snippet-injector": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bs-snippet-injector/-/bs-snippet-injector-2.0.1.tgz", + "integrity": "sha1-YbU5PxH1JVntEgaTEANDtu2wTdU=", + "dev": true + }, + "bser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", + "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://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-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "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-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "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 + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cacache": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "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.1", + "unique-filename": "^1.1.1", + "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" + } + }, + "cache-loader": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-2.0.1.tgz", + "integrity": "sha512-V99T3FOynmGx26Zom+JrVBytLBsmUCzVG2/4NnUKgvXN4bEV42R1ERl1IyiH/cvFIDA1Ytq2lPZ9tXDSahcQpQ==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.0", + "normalize-path": "^3.0.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + } + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + } + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30000950", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000950.tgz", + "integrity": "sha512-Cs+4U9T0okW2ftBsCIHuEYXXkki7mjXmjCh4c6PzYShk04qDEr76/iC7KwhLoWoY65wcra1XOsRD+S7BptEb5A==", + "dev": true + }, + "canonical-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz", + "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==", + "dev": true + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" + }, + "chevrotain": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-4.2.0.tgz", + "integrity": "sha512-uiwhNpkudwrk3rHxKKfrvsWNe4SBDjnswbF2FDqDfrqsfYr4gY0Yl1k2m9yPKR0fqfbiIP67EbgOv4e+JP+GGg==", + "dev": true, + "requires": { + "regexp-to-ast": "0.3.5" + } + }, + "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" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "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" + } + }, + "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" + } + } + } + }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "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 + } + } + }, + "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=", + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "dev": true, + "requires": { + "colors": "1.0.3" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "^1.0.1" + }, + "dependencies": { + "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" + } + } + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true + }, + "clone-deep": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", + "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.0", + "shallow-clone": "^1.0.0" + }, + "dependencies": { + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + } + } + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "dev": true + }, + "cloneable-readable": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", + "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "closest-file-data": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/closest-file-data/-/closest-file-data-0.1.4.tgz", + "integrity": "sha1-l1+HwTLymdJKA3W59jyj+4j3Kzo=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "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 + }, + "codelyzer": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.5.0.tgz", + "integrity": "sha512-oO6vCkjqsVrEsmh58oNlnJkRXuA30hF8cdNAQV9DytEalDwyOFRvHMnlKFzmOStNerOmPGZU9GAHnBo4tGvtiQ==", + "dev": true, + "requires": { + "app-root-path": "^2.1.0", + "css-selector-tokenizer": "^0.7.0", + "cssauron": "^1.4.0", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "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": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "dev": true, + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "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 + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=", + "dev": true + }, + "colors": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "dev": true + }, + "colorspace": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", + "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", + "dev": true, + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, + "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 + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "commoner": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz", + "integrity": "sha1-NPw2cs0kOT6LtH5wyqApOBH08sU=", + "dev": true, + "requires": { + "commander": "^2.5.0", + "detective": "^4.3.1", + "glob": "^5.0.15", + "graceful-fs": "^4.1.2", + "iconv-lite": "^0.4.5", + "mkdirp": "^0.5.0", + "private": "^0.1.6", + "q": "^1.1.2", + "recast": "^0.11.17" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "compare-versions": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.4.0.tgz", + "integrity": "sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg==", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "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 + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.16.tgz", + "integrity": "sha512-JQfEOdnI7dASwCuSPWIeVYwc/zMsu/+tRhoUvEfXz2gxOA2DNjmG5vhtFdBlhWPPGo+RdT9S3tgc/uH5qgDiiA==", + "dev": true, + "requires": { + "mime-db": ">= 1.38.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + } + }, + "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" + } + }, + "conf": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-2.0.0.tgz", + "integrity": "sha512-iCLzBsGFi8S73EANsEJZz0JnJ/e5VZef/kSaxydYZLAvw0rFNAUx5R7K5leC/CXXR2mZfXWhUvcZOO/dM2D5xg==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "env-paths": "^1.0.0", + "make-dir": "^1.0.0", + "pkg-up": "^2.0.0", + "write-file-atomic": "^2.3.0" + } + }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "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 + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "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" + } + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "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 + }, + "copy-webpack-plugin": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz", + "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==", + "dev": true, + "requires": { + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "globby": "^7.1.1", + "is-glob": "^4.0.0", + "loader-utils": "^1.1.0", + "minimatch": "^3.0.4", + "p-limit": "^1.0.0", + "serialize-javascript": "^1.4.0" + }, + "dependencies": { + "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" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "core-js": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.4.tgz", + "integrity": "sha512-05qQ5hXShcqGkPZpXEFLIpxayZscVD2kuMBZewxiIPPEagukO4mqgPA9CWhUvFBJfy3ODdK2p9xyHh7FTU9/7A==" + }, + "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 + }, + "cosmiconfig": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.1.0.tgz", + "integrity": "sha512-kCNPvthka8gvLtzAxQXvWo4FxqRB+ftRZyPZNuab5ngvM9Y7yw7hbEysglptLgpkGX9nAOKTBVkHUAe8xtYR6Q==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "lodash.get": "^4.4.2", + "parse-json": "^4.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "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": "https://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": "https://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-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" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "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" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-loader": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.0.tgz", + "integrity": "sha512-MoOu+CStsGrSt5K2OeZ89q3Snf+IkxRfAIt9aAKg4piioTrhtP1iEFPu+OVn3Ohz24FO6L+rw9UJxBILiSBw5Q==", + "dev": true, + "requires": { + "icss-utils": "^4.0.0", + "loader-utils": "^1.2.1", + "lodash": "^4.17.11", + "postcss": "^7.0.6", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^2.0.3", + "postcss-modules-scope": "^2.0.0", + "postcss-modules-values": "^2.0.0", + "postcss-value-parser": "^3.3.0", + "schema-utils": "^1.0.0" + } + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "css-selector-tokenizer": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", + "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", + "dev": true, + "requires": { + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" + } + }, + "css-tree": { + "version": "1.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.28.tgz", + "integrity": "sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w==", + "dev": true, + "requires": { + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "css-unit-converter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz", + "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=", + "dev": true + }, + "css-url-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/css-url-regex/-/css-url-regex-1.1.0.tgz", + "integrity": "sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w=", + "dev": true + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "dev": true + }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "requires": { + "through": "X.X.X" + } + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "dev": true, + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true + }, + "csso": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz", + "integrity": "sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==", + "dev": true, + "requires": { + "css-tree": "1.0.0-alpha.29" + }, + "dependencies": { + "css-tree": { + "version": "1.0.0-alpha.29", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz", + "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", + "dev": true, + "requires": { + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "cssom": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", + "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==", + "dev": true + }, + "cssstyle": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.1.tgz", + "integrity": "sha512-7DYm8qe+gPx/h77QlCyFmX80+fGaE/6A/Ekl0zaszYOubvySO2saYFdQ78P29D0UsULxFKCetDGNaNRUdSF+2A==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "cyclist": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "dev": true + }, + "d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=", + "dev": true + }, + "dargs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-6.0.0.tgz", + "integrity": "sha512-6lJauzNaI7MiM8EHQWmGj+s3rP5/i1nYs8GAvKrLAx/9dpc9xS/4seFb1ioR39A+kcfu4v3jnEa/EE5qWYnitQ==", + "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": { + "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-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true + }, + "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 + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "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" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "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 + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "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-gateway": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-2.7.2.tgz", + "integrity": "sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ==", + "dev": true, + "requires": { + "execa": "^0.10.0", + "ip-regex": "^2.1.0" + }, + "dependencies": { + "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" + } + }, + "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" + } + }, + "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 + } + } + }, + "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" + } + } + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "requires": { + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "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 + } + } + }, + "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 + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "dependency-graph": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz", + "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==", + "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" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-conflict": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.1.tgz", + "integrity": "sha1-CIZXpmqWHAUBnbfEIwiDsca0F24=", + "dev": true + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, + "detective": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", + "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "dev": true, + "requires": { + "acorn": "^5.2.1", + "defined": "^1.0.0" + } + }, + "dev-ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz", + "integrity": "sha1-p2o+0YVb56ASu4rBbLgPPADcKPA=", + "dev": true + }, + "diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "dev": true, + "requires": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" + } + }, + "didyoumean": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.1.tgz", + "integrity": "sha1-6S7f2tplN9SE1zwBcv0eugxJdv8=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diff-sequences": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.3.0.tgz", + "integrity": "sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://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" + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + }, + "dependencies": { + "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" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "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 + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "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" + } + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "drange": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz", + "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==", + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "easy-extender": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.4.tgz", + "integrity": "sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "eazy-logger": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-3.0.2.tgz", + "integrity": "sha1-oyWqXlPROiIliJsqxBE7K5Y29Pw=", + "dev": true, + "requires": { + "tfunk": "^3.0.1" + } + }, + "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" + } + }, + "editions": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/editions/-/editions-2.1.3.tgz", + "integrity": "sha512-xDZyVm0A4nLgMNWVVLJvcwMjI80ShiH/27RyLiCnW1L273TcJIA25C4pwJ33AWV01OX6UriP35Xu+lH4S7HWQw==", + "dev": true, + "requires": { + "errlop": "^1.1.1", + "semver": "^5.6.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ejs": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", + "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.116", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.116.tgz", + "integrity": "sha512-NKwKAXzur5vFCZYBHpdWjTMO8QptNLNP80nItkSIgUOapPAo9Uia+RvkCaZJtO7fhQaVElSvBPWEc2ku6cKsPA==", + "dev": true + }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "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" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "dev": true, + "requires": { + "env-variable": "0.0.x" + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "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" + } + }, + "engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "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" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz", + "integrity": "sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~6.1.0", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "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" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "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" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "env-paths": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz", + "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=", + "dev": true + }, + "env-variable": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", + "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==", + "dev": true + }, + "envify": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/envify/-/envify-3.4.1.tgz", + "integrity": "sha1-1xIjKejfFoi6dxsSUBkXyc5cvOg=", + "dev": true, + "requires": { + "jstransform": "^11.0.3", + "through": "~2.3.4" + } + }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "dev": true + }, + "errlop": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/errlop/-/errlop-1.1.1.tgz", + "integrity": "sha512-WX7QjiPHhsny7/PQvrhS5VMizXXKoKCS3udaBp8gjlARdbn+XmK300eKBAAN0hGyRaTCtRpOaxK+xFVPUJ3zkw==", + "dev": true, + "requires": { + "editions": "^2.1.2" + } + }, + "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": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "dev": true, + "requires": { + "string-template": "~0.2.1", + "xtend": "~4.0.0" + } + }, + "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" + } + }, + "error-stack-parser": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.2.tgz", + "integrity": "sha512-E1fPutRDdIj/hohG0UpT5mayXNCxXP9d+snxFsPU9X0XgccOumKraa3juDMwTUyi7+Bu5+mCGagjg4IYeNbOdw==", + "dev": true, + "requires": { + "stackframe": "^1.0.4" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "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-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", + "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "es6-templates": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz", + "integrity": "sha1-XLmsn7He1usSOTQrgdeSu7QHjuQ=", + "dev": true, + "requires": { + "recast": "~0.11.12", + "through": "~2.3.6" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "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=" + }, + "escodegen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", + "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", + "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-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "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 + }, + "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 + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", + "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", + "dev": true + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "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" + } + }, + "exec-sh": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", + "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", + "dev": true + }, + "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" + }, + "dependencies": { + "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 + } + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, + "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": { + "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" + } + } + } + }, + "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" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "expect": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.5.0.tgz", + "integrity": "sha512-p2Gmc0CLxOgkyA93ySWmHFYHUPFIHG6XZ06l7WArWAsrqYVaVEkOU5NtT5i68KUyGKbkQgDCkiT65bWmdoL6Bw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.3.0", + "jest-matcher-utils": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-regex-util": "^24.3.0" + }, + "dependencies": { + "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" + } + } + } + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "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 + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + } + } + }, + "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": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "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-glob": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz", + "integrity": "sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "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 + }, + "fast-safe-stringify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", + "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==", + "dev": true + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "^2.0.0" + } + }, + "fbjs": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.1.tgz", + "integrity": "sha1-lja3cF9bqWhNRLcveDISVK/IYPc=", + "dev": true, + "requires": { + "core-js": "^1.0.0", + "loose-envify": "^1.0.0", + "promise": "^7.0.3", + "ua-parser-js": "^0.7.9", + "whatwg-fetch": "^0.9.0" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", + "dev": true + } + } + }, + "fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==", + "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=", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", + "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" + } + }, + "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 + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "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" + } + } + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.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-parent-dir": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", + "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", + "dev": true + }, + "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" + } + }, + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "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" + } + } + } + }, + "first-chunk-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", + "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "fn-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", + "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=", + "dev": true + }, + "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" + } + }, + "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 + } + } + }, + "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" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "fork-ts-checker-webpack-plugin": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-0.5.2.tgz", + "integrity": "sha512-a5IG+xXyKnpruI0CP/anyRLAoxWtp3lzdG6flxicANnoSzz64b12dJ7ASAVRrI2OaWwZR2JyBaMHFQqInhWhIw==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "chalk": "^2.4.1", + "chokidar": "^2.0.4", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "tapable": "^1.0.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "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" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "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" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "friendly-errors-webpack-plugin": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.0.tgz", + "integrity": "sha512-K27M3VK30wVoOarP651zDmb93R9zF28usW4ocaK3mfQeIEI5BPht/EzZs5E8QLLwbLRJQMwscAjDxYPb1FuNiw==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "error-stack-parser": "^2.0.0", + "string-width": "^2.0.0" + } + }, + "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-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "dev": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "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.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", + "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.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": "2.6.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "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.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.3", + "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.5", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.2.0", + "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.6.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 + }, + "g-status": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/g-status/-/g-status-2.0.2.tgz", + "integrity": "sha512-kQoE9qH+T1AHKgSSD0Hkv98bobE90ILQcXAF4wvGgsr7uFqNvwmh8j+Lq3l0RVt3E3HjSbv2B9biEGcEtpHLCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "matcher": "^1.0.0", + "simple-git": "^1.85.0" + } + }, + "gauge": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz", + "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=", + "dev": true, + "requires": { + "ansi": "^0.3.0", + "has-unicode": "^2.0.0", + "lodash.pad": "^4.1.0", + "lodash.padend": "^4.1.0", + "lodash.padstart": "^4.1.0" + } + }, + "generator-jhipster": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/generator-jhipster/-/generator-jhipster-5.8.2.tgz", + "integrity": "sha512-GW33cKnIf0wWuK411U9GDiNKwKVLbL4BpAqyR4b9JD6ClhwHsQg3HRlItN8pV0iTHJtyFnSfcV/9nJIHFWwvKA==", + "dev": true, + "requires": { + "axios": "0.18.0", + "chalk": "2.4.1", + "commander": "2.16.0", + "conf": "2.0.0", + "didyoumean": "1.2.1", + "ejs": "2.6.1", + "glob": "7.1.2", + "gulp-filter": "5.1.0", + "insight": "0.10.1", + "jhipster-core": "3.6.11", + "js-object-pretty-print": "0.3.0", + "js-yaml": "3.12.0", + "lodash": "4.17.10", + "meow": "5.0.0", + "mkdirp": "0.5.1", + "os-locale": "2.1.0", + "parse-gitignore": "1.0.1", + "pluralize": "7.0.0", + "prettier": "1.13.7", + "randexp": "0.4.9", + "semver": "5.5.0", + "shelljs": "0.8.2", + "tabtab": "2.2.2", + "through2": "2.0.3", + "uuid": "3.3.2", + "yeoman-environment": "2.3.0", + "yeoman-generator": "3.0.0" + }, + "dependencies": { + "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" + } + }, + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "dev": true, + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, + "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" + } + }, + "commander": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz", + "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==", + "dev": true + }, + "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" + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "dev": true + }, + "prettier": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.13.7.tgz", + "integrity": "sha512-KIU72UmYPGk4MujZGYMFwinB7lOf2LsDNGSOC8ufevsrPLISrZbNJlWstRi3m0AMuszbH+EFSQ/r6w56RSPK6w==", + "dev": true + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "shelljs": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz", + "integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "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" + } + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + } + } + } + }, + "genfun": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", + "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-own-enumerable-property-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", + "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==", + "dev": true + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "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" + } + }, + "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" + } + }, + "gh-got": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-6.0.0.tgz", + "integrity": "sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw==", + "dev": true, + "requires": { + "got": "^7.0.0", + "is-plain-obj": "^1.1.0" + } + }, + "github-username": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/github-username/-/github-username-4.1.0.tgz", + "integrity": "sha1-y+KABBiDIG2kISrp5LXxacML9Bc=", + "dev": true, + "requires": { + "gh-got": "^6.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" + } + } + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "dev": true + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "dev": true, + "requires": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + }, + "dependencies": { + "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 + } + } + }, + "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 + }, + "grouped-queue": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.3.tgz", + "integrity": "sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=", + "dev": true, + "requires": { + "lodash": "^4.17.2" + } + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "gulp-filter": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/gulp-filter/-/gulp-filter-5.1.0.tgz", + "integrity": "sha1-oF4Rr/sHz33PQafeHLe2OsN4PnM=", + "dev": true, + "requires": { + "multimatch": "^2.0.0", + "plugin-error": "^0.1.2", + "streamfilter": "^1.0.5" + } + }, + "handle-thing": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==", + "dev": true + }, + "handlebars": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz", + "integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "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 + } + } + }, + "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-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "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-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "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-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "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.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "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" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "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 + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "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" + } + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "html-loader": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-0.5.5.tgz", + "integrity": "sha512-7hIW7YinOYUpo//kSYcPB6dCKoceKLmOwjEMmhIobHuWGDVl0Nwe4l68mdG/Ru0wcUxQjVMEoZpkalZ/SE7zog==", + "dev": true, + "requires": { + "es6-templates": "^0.2.3", + "fastparse": "^1.1.1", + "html-minifier": "^3.5.8", + "loader-utils": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "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 + } + } + }, + "html-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", + "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", + "dev": true, + "requires": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "dependencies": { + "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 + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz", + "integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "dependencies": { + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.0.tgz", + "integrity": "sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==", + "dev": true + }, + "http-proxy": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.15.2.tgz", + "integrity": "sha1-ZC/cr/5S00SNK9o7AHnpQJBk2jE=", + "dev": true, + "requires": { + "eventemitter3": "1.x.x", + "requires-port": "1.x.x" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "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" + } + } + } + }, + "http-proxy-middleware": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz", + "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==", + "dev": true, + "requires": { + "http-proxy": "^1.16.2", + "is-glob": "^4.0.0", + "lodash": "^4.17.5", + "micromatch": "^3.1.9" + }, + "dependencies": { + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "dev": true + }, + "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-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 + }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "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" + } + }, + "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 + } + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "husky": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-1.3.1.tgz", + "integrity": "sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.7", + "execa": "^1.0.0", + "find-up": "^3.0.0", + "get-stdin": "^6.0.0", + "is-ci": "^2.0.0", + "pkg-dir": "^3.0.0", + "please-upgrade-node": "^3.1.1", + "read-pkg": "^4.0.1", + "run-node": "^1.0.0", + "slash": "^2.0.0" + }, + "dependencies": { + "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" + } + }, + "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-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.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": "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.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "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" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "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" + } + }, + "read-pkg": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", + "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", + "dev": true, + "requires": { + "normalize-package-data": "^2.3.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.0.tgz", + "integrity": "sha512-3DEun4VOeMvSczifM3F2cKQrDQ5Pj6WKhkOq6HD4QTnDUAq8MQRxy5TX6Sy1iY6WPBe4gQ3p5vTECjbIkglkkQ==", + "dev": true, + "requires": { + "postcss": "^7.0.14" + } + }, + "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": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=", + "dev": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "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.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": "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.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "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 + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "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 + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz", + "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=", + "requires": { + "ansi-escapes": "^1.1.0", + "chalk": "^1.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.1", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx": "^4.1.0", + "string-width": "^2.0.0", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "insight": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/insight/-/insight-0.10.1.tgz", + "integrity": "sha512-kLGeYQkh18f8KuC68QKdi0iwUcIaayJVB/STpX7x452/7pAUm1yfG4giJwcxbrTh0zNYtc8kBR+6maLMOzglOQ==", + "dev": true, + "requires": { + "async": "^2.1.4", + "chalk": "^2.3.0", + "conf": "^1.3.1", + "inquirer": "^5.0.0", + "lodash.debounce": "^4.0.8", + "os-name": "^2.0.1", + "request": "^2.74.0", + "tough-cookie": "^2.0.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "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" + } + }, + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "conf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-1.4.0.tgz", + "integrity": "sha512-bzlVWS2THbMetHqXKB8ypsXN4DQ/1qopGwNJi1eYbpwesJcd86FBjFciCQX/YwAhp9bM7NVnPFqZ5LpV7gP0Dg==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "env-paths": "^1.0.0", + "make-dir": "^1.0.0", + "pkg-up": "^2.0.0", + "write-file-atomic": "^2.3.0" + } + }, + "inquirer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", + "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.1.0", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^5.5.2", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + } + }, + "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" + } + }, + "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-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + } + } + }, + "internal-ip": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-3.0.1.tgz", + "integrity": "sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q==", + "dev": true, + "requires": { + "default-gateway": "^2.6.0", + "ipaddr.js": "^1.5.2" + } + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "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-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "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-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "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=" + }, + "is-generator-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.0.0.tgz", + "integrity": "sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g==", + "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-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "dev": true, + "requires": { + "lodash.isfinite": "^3.3.2" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", + "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", + "dev": true, + "requires": { + "symbol-observable": "^1.1.0" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "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=" + }, + "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-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, + "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-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true + }, + "is-scoped": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-1.0.0.tgz", + "integrity": "sha1-RJypgpnnEwOCViieyytUDcQ3yzA=", + "dev": true, + "requires": { + "scoped-regex": "^1.0.0" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "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-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "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 + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "isemail": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", + "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", + "dev": true, + "requires": { + "punycode": "2.x.x" + } + }, + "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-api": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.1.tgz", + "integrity": "sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw==", + "dev": true, + "requires": { + "async": "^2.6.1", + "compare-versions": "^3.2.1", + "fileset": "^2.0.3", + "istanbul-lib-coverage": "^2.0.3", + "istanbul-lib-hook": "^2.0.3", + "istanbul-lib-instrument": "^3.1.0", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.2", + "istanbul-reports": "^2.1.1", + "js-yaml": "^3.12.0", + "make-dir": "^1.3.0", + "minimatch": "^3.0.4", + "once": "^1.4.0" + }, + "dependencies": { + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz", + "integrity": "sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "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.3", + "semver": "^5.5.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz", + "integrity": "sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.3", + "make-dir": "^1.3.0", + "supports-color": "^6.0.0" + }, + "dependencies": { + "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.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz", + "integrity": "sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.3", + "make-dir": "^1.3.0", + "rimraf": "^2.6.2", + "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" + } + }, + "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 + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.1.tgz", + "integrity": "sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw==", + "dev": true, + "requires": { + "handlebars": "^4.1.0" + } + }, + "istextorbinary": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.5.1.tgz", + "integrity": "sha512-pv/JNPWnfpwGjPx7JrtWTwsWsxkrK3fNzcEVnt92YKEIErps4Fsk49+qzCe9iQF2hjqK8Naqf8P9kzoeCuQI1g==", + "dev": true, + "requires": { + "binaryextensions": "^2.1.2", + "editions": "^2.1.3", + "textextensions": "^2.4.0" + } + }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, + "jest": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.1.0.tgz", + "integrity": "sha512-+q91L65kypqklvlRFfXfdzUKyngQLOcwGhXQaLmVHv+d09LkNXuBuGxlofTFW42XMzu3giIcChchTsCNUjQ78A==", + "dev": true, + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.1.0" + }, + "dependencies": { + "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" + } + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + }, + "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" + } + }, + "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-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" + } + }, + "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 + }, + "jest-cli": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.5.0.tgz", + "integrity": "sha512-P+Jp0SLO4KWN0cGlNtC7JV0dW1eSFR7eRpoOucP2UM0sqlzp/bVHeo71Omonvigrj9AvCKy7NtQANtqJ7FXz8g==", + "dev": true, + "requires": { + "@jest/core": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^12.0.2" + } + }, + "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" + } + }, + "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" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, + "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": "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.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + } + } + }, + "jest-changed-files": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.5.0.tgz", + "integrity": "sha512-Ikl29dosYnTsH9pYa1Tv9POkILBhN/TLZ37xbzgNsZ1D2+2n+8oEZS2yP1BrHn/T4Rs4Ggwwbp/x8CKOS5YJOg==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + }, + "dependencies": { + "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" + } + }, + "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" + } + } + } + }, + "jest-config": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.5.0.tgz", + "integrity": "sha512-t2UTh0Z2uZhGBNVseF8wA2DS2SuBiLOL6qpLq18+OZGfFUxTM7BzUVKyHFN/vuN+s/aslY1COW95j1Rw81huOQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.5.0", + "babel-jest": "^24.5.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.5.0", + "jest-environment-node": "^24.5.0", + "jest-get-type": "^24.3.0", + "jest-jasmine2": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.5.0", + "realpath-native": "^1.1.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "jest-diff": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.5.0.tgz", + "integrity": "sha512-mCILZd9r7zqL9Uh6yNoXjwGQx0/J43OD2vvWVKwOEOLZliQOsojXwqboubAQ+Tszrb6DHGmNU7m4whGeB9YOqw==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.3.0", + "jest-get-type": "^24.3.0", + "pretty-format": "^24.5.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "jest-docblock": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.3.0.tgz", + "integrity": "sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.5.0.tgz", + "integrity": "sha512-6gy3Kh37PwIT5sNvNY2VchtIFOOBh8UCYnBlxXMb5sr5wpJUDPTUATX2Axq1Vfk+HWTMpsYPeVYp4TXx5uqUBw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.3.0", + "jest-util": "^24.5.0", + "pretty-format": "^24.5.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "jest-environment-jsdom": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.5.0.tgz", + "integrity": "sha512-62Ih5HbdAWcsqBx2ktUnor/mABBo1U111AvZWcLKeWN/n/gc5ZvDBKe4Og44fQdHKiXClrNGC6G0mBo6wrPeGQ==", + "dev": true, + "requires": { + "@jest/environment": "^24.5.0", + "@jest/fake-timers": "^24.5.0", + "@jest/types": "^24.5.0", + "jest-mock": "^24.5.0", + "jest-util": "^24.5.0", + "jsdom": "^11.5.1" + } + }, + "jest-environment-node": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.5.0.tgz", + "integrity": "sha512-du6FuyWr/GbKLsmAbzNF9mpr2Iu2zWSaq/BNHzX+vgOcts9f2ayXBweS7RAhr+6bLp6qRpMB6utAMF5Ygktxnw==", + "dev": true, + "requires": { + "@jest/environment": "^24.5.0", + "@jest/fake-timers": "^24.5.0", + "@jest/types": "^24.5.0", + "jest-mock": "^24.5.0", + "jest-util": "^24.5.0" + } + }, + "jest-get-type": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.3.0.tgz", + "integrity": "sha512-HYF6pry72YUlVcvUx3sEpMRwXEWGEPlJ0bSPVnB3b3n++j4phUEoSPcS6GC0pPJ9rpyPSe4cb5muFo6D39cXow==", + "dev": true + }, + "jest-haste-map": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.5.0.tgz", + "integrity": "sha512-mb4Yrcjw9vBgSvobDwH8QUovxApdimGcOkp+V1ucGGw4Uvr3VzZQBJhNm1UY3dXYm4XXyTW2G7IBEZ9pM2ggRQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.4.0", + "jest-util": "^24.5.0", + "jest-worker": "^24.4.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3" + } + }, + "jest-jasmine2": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.5.0.tgz", + "integrity": "sha512-sfVrxVcx1rNUbBeyIyhkqZ4q+seNKyAG6iM0S2TYBdQsXjoFDdqWFfsUxb6uXSsbimbXX/NMkJIwUZ1uT9+/Aw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.5.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.5.0", + "jest-matcher-utils": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-snapshot": "^24.5.0", + "jest-util": "^24.5.0", + "pretty-format": "^24.5.0", + "throat": "^4.0.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "jest-junit": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-6.2.1.tgz", + "integrity": "sha512-zMbwKzZGo9TQOjdBUNQdTEf81QvOrwiQtLIUSEyCwPXYx/G/DJGXEJcqs8viXxn6poJ4Xh4pYGDLD0DKDwtfVA==", + "dev": true, + "requires": { + "jest-validate": "^24.0.0", + "mkdirp": "^0.5.1", + "strip-ansi": "^4.0.0", + "xml": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "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" + } + } + } + }, + "jest-leak-detector": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.5.0.tgz", + "integrity": "sha512-LZKBjGovFRx3cRBkqmIg+BZnxbrLqhQl09IziMk3oeh1OV81Hg30RUIx885mq8qBv1PA0comB9bjKcuyNO1bCQ==", + "dev": true, + "requires": { + "pretty-format": "^24.5.0" + } + }, + "jest-matcher-utils": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.5.0.tgz", + "integrity": "sha512-QM1nmLROjLj8GMGzg5VBra3I9hLpjMPtF1YqzQS3rvWn2ltGZLrGAO1KQ9zUCVi5aCvrkbS5Ndm2evIP9yZg1Q==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.5.0", + "jest-get-type": "^24.3.0", + "pretty-format": "^24.5.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "jest-message-util": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.5.0.tgz", + "integrity": "sha512-6ZYgdOojowCGiV0D8WdgctZEAe+EcFU+KrVds+0ZjvpZurUW2/oKJGltJ6FWY2joZwYXN5VL36GPV6pNVRqRnQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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" + } + } + } + }, + "jest-mock": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.5.0.tgz", + "integrity": "sha512-ZnAtkWrKf48eERgAOiUxVoFavVBziO2pAi2MfZ1+bGXVkDfxWLxU0//oJBkgwbsv6OAmuLBz4XFFqvCFMqnGUw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", + "dev": true + }, + "jest-preset-angular": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/jest-preset-angular/-/jest-preset-angular-6.0.2.tgz", + "integrity": "sha512-uhrllY41tUvkeR41aX9bU5w3/EvvmwZiJ3UitDhRSEJL2Jvq2N/xKlmw7qvlZoGZnciFjOUJ2WDKv5fmCrvnQA==", + "dev": true, + "requires": { + "@types/jest": "^23.3.1", + "jest-zone-patch": ">=0.0.9 <1.0.0", + "ts-jest": "~23.1.3" + }, + "dependencies": { + "@types/jest": { + "version": "23.3.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-23.3.14.tgz", + "integrity": "sha512-Q5hTcfdudEL2yOmluA1zaSyPbzWPmJ3XfSWeP3RyoYvS9hnje1ZyagrZOuQ6+1nQC1Gw+7gap3pLNL3xL6UBug==", + "dev": true + } + } + }, + "jest-regex-util": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.3.0.tgz", + "integrity": "sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg==", + "dev": true + }, + "jest-resolve": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.5.0.tgz", + "integrity": "sha512-ZIfGqLX1Rg8xJpQqNjdoO8MuxHV1q/i2OO1hLXjgCWFWs5bsedS8UrOdgjUqqNae6DXA+pCyRmdcB7lQEEbXew==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.5.0.tgz", + "integrity": "sha512-dRVM1D+gWrFfrq2vlL5P9P/i8kB4BOYqYf3S7xczZ+A6PC3SgXYSErX/ScW/469pWMboM1uAhgLF+39nXlirCQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.5.0" + } + }, + "jest-runner": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.5.0.tgz", + "integrity": "sha512-oqsiS9TkIZV5dVkD+GmbNfWBRPIvxqmlTQ+AQUJUQ07n+4xTSDc40r+aKBynHw9/tLzafC00DIbJjB2cOZdvMA==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/environment": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.5.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.5.0", + "jest-jasmine2": "^24.5.0", + "jest-leak-detector": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-resolve": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-util": "^24.5.0", + "jest-worker": "^24.4.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "jest-runtime": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.5.0.tgz", + "integrity": "sha512-GTFHzfLdwpaeoDPilNpBrorlPoNZuZrwKKzKJs09vWwHo+9TOsIIuszK8cWOuKC7ss07aN1922Ge8fsGdsqCuw==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/environment": "^24.5.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/yargs": "^12.0.2", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.5.0", + "jest-haste-map": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-mock": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.5.0", + "jest-snapshot": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^12.0.2" + }, + "dependencies": { + "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" + } + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + }, + "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" + } + }, + "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-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" + } + }, + "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 + }, + "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" + } + }, + "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" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, + "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": "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.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + } + } + }, + "jest-serializer": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.4.0.tgz", + "integrity": "sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q==", + "dev": true + }, + "jest-snapshot": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.5.0.tgz", + "integrity": "sha512-eBEeJb5ROk0NcpodmSKnCVgMOo+Qsu5z9EDl3tGffwPzK1yV37mjGWF2YeIz1NkntgTzP+fUL4s09a0+0dpVWA==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "expect": "^24.5.0", + "jest-diff": "^24.5.0", + "jest-matcher-utils": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-resolve": "^24.5.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.5.0", + "semver": "^5.5.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "jest-sonar-reporter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jest-sonar-reporter/-/jest-sonar-reporter-2.0.0.tgz", + "integrity": "sha512-ZervDCgEX5gdUbdtWsjdipLN3bKJwpxbvhkYNXTAYvAckCihobSLr9OT/IuyNIRT1EZMDDwR6DroWtrq+IL64w==", + "dev": true, + "requires": { + "xml": "^1.0.1" + } + }, + "jest-util": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.5.0.tgz", + "integrity": "sha512-Xy8JsD0jvBz85K7VsTIQDuY44s+hYJyppAhcsHsOsGisVtdhar6fajf2UOf2mEVEgh15ZSdA0zkCuheN8cbr1Q==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/fake-timers": "^24.5.0", + "@jest/source-map": "^24.3.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/node": "*", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "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" + } + }, + "callsites": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", + "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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 + }, + "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" + } + } + } + }, + "jest-validate": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.5.0.tgz", + "integrity": "sha512-gg0dYszxjgK2o11unSIJhkOFZqNRQbWOAB2/LOUdsd2LfD9oXiMeuee8XsT0iRy5EvSccBgB4h/9HRbIo3MHgQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "camelcase": "^5.0.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.3.0", + "leven": "^2.1.0", + "pretty-format": "^24.5.0" + }, + "dependencies": { + "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" + } + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "jest-watcher": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.5.0.tgz", + "integrity": "sha512-/hCpgR6bg0nKvD3nv4KasdTxuhwfViVMHUATJlnGCD0r1QrmIssimPbmc5KfAQblAVxkD8xrzuij9vfPUk1/rA==", + "dev": true, + "requires": { + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/node": "*", + "@types/yargs": "^12.0.9", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.5.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "jest-worker": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.4.0.tgz", + "integrity": "sha512-BH9X/klG9vxwoO99ZBUbZFfV8qO0XNZ5SIiCyYK2zOuJBl6YJVAeNIQjcoOVNu4HGEHeYEKsUWws8kSlSbZ9YQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^1.0.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "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" + } + } + } + }, + "jest-zone-patch": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/jest-zone-patch/-/jest-zone-patch-0.0.10.tgz", + "integrity": "sha512-K5uHLHgMgi2Eyj74gbY+xSeGGekb5U48bXsgDwgipRbFdaekyZK+TAcp8auamqU4UjrAt5S4sIUZz/2bBNyTTA==", + "dev": true + }, + "jhipster-core": { + "version": "3.6.11", + "resolved": "https://registry.npmjs.org/jhipster-core/-/jhipster-core-3.6.11.tgz", + "integrity": "sha512-OibJay1+nwKk+mfRfuTrt2rW2h7BmGNfKWR7TQO4oYqG+I096EvJxZkIMCcjA9KuKLOZvnzfEi4UbtKyRTmHkg==", + "dev": true, + "requires": { + "chevrotain": "4.2.0", + "fs-extra": "7.0.1", + "lodash": "4.17.11", + "winston": "3.2.1" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + } + } + }, + "joi": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz", + "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==", + "dev": true, + "requires": { + "hoek": "4.x.x", + "isemail": "3.x.x", + "topo": "2.x.x" + } + }, + "js-object-pretty-print": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/js-object-pretty-print/-/js-object-pretty-print-0.3.0.tgz", + "integrity": "sha1-RnDkUAZu4ezPNRdMfRl/WqOLz3Q=", + "dev": true + }, + "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 + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "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.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "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": "^5.2.0", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "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 + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "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" + } + }, + "jstransform": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz", + "integrity": "sha1-CaeJk+CuTU70SH9hVakfYZDLQiM=", + "dev": true, + "requires": { + "base62": "^1.1.0", + "commoner": "^0.10.1", + "esprima-fb": "^15001.1.0-dev-harmony-fb", + "object-assign": "^2.0.0", + "source-map": "^0.4.2" + }, + "dependencies": { + "esprima-fb": { + "version": "15001.1.0-dev-harmony-fb", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz", + "integrity": "sha1-MKlHMDxrjV6VW+4rmbHSMyBqaQE=", + "dev": true + }, + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "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 + }, + "kleur": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.2.tgz", + "integrity": "sha512-3h7B2WRT5LNXOtQiAaWonilegHcPSf9nLVXlSTci8lu1dZUuui61+EsPEZqSVxY7rXYmB2DVKMQILxaO5WL61Q==", + "dev": true + }, + "kuler": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", + "dev": true, + "requires": { + "colornames": "^1.1.1" + } + }, + "last-call-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "dev": true, + "requires": { + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" + } + }, + "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" + } + }, + "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 + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "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" + } + }, + "limiter": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.4.tgz", + "integrity": "sha512-XCpr5bElgDI65vVgstP8TWjv6/QKWm9GU5UG0Pr5sLQ3QLo8NVKsioe+Jed5/3vFOe3IQuqE7DKwTvKQkjTHvg==", + "dev": true + }, + "lint-staged": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.3.tgz", + "integrity": "sha512-6TGkikL1B+6mIOuSNq2TV6oP21IhPMnV8q0cf9oYZ296ArTVNcbFh1l1pfVOHHbBIYLlziWNsQ2q45/ffmJ4AA==", + "dev": true, + "requires": { + "@iamstarkov/listr-update-renderer": "0.4.1", + "chalk": "^2.3.1", + "commander": "^2.14.1", + "cosmiconfig": "^5.0.2", + "debug": "^3.1.0", + "dedent": "^0.7.0", + "del": "^3.0.0", + "execa": "^1.0.0", + "find-parent-dir": "^0.3.0", + "g-status": "^2.0.2", + "is-glob": "^4.0.0", + "is-windows": "^1.0.2", + "listr": "^0.14.2", + "lodash": "^4.17.5", + "log-symbols": "^2.2.0", + "micromatch": "^3.1.8", + "npm-which": "^3.0.1", + "p-map": "^1.1.1", + "path-is-inside": "^1.0.2", + "pify": "^3.0.0", + "please-upgrade-node": "^3.0.2", + "staged-git-files": "1.1.2", + "string-argv": "^0.0.2", + "stringify-object": "^3.2.2", + "yup": "^0.26.10" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.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" + } + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "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" + } + } + } + }, + "listr": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", + "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", + "dev": true, + "requires": { + "@samverschueren/stream-to-observable": "^0.3.0", + "is-observable": "^1.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "p-map": "^2.0.0", + "rxjs": "^6.3.3" + }, + "dependencies": { + "p-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.0.0.tgz", + "integrity": "sha512-GO107XdrSUmtHxVoi60qc9tUl/KkNKm+X2CF4P9amalpGxv5YqVPJNfSb0wcA+syCopkZvYYIzW8OVTQW59x/w==", + "dev": true + } + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", + "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + } + } + }, + "listr-verbose-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", + "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", + "date-fns": "^1.27.2", + "figures": "^2.0.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "localtunnel": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.9.1.tgz", + "integrity": "sha512-HWrhOslklDvxgOGFLxi6fQVnvpl6XdX4sPscfqMZkzi3gtt9V7LKBWYvNUcpHSVvjwCQ6xzXacVvICNbNcyPnQ==", + "dev": true, + "requires": { + "axios": "0.17.1", + "debug": "2.6.9", + "openurl": "1.1.1", + "yargs": "6.6.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "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" + } + }, + "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" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.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" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^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-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^4.2.0" + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + } + } + } + }, + "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.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "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.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha1-+4m2WpqAKBgz8LdHizpRBPiY67M=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.pad": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", + "integrity": "sha1-QzCUmoM6fI2iLMIPaibE1Z3runA=", + "dev": true + }, + "lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=", + "dev": true + }, + "lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=", + "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 + }, + "lodash.tail": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", + "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", + "dev": true + }, + "lodash.template": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", + "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", + "dev": true, + "requires": { + "lodash._reinterpolate": "~3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", + "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", + "dev": true, + "requires": { + "lodash._reinterpolate": "~3.0.0" + } + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "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 + }, + "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" + } + }, + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + } + } + } + }, + "logform": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", + "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", + "dev": true, + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^2.3.3", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "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 + } + } + }, + "loglevel": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", + "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", + "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" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "macos-release": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-1.1.0.tgz", + "integrity": "sha512-mmLbumEYMi5nXReB9js3WGsB8UE6cDBWyIO62Z4DNx6GbRhDxHNjA1MlzSpJ2S2KM1wyiPRA0d19uHWYYvMHjA==", + "dev": true + }, + "magic-string": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.2.tgz", + "integrity": "sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "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" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "make-fetch-happen": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz", + "integrity": "sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ==", + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^11.0.1", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, + "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-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "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" + } + }, + "matcher": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz", + "integrity": "sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.4" + } + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "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" + } + }, + "mdn-data": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", + "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "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" + } + }, + "mem-fs": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.3.tgz", + "integrity": "sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=", + "dev": true, + "requires": { + "through2": "^2.0.0", + "vinyl": "^1.1.0", + "vinyl-file": "^2.0.0" + } + }, + "mem-fs-editor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-5.1.0.tgz", + "integrity": "sha512-2Yt2GCYEbcotYbIJagmow4gEtHDqzpq5XN94+yAx/NT5+bGqIjkXnm3KCUQfE6kRfScGp9IZknScoGRKu8L78w==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "deep-extend": "^0.6.0", + "ejs": "^2.5.9", + "glob": "^7.0.3", + "globby": "^8.0.1", + "isbinaryfile": "^3.0.2", + "mkdirp": "^0.5.0", + "multimatch": "^2.0.0", + "rimraf": "^2.2.8", + "through2": "^2.0.0", + "vinyl": "^2.0.1" + }, + "dependencies": { + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "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" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, + "vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.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" + } + }, + "meow": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", + "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0", + "yargs-parser": "^10.0.0" + }, + "dependencies": { + "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" + } + }, + "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" + } + }, + "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" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "merge2": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", + "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "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.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", + "dev": true + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "dev": true, + "requires": { + "mime-db": "~1.38.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==" + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz", + "integrity": "sha512-IuaLjruM0vMKhUUT51fQdQzBYTX49dLj8w68ALEAe2A4iYNpIC4eMac67mt3NzycvjOlf07/kYxJDc0RTl1Wqw==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + } + }, + "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": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "minimist-options": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0" + } + }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "dev": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "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" + } + }, + "mitt": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.1.3.tgz", + "integrity": "sha512-mUDCnVNsAi+eD6qA0HkRkwYczbLHJ49z17BGe2PYRhZL4wpZUFZGJHU7/5tmvohoma+Hdn0Vh/oJTiPEmgSruA==", + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "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" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "moment-locales-webpack-plugin": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/moment-locales-webpack-plugin/-/moment-locales-webpack-plugin-1.0.7.tgz", + "integrity": "sha512-KjYpaAhmuzGFZl6534FlZoK7QtW3vqlxd+A17W9DlgHJ5yhXANy7AZJl7iYtZpWjAfMTAWiVrQ7YDZdkFO6uRw==", + "dev": true, + "requires": { + "lodash.difference": "^4.5.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.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "dev": true, + "requires": { + "array-differ": "^1.0.0", + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "minimatch": "^3.0.0" + } + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "nan": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.1.tgz", + "integrity": "sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA==", + "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 + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "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 + }, + "ng-jhipster": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/ng-jhipster/-/ng-jhipster-0.9.1.tgz", + "integrity": "sha512-/ViJ6bNtc/4w6valKNvHKyvXF1cn1OBnSEh3Q8aEUHtmoyr9owReTGHT7ylNclthUsxztRMUS4GrMMEQ5kM09Q==", + "requires": { + "tslib": "^1.9.0" + } + }, + "ngx-cookie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ngx-cookie/-/ngx-cookie-2.0.1.tgz", + "integrity": "sha512-3+agXZkoPxRP3IyELf7Eiuhk6TX+EAX974kkCR6Xjm+N7boEA+Fin2Q90AAE4XZzY48skkVzLH96TOikb5yU3g==" + }, + "ngx-infinite-scroll": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-7.0.1.tgz", + "integrity": "sha512-be9DAAuabV7VGI06/JUnS6pXC6mcBOzA4+SBCwOcP9WwJ2r5GjdZyOa34ls9hi1MnCOj3zrXLvPKQ/UDp6csIw==", + "requires": { + "opencollective": "^1.0.3" + } + }, + "ngx-webstorage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ngx-webstorage/-/ngx-webstorage-2.0.1.tgz", + "integrity": "sha512-AhBkl1v5sBLYiGC1DuHxM90B8OewqyhYhm+KGtJIFxMh5dj3tlNgPokmWCtKcUZF26m8MgxDDuP5e6NeDCpYQw==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-fetch": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", + "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "node-fetch-npm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", + "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", + "dev": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-forge": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", + "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", + "dev": true + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", + "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", + "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": "^3.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.11.0", + "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-notifier": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", + "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + } + }, + "node-releases": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.11.tgz", + "integrity": "sha512-8v1j5KfP+s5WOTa1spNUAOfreajQPN12JXbRR0oDE+YrJBQCXBnNqUDj27EKpPLOoSiU3tKi3xGPB+JaOdUEQQ==", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.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" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true + }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "dev": true + }, + "npm-package-arg": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz", + "integrity": "sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.6.0", + "osenv": "^0.1.5", + "semver": "^5.5.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", + "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npm-path": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", + "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "dev": true, + "requires": { + "which": "^1.2.10" + } + }, + "npm-pick-manifest": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz", + "integrity": "sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "npm-registry-fetch": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz", + "integrity": "sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw==", + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^4.1.3", + "make-fetch-happen": "^4.0.1", + "npm-package-arg": "^6.1.0" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "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" + } + }, + "npm-which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", + "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "dev": true, + "requires": { + "commander": "^2.9.0", + "npm-path": "^2.0.2", + "which": "^1.2.10" + } + }, + "npmlog": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz", + "integrity": "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI=", + "dev": true, + "requires": { + "ansi": "~0.3.1", + "are-we-there-yet": "~1.1.2", + "gauge": "~1.2.5" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.1.tgz", + "integrity": "sha512-T5GaA1J/d34AC8mkrFD2O0DR17kwJ702ZOtJOsS8RpbsQZVOC2/xYFb1i/cw+xdM54JIlMuojjDOYct8GIWtwg==", + "dev": true + }, + "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=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "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-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", + "dev": true + }, + "object-path": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.9.2.tgz", + "integrity": "sha1-D9mnT8X60a45aLWGvaXGMr1sBaU=", + "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" + } + }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "one-time": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", + "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "opencollective": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz", + "integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=", + "requires": { + "babel-polyfill": "6.23.0", + "chalk": "1.1.3", + "inquirer": "3.0.6", + "minimist": "1.2.0", + "node-fetch": "1.6.3", + "opn": "4.0.2" + } + }, + "openurl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", + "integrity": "sha1-OHW0sO96UsFW8NtB1GCduw+Us4c=", + "dev": true + }, + "opn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "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": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "optimize-css-assets-webpack-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-Rqm6sSjWtx9FchdP0uzTQDc7GXDKnwVEGoSxjezPkzMewx7gEWE9IMUYKmigTRC4U3RaNSwYVnUDLuIdtTpm0A==", + "dev": true, + "requires": { + "cssnano": "^4.1.0", + "last-call-webpack-plugin": "^3.0.0" + } + }, + "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" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "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": "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" + } + }, + "os-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-2.0.1.tgz", + "integrity": "sha1-uaOGNhwXrjohc27wWZQFyajF3F4=", + "dev": true, + "requires": { + "macos-release": "^1.0.0", + "win-release": "^1.0.0" + } + }, + "os-shim": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "dev": true + }, + "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-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", + "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-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "dev": true, + "requires": { + "p-finally": "^1.0.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 + }, + "pacote": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.4.0.tgz", + "integrity": "sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^11.3.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^4.0.1", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^2.2.3", + "npm-registry-fetch": "^3.8.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.8", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + } + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "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" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parse-asn1": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", + "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", + "safe-buffer": "^5.1.1" + } + }, + "parse-gitignore": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-gitignore/-/parse-gitignore-1.0.1.tgz", + "integrity": "sha512-UGyowyjtx26n65kdAMWhm6/3uy5uSrpcuH7tt+QEVudiBoVS+eqHxD5kbi9oWVRwj7sCzXqwuM+rUGw7earl6A==", + "dev": true + }, + "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": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "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": "https://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-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "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": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "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" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "please-upgrade-node": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz", + "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, + "plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", + "dev": true, + "requires": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "dependencies": { + "arr-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + } + }, + "arr-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", + "dev": true + }, + "extend-shallow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", + "dev": true, + "requires": { + "kind-of": "^1.1.0" + } + }, + "kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", + "dev": true + } + } + }, + "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" + } + }, + "portscanner": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.1.1.tgz", + "integrity": "sha1-6rtAnk3iSVD1oqUW01rnaTQ/u5Y=", + "dev": true, + "requires": { + "async": "1.5.2", + "is-number-like": "^1.0.3" + } + }, + "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 + }, + "postcss": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", + "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "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" + } + } + } + }, + "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 + }, + "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" + } + } + } + }, + "postcss-calc": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.1.tgz", + "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", + "dev": true, + "requires": { + "css-unit-converter": "^1.1.1", + "postcss": "^7.0.5", + "postcss-selector-parser": "^5.0.0-rc.4", + "postcss-value-parser": "^3.3.1" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-load-config": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz", + "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==", + "dev": true, + "requires": { + "cosmiconfig": "^4.0.0", + "import-cwd": "^2.0.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz", + "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0", + "require-from-string": "^2.0.1" + } + }, + "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" + } + } + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz", + "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0", + "postcss-value-parser": "^3.3.1" + } + }, + "postcss-modules-scope": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz", + "integrity": "sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz", + "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==", + "dev": true, + "requires": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^7.0.6" + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", + "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "dependencies": { + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + } + } + }, + "postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "dev": true, + "requires": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "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 + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "prettier": { + "version": "1.16.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", + "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==", + "dev": true + }, + "pretty-bytes": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.1.0.tgz", + "integrity": "sha512-wa5+qGVg9Yt7PB6rYm3kXlKzgzgivYTLRandezh43jjRqgyDyP+9YxfJpJiLs9yKD1WeU8/OvtToWpW7255FtA==", + "dev": true + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "dev": true, + "requires": { + "renderkid": "^2.0.1", + "utila": "~0.4" + } + }, + "pretty-format": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.5.0.tgz", + "integrity": "sha512-/3RuSghukCf8Riu5Ncve0iI+BzVkbRU5EeUoArKARZobREycuH5O4waxvaNIloEXdb0qwgmEAed5vTpX1HNROQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + }, + "dependencies": { + "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 + }, + "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" + } + } + } + }, + "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 + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "requires": { + "asap": "~2.0.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise-retry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "dev": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + } + }, + "prompts": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.0.4.tgz", + "integrity": "sha512-HTzM3UWp/99A0gk51gAegwo1QRYA7xjcZufMNe33rCclFszUYAuHe1fIN/3ZmiHeGPkUsNaRyQm1hHOfM0PKxA==", + "dev": true, + "requires": { + "kleur": "^3.0.2", + "sisteransi": "^1.0.0" + } + }, + "property-expr": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", + "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", + "dev": true + }, + "protoduck": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "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.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "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": "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" + } + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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 + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", + "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", + "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 + }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==", + "dev": true + }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, + "randexp": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.9.tgz", + "integrity": "sha512-maAX1cnBkzIZ89O4tSQUOF098xjGMC8N+9vuY/WfHwg87THw6odD2Br35donlj5e6KnB1SB0QBHhTQhhDHuTPQ==", + "dev": true, + "requires": { + "drange": "^1.0.0", + "ret": "^0.2.0" + }, + "dependencies": { + "ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "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.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "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" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "react": { + "version": "0.14.9", + "resolved": "https://registry.npmjs.org/react/-/react-0.14.9.tgz", + "integrity": "sha1-kRCmSXxJ1EuhwO3TF67CnC4NkdE=", + "dev": true, + "requires": { + "envify": "^3.0.0", + "fbjs": "^0.6.1" + } + }, + "react-dom": { + "version": "0.14.9", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-0.14.9.tgz", + "integrity": "sha1-BQZKPc8PsYgKOyv8nVjFXY2fYpM=", + "dev": true + }, + "react-is": { + "version": "16.8.4", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.4.tgz", + "integrity": "sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA==", + "dev": true + }, + "read-chunk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", + "integrity": "sha1-agTAkoAF7Z1C4aasVgDhnLx/9lU=", + "dev": true, + "requires": { + "pify": "^3.0.0", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://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" + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "recast": { + "version": "0.11.23", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz", + "integrity": "sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=", + "dev": true, + "requires": { + "ast-types": "0.9.6", + "esprima": "~3.1.0", + "private": "~0.1.5", + "source-map": "~0.5.0" + }, + "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.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "^3.0.0", + "strip-indent": "^2.0.0" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + }, + "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" + } + }, + "regexp-to-ast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.3.5.tgz", + "integrity": "sha512-1CJygtdvsfNFwiyjaMLBWtg2tfEqx/jSZ8S6TV+GlNL8kiH8rb4cm5Pb7A/C2BpyM/fA8ZJEudlCwi/jvAY+Ow==", + "dev": true + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "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 + }, + "renderkid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz", + "integrity": "sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==", + "dev": true, + "requires": { + "css-select": "^1.1.0", + "dom-converter": "^0.2", + "htmlparser2": "^3.3.0", + "strip-ansi": "^3.0.0", + "utila": "^0.4.0" + } + }, + "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 + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "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" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "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 + }, + "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" + } + } + } + }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "dev": true, + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "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-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "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 + }, + "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.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "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" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "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-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 + }, + "resp-modifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", + "integrity": "sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08=", + "dev": true, + "requires": { + "debug": "^2.2.0", + "minimatch": "^3.0.2" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "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 + }, + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "dev": true + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "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" + } + }, + "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" + } + }, + "rsvp": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz", + "integrity": "sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA==", + "dev": true + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", + "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", + "dev": true + }, + "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" + } + }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=" + }, + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "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": "https://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==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "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" + } + }, + "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" + } + } + } + }, + "sass": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.17.0.tgz", + "integrity": "sha512-aFi9RQqrCYkHB2DaLKBBbdUhos1N5o3l1ke9N5JqWzgSPmYwZsdmA+ViPVatUy/RPA21uejgYVUXM7GCh8lcdw==", + "dev": true, + "requires": { + "chokidar": "^2.0.0" + } + }, + "sass-loader": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", + "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", + "dev": true, + "requires": { + "clone-deep": "^2.0.1", + "loader-utils": "^1.0.1", + "lodash.tail": "^4.1.1", + "neo-async": "^2.5.0", + "pify": "^3.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "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": "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" + } + }, + "scoped-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz", + "integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=", + "dev": true + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selfsigned": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.4.tgz", + "integrity": "sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==", + "dev": true, + "requires": { + "node-forge": "0.7.5" + } + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, + "semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "semver-intersect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz", + "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==", + "dev": true, + "requires": { + "semver": "^5.0.0" + } + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.6.1.tgz", + "integrity": "sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw==", + "dev": true + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=", + "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.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "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 + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://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" + } + }, + "shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "dev": true, + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "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 + } + } + }, + "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 + }, + "shelljs": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "simple-git": { + "version": "1.107.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.107.0.tgz", + "integrity": "sha512-t4OK1JRlp4ayKRfcW6owrWcRVLyHRUlhGd0uN6ZZTqfDq8a5XpcUdOKiGRNobHEuMtNqzp0vcJNvhYWwh5PsQA==", + "dev": true, + "requires": { + "debug": "^4.0.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" + } + }, + "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 + } + } + }, + "simple-progress-webpack-plugin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/simple-progress-webpack-plugin/-/simple-progress-webpack-plugin-1.1.2.tgz", + "integrity": "sha512-bNQfb3qSqbtsfxg6d0dGechUUJH2lZqKG5+bj2aoJmEA0rSzcm+2JVfC2YgkDABfuGItZ/O5ttt6BssWZW4SNg==", + "dev": true, + "requires": { + "chalk": "2.3.x", + "figures": "2.0.x", + "log-update": "2.3.x" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + } + } + }, + "sisteransi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.0.tgz", + "integrity": "sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ==", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "smart-buffer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz", + "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==", + "dev": true + }, + "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": { + "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" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "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" + } + } + } + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "dev": true, + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "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" + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz", + "integrity": "sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.3.1", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "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" + } + } + } + }, + "socket.io-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", + "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "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" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "sockjs-client": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz", + "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==", + "dev": true, + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + }, + "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" + } + }, + "faye-websocket": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "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 + } + } + }, + "socks": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.2.tgz", + "integrity": "sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "4.0.2" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "dev": true, + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + } + }, + "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.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "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.5.11", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.11.tgz", + "integrity": "sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "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 + } + } + }, + "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 + }, + "sourcemap-codec": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz", + "integrity": "sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg==", + "dev": true + }, + "spawn-sync": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "dev": true, + "requires": { + "concat-stream": "^1.4.7", + "os-shim": "^0.1.2" + } + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "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.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "dev": true + }, + "spdy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.0.tgz", + "integrity": "sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "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" + } + }, + "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 + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "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" + } + }, + "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 + }, + "readable-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz", + "integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "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.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "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": "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" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "stackframe": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.0.4.tgz", + "integrity": "sha512-to7oADIniaYwS3MhtCa/sQhrxidCCQiF/qp4/m5iN3ipf0Y7Xlri0f6eG29r08aL7JYl8n32AF3Q5GYBZ7K8vw==", + "dev": true + }, + "staged-git-files": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.2.tgz", + "integrity": "sha512-0Eyrk6uXW6tg9PYkhi/V/J4zHp33aNyi2hOCmhFLqLTIhbgqWn5jlSzI+IU0VqrZq6+DbHcabQl/WP6P3BG0QA==", + "dev": true + }, + "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" + } + } + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + }, + "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.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "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 + }, + "stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM=", + "dev": true, + "requires": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + } + }, + "streamfilter": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/streamfilter/-/streamfilter-1.0.7.tgz", + "integrity": "sha512-Gk6KZM+yNA1JpW0KzlZIhjo3EaBJDkYfXtYSbOwNIQ7Zd6006E6+sCFlW1NDvFG/vnXhKmw6TJJgiEQg/8lXfQ==", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "string-argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", + "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "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" + } + } + } + }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.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" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.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=", + "requires": { + "ansi-regex": "^2.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-bom-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", + "integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=", + "dev": true, + "requires": { + "first-chunk-stream": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + } + } + }, + "strip-comments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", + "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", + "dev": true, + "requires": { + "babel-extract-comments": "^1.0.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, + "style-loader": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", + "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" + } + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "svgo": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.2.0.tgz", + "integrity": "sha512-xBfxJxfk4UeVN8asec9jNxHiv3UAMv/ujwBWGYvQhhMb2u3YTGKkiybPcLFDLq7GLLWE9wa73e0/m8L5nTzQbw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.28", + "css-url-regex": "^1.1.0", + "csso": "^3.5.1", + "js-yaml": "^3.12.0", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "css-select": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.0.2.tgz", + "integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^2.1.2", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "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" + } + } + } + }, + "swagger-ui": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/swagger-ui/-/swagger-ui-2.2.10.tgz", + "integrity": "sha1-sl56IWZOXZC/OR2zDbCN5B6FLXs=" + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, + "synchronous-promise": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.6.tgz", + "integrity": "sha512-TyOuWLwkmtPL49LHCX1caIwHjRzcVd62+GF6h8W/jHOeZUFHpnd2XJDVuUlaTaLPH1nuu2M69mfHr5XbQJnf/g==", + "dev": true + }, + "tabtab": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tabtab/-/tabtab-2.2.2.tgz", + "integrity": "sha1-egR/FDsBC0y9MfhX6ClhUSy/ThQ=", + "dev": true, + "requires": { + "debug": "^2.2.0", + "inquirer": "^1.0.2", + "lodash.difference": "^4.5.0", + "lodash.uniq": "^4.5.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "npmlog": "^2.0.3", + "object-assign": "^4.1.0" + }, + "dependencies": { + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "^1.0.1" + } + }, + "external-editor": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz", + "integrity": "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=", + "dev": true, + "requires": { + "extend": "^3.0.0", + "spawn-sync": "^1.0.15", + "tmp": "^0.0.29" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "inquirer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz", + "integrity": "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=", + "dev": true, + "requires": { + "ansi-escapes": "^1.1.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "external-editor": "^1.1.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "mute-stream": "0.0.6", + "pinkie-promise": "^2.0.0", + "run-async": "^2.2.0", + "rx": "^4.1.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "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" + } + }, + "mute-stream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz", + "integrity": "sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=", + "dev": true + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "^1.0.0", + "onetime": "^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" + } + }, + "tmp": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", + "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, + "tapable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.1.tgz", + "integrity": "sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA==", + "dev": true + }, + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "dev": 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" + } + }, + "terser": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", + "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.10" + }, + "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 + } + } + }, + "terser-webpack-plugin": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz", + "integrity": "sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg==", + "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.16.1", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" + }, + "dependencies": { + "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": "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" + } + }, + "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" + } + }, + "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": "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.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "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": "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" + } + }, + "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 + } + } + }, + "test-exclude": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.1.0.tgz", + "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^1.0.1" + }, + "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" + } + }, + "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" + } + }, + "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.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": "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.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "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" + } + }, + "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" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "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" + } + } + } + }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true + }, + "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 + }, + "textextensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.4.0.tgz", + "integrity": "sha512-qftQXnX1DzpSV8EddtHIT0eDDEiBF8ywhFYR2lI9xrGtxqKN+CvLXhACeCIGbCpQfxxERbrkZEFb8cZcDKbVZA==", + "dev": true + }, + "tfunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tfunk/-/tfunk-3.1.0.tgz", + "integrity": "sha1-OORBT8ZJd9h6/apy+sttKfgve1s=", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "object-path": "^0.9.0" + } + }, + "thread-loader": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thread-loader/-/thread-loader-2.1.2.tgz", + "integrity": "sha512-7xpuc9Ifg6WU+QYw/8uUqNdRwMD+N5gjwHKMqETrs96Qn+7BHwECpt2Brzr4HFlf4IAkZsayNhmGdbkBsTJ//w==", + "dev": true, + "requires": { + "loader-runner": "^2.3.1", + "loader-utils": "^1.1.0", + "neo-async": "^2.6.0" + } + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "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" + } + }, + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==", + "dev": true + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "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" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "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" + } + }, + "to-string-loader": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/to-string-loader/-/to-string-loader-1.1.5.tgz", + "integrity": "sha1-e3qheJG3u0lHp6Eb+wO1/enG5pU=", + "dev": true, + "requires": { + "loader-utils": "^0.2.16" + }, + "dependencies": { + "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 + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "topo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", + "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", + "dev": true, + "requires": { + "hoek": "4.x.x" + } + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "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" + } + }, + "tree-kill": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", + "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", + "dev": true + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true + }, + "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 + }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", + "dev": true + }, + "ts-jest": { + "version": "23.1.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-23.1.4.tgz", + "integrity": "sha512-9rCSxbWfoZxxeXnSoEIzRNr9hDIQ8iEJAWmSRsWhDHDT8OeuGfURhJQUE8jtJlkyEygs6rngH8RYtHz9cfjmEA==", + "dev": true, + "requires": { + "closest-file-data": "^0.1.4", + "fs-extra": "6.0.1", + "json5": "^0.5.0", + "lodash": "^4.17.10" + }, + "dependencies": { + "fs-extra": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + } + } + }, + "ts-loader": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.3.3.tgz", + "integrity": "sha512-KwF1SplmOJepnoZ4eRIloH/zXL195F51skt7reEsS6jvDqzgc/YSbz9b8E07GxIUwLXdcD4ssrJu6v8CwaTafA==", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "enhanced-resolve": "^4.0.0", + "loader-utils": "^1.0.2", + "micromatch": "^3.1.4", + "semver": "^5.0.1" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, + "tslint": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.12.1.tgz", + "integrity": "sha512-sfodBHOucFg6egff8d1BvuofoOQ/nOeYNfbp7LDlKBcLNrL3lmS5zoiDGyOMdT7YsEXAwWpTdAHwOGOc8eRZAw==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.27.2" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + } + } + }, + "tslint-config-prettier": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz", + "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==", + "dev": true + }, + "tslint-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tslint-loader/-/tslint-loader-3.6.0.tgz", + "integrity": "sha512-Me9Qf/87BOfCY8uJJw+J7VMF4U8WiMXKLhKKKugMydF0xMhMOt9wo2mjYTNhwbF9H7SHh8PAIwRG8roisTNekQ==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.1", + "rimraf": "^2.4.4", + "semver": "^5.3.0" + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "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-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz", + "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.17", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz", + "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g==", + "dev": true + }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "requires": { + "commander": "~2.19.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 + } + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "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" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "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" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "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 + } + } + }, + "untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", + "dev": true + }, + "upath": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "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-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "dev": true, + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "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.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "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" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "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" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", + "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==", + "dev": true + }, + "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" + } + }, + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "dev": true, + "requires": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + } + }, + "vinyl-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-2.0.0.tgz", + "integrity": "sha1-p+v1/779obfRjRQPyweyI++2dRo=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.3.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0", + "strip-bom-stream": "^2.0.0", + "vinyl": "^1.1.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.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" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "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" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.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.29.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.29.3.tgz", + "integrity": "sha512-xPJvFeB+8tUflXFq+OgdpiSnsCD5EANyv56co5q8q8+YtEasn5Sj3kzY44mta+csCIEB0vneSxnuaHkOL2h94A==", + "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": "^6.0.5", + "acorn-dynamic-import": "^4.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": "^1.0.0", + "tapable": "^1.1.0", + "terser-webpack-plugin": "^1.1.0", + "watchpack": "^1.5.0", + "webpack-sources": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "dev": true + } + } + }, + "webpack-cli": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.2.3.tgz", + "integrity": "sha512-Ik3SjV6uJtWIAN5jp5ZuBMWEAaP5E4V78XJ2nI+paFPh8v4HPSwo/myN0r29Xc/6ZKnd2IdrAlpSgNOu2CDQ6Q==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.0", + "findup-sync": "^2.0.0", + "global-modules": "^1.0.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.4" + }, + "dependencies": { + "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" + } + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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" + } + }, + "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" + } + }, + "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-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" + } + }, + "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 + }, + "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" + } + }, + "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" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, + "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": "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.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + } + } + }, + "webpack-dev-middleware": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz", + "integrity": "sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA==", + "dev": true, + "requires": { + "memory-fs": "~0.4.1", + "mime": "^2.3.1", + "range-parser": "^1.0.3", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "mime": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", + "dev": true + } + } + }, + "webpack-dev-server": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz", + "integrity": "sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.0.0", + "compression": "^1.5.2", + "connect-history-api-fallback": "^1.3.0", + "debug": "^3.1.0", + "del": "^3.0.0", + "express": "^4.16.2", + "html-entities": "^1.2.0", + "http-proxy-middleware": "~0.18.0", + "import-local": "^2.0.0", + "internal-ip": "^3.0.1", + "ip": "^1.1.5", + "killable": "^1.0.0", + "loglevel": "^1.4.1", + "opn": "^5.1.0", + "portfinder": "^1.0.9", + "schema-utils": "^1.0.0", + "selfsigned": "^1.9.1", + "semver": "^5.6.0", + "serve-index": "^1.7.2", + "sockjs": "0.3.19", + "sockjs-client": "1.3.0", + "spdy": "^4.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^5.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "3.4.0", + "webpack-log": "^2.0.0", + "yargs": "12.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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" + } + }, + "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" + } + }, + "decamelize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", + "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", + "dev": true, + "requires": { + "xregexp": "4.0.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-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" + } + }, + "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 + }, + "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" + } + }, + "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" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, + "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 + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.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": "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.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "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" + } + }, + "yargs": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz", + "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^2.0.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": "^10.1.0" + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-merge": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.1.tgz", + "integrity": "sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw==", + "dev": true, + "requires": { + "lodash": "^4.17.5" + } + }, + "webpack-notifier": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/webpack-notifier/-/webpack-notifier-1.7.0.tgz", + "integrity": "sha512-L3UKrl500xk0VDYKkwQxy5/BPhBWsZ2xHsAx2Qe3dVKYUEk9+y690RcNTMIUcVOK2fRgK7KK3PA4ccOq1h+fTg==", + "dev": true, + "requires": { + "node-notifier": "^5.1.2", + "object-assign": "^4.1.0", + "strip-ansi": "^3.0.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 + } + } + }, + "webpack-visualizer-plugin": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/webpack-visualizer-plugin/-/webpack-visualizer-plugin-0.1.11.tgz", + "integrity": "sha1-uHcK2GtPZSYSxosbeCJT+vn4o04=", + "dev": true, + "requires": { + "d3": "^3.5.6", + "mkdirp": "^0.5.1", + "react": "^0.14.0", + "react-dom": "^0.14.0" + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "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-fetch": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz", + "integrity": "sha1-DjaExsuZlbQ+/J3wPkw2XZX9nMA=", + "dev": true + }, + "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 + }, + "win-release": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", + "integrity": "sha1-X6VeAr58qTTt/BJmVjLoSbcuUgk=", + "dev": true, + "requires": { + "semver": "^5.0.1" + } + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", + "dev": true + }, + "winston": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", + "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", + "dev": true, + "requires": { + "async": "^2.6.1", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^2.1.1", + "one-time": "0.0.4", + "readable-stream": "^3.1.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.3.0" + }, + "dependencies": { + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "readable-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz", + "integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "winston-transport": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", + "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", + "dev": true, + "requires": { + "readable-stream": "^2.3.6", + "triple-beam": "^1.2.0" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "workbox-background-sync": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-3.6.3.tgz", + "integrity": "sha512-ypLo0B6dces4gSpaslmDg5wuoUWrHHVJfFWwl1udvSylLdXvnrfhFfriCS42SNEe5lsZtcNZF27W/SMzBlva7Q==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-broadcast-cache-update": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-broadcast-cache-update/-/workbox-broadcast-cache-update-3.6.3.tgz", + "integrity": "sha512-pJl4lbClQcvp0SyTiEw0zLSsVYE1RDlCPtpKnpMjxFtu8lCFTAEuVyzxp9w7GF4/b3P4h5nyQ+q7V9mIR7YzGg==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-build": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-3.6.3.tgz", + "integrity": "sha512-w0clZ/pVjL8VXy6GfthefxpEXs0T8uiRuopZSFVQ8ovfbH6c6kUpEh6DcYwm/Y6dyWPiCucdyAZotgjz+nRz8g==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "common-tags": "^1.4.0", + "fs-extra": "^4.0.2", + "glob": "^7.1.2", + "joi": "^11.1.1", + "lodash.template": "^4.4.0", + "pretty-bytes": "^4.0.2", + "stringify-object": "^3.2.2", + "strip-comments": "^1.0.2", + "workbox-background-sync": "^3.6.3", + "workbox-broadcast-cache-update": "^3.6.3", + "workbox-cache-expiration": "^3.6.3", + "workbox-cacheable-response": "^3.6.3", + "workbox-core": "^3.6.3", + "workbox-google-analytics": "^3.6.3", + "workbox-navigation-preload": "^3.6.3", + "workbox-precaching": "^3.6.3", + "workbox-range-requests": "^3.6.3", + "workbox-routing": "^3.6.3", + "workbox-strategies": "^3.6.3", + "workbox-streams": "^3.6.3", + "workbox-sw": "^3.6.3" + }, + "dependencies": { + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "pretty-bytes": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz", + "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=", + "dev": true + } + } + }, + "workbox-cache-expiration": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-cache-expiration/-/workbox-cache-expiration-3.6.3.tgz", + "integrity": "sha512-+ECNph/6doYx89oopO/UolYdDmQtGUgo8KCgluwBF/RieyA1ZOFKfrSiNjztxOrGJoyBB7raTIOlEEwZ1LaHoA==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-cacheable-response": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-3.6.3.tgz", + "integrity": "sha512-QpmbGA9SLcA7fklBLm06C4zFg577Dt8u3QgLM0eMnnbaVv3rhm4vbmDpBkyTqvgK/Ly8MBDQzlXDtUCswQwqqg==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-core": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-3.6.3.tgz", + "integrity": "sha512-cx9cx0nscPkIWs8Pt98HGrS9/aORuUcSkWjG25GqNWdvD/pSe7/5Oh3BKs0fC+rUshCiyLbxW54q0hA+GqZeSQ==", + "dev": true + }, + "workbox-google-analytics": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-3.6.3.tgz", + "integrity": "sha512-RQBUo/6SXtIaQTRFj4RQZ9e1gAl7D8oS5S+Hi173Kk70/BgJjzPwXpC5A249Jv5YfkCOLMQCeF9A27BiD0b0ig==", + "dev": true, + "requires": { + "workbox-background-sync": "^3.6.3", + "workbox-core": "^3.6.3", + "workbox-routing": "^3.6.3", + "workbox-strategies": "^3.6.3" + } + }, + "workbox-navigation-preload": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-3.6.3.tgz", + "integrity": "sha512-dd26xTX16DUu0i+MhqZK/jQXgfIitu0yATM4jhRXEmpMqQ4MxEeNvl2CgjDMOHBnCVMax+CFZQWwxMx/X/PqCw==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-precaching": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-3.6.3.tgz", + "integrity": "sha512-aBqT66BuMFviPTW6IpccZZHzpA8xzvZU2OM1AdhmSlYDXOJyb1+Z6blVD7z2Q8VNtV1UVwQIdImIX+hH3C3PIw==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-range-requests": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-3.6.3.tgz", + "integrity": "sha512-R+yLWQy7D9aRF9yJ3QzwYnGFnGDhMUij4jVBUVtkl67oaVoP1ymZ81AfCmfZro2kpPRI+vmNMfxxW531cqdx8A==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-routing": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-3.6.3.tgz", + "integrity": "sha512-bX20i95OKXXQovXhFOViOK63HYmXvsIwZXKWbSpVeKToxMrp0G/6LZXnhg82ijj/S5yhKNRf9LeGDzaqxzAwMQ==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-strategies": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-3.6.3.tgz", + "integrity": "sha512-Pg5eulqeKet2y8j73Yw6xTgLdElktcWExGkzDVCGqfV9JCvnGuEpz5eVsCIK70+k4oJcBCin9qEg3g3CwEIH3g==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-streams": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-3.6.3.tgz", + "integrity": "sha512-rqDuS4duj+3aZUYI1LsrD2t9hHOjwPqnUIfrXSOxSVjVn83W2MisDF2Bj+dFUZv4GalL9xqErcFW++9gH+Z27w==", + "dev": true, + "requires": { + "workbox-core": "^3.6.3" + } + }, + "workbox-sw": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-3.6.3.tgz", + "integrity": "sha512-IQOUi+RLhvYCiv80RP23KBW/NTtIvzvjex28B8NW1jOm+iV4VIu3VXKXTA6er5/wjjuhmtB28qEAUqADLAyOSg==", + "dev": true + }, + "workbox-webpack-plugin": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-3.6.3.tgz", + "integrity": "sha512-RwmKjc7HFHUFHoOlKoZUq9349u0QN3F8W5tZZU0vc1qsBZDINWXRiIBCAKvo/Njgay5sWz7z4I2adnyTo97qIQ==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "json-stable-stringify": "^1.0.1", + "workbox-build": "^3.6.3" + } + }, + "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": { + "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" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", + "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "write-file-webpack-plugin": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/write-file-webpack-plugin/-/write-file-webpack-plugin-4.5.0.tgz", + "integrity": "sha512-k46VeERtaezbmjpDcMWATjKUWBrVe/ZEEm0cyvUm8FFP8A/r+dw5x3psRvkUOhqh9bqBLUlGYYbtr6luI+HeAg==", + "dev": true, + "requires": { + "chalk": "^2.4.0", + "debug": "^3.1.0", + "filesize": "^3.6.1", + "lodash": "^4.17.5", + "mkdirp": "^0.5.1", + "moment": "^2.22.1", + "write-file-atomic": "^2.3.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.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" + } + }, + "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 + }, + "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" + } + } + } + }, + "ws": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", + "dev": true + }, + "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 + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xregexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", + "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==", + "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": "9.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz", + "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^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": "^7.0.0" + }, + "dependencies": { + "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": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yeoman-environment": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.3.0.tgz", + "integrity": "sha512-PHSAkVOqYdcR+C+Uht1SGC4eVD/9OhygYFkYaI66xF8vKIeS1RNYay+umj2ZrQeJ50tF5Q/RSO6qGDz9y3Ifug==", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^3.1.0", + "diff": "^3.3.1", + "escape-string-regexp": "^1.0.2", + "globby": "^8.0.1", + "grouped-queue": "^0.3.3", + "inquirer": "^5.2.0", + "is-scoped": "^1.0.0", + "lodash": "^4.17.10", + "log-symbols": "^2.1.0", + "mem-fs": "^1.1.0", + "strip-ansi": "^4.0.0", + "text-table": "^0.2.0", + "untildify": "^3.0.2" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.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" + } + }, + "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" + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "inquirer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", + "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.1.0", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^5.5.2", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "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 + }, + "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" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + } + }, + "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" + } + }, + "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-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + } + } + }, + "yeoman-generator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-3.0.0.tgz", + "integrity": "sha512-aHsNXzkdgAoakZTZsDX7T56wYWYd1O5E/GBIFAVMJLH7TKRr+1MiEJszZQbbCSA+J+lpT743/8L88j35yNdTLQ==", + "dev": true, + "requires": { + "async": "^2.6.0", + "chalk": "^2.3.0", + "cli-table": "^0.3.1", + "cross-spawn": "^6.0.5", + "dargs": "^6.0.0", + "dateformat": "^3.0.3", + "debug": "^3.1.0", + "detect-conflict": "^1.0.0", + "error": "^7.0.2", + "find-up": "^3.0.0", + "github-username": "^4.0.0", + "istextorbinary": "^2.2.1", + "lodash": "^4.17.10", + "make-dir": "^1.1.0", + "mem-fs-editor": "^5.0.0", + "minimist": "^1.2.0", + "pretty-bytes": "^5.1.0", + "read-chunk": "^2.1.0", + "read-pkg-up": "^4.0.0", + "rimraf": "^2.6.2", + "run-async": "^2.0.0", + "shelljs": "^0.8.0", + "text-table": "^0.2.0", + "through2": "^2.0.0", + "yeoman-environment": "^2.0.5" + }, + "dependencies": { + "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" + } + }, + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "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": "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.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "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" + } + }, + "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" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "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" + } + }, + "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" + } + } + } + }, + "yup": { + "version": "0.26.10", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.26.10.tgz", + "integrity": "sha512-keuNEbNSnsOTOuGCt3UJW69jDE3O4P+UHAakO7vSeFMnjaitcmlbij/a3oNb9g1Y1KvSKH/7O1R2PQ4m4TRylw==", + "dev": true, + "requires": { + "@babel/runtime": "7.0.0", + "fn-name": "~2.0.1", + "lodash": "^4.17.10", + "property-expr": "^1.5.0", + "synchronous-promise": "^2.0.5", + "toposort": "^2.0.2" + }, + "dependencies": { + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=", + "dev": true + } + } + }, + "zone.js": { + "version": "0.8.29", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.29.tgz", + "integrity": "sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ==" + } + } +} diff --git a/jhipster-5/bookstore-monolith/package.json b/jhipster-5/bookstore-monolith/package.json new file mode 100644 index 0000000000..46b920edb3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/package.json @@ -0,0 +1,128 @@ +{ + "name": "bookstore", + "version": "0.0.0", + "description": "Description for Bookstore", + "private": true, + "license": "UNLICENSED", + "cacheDirectories": [ + "node_modules" + ], + "dependencies": { + "@angular/common": "7.2.4", + "@angular/compiler": "7.2.4", + "@angular/core": "7.2.4", + "@angular/forms": "7.2.4", + "@angular/platform-browser": "7.2.4", + "@angular/platform-browser-dynamic": "7.2.4", + "@angular/router": "7.2.4", + "@fortawesome/angular-fontawesome": "0.3.0", + "@fortawesome/fontawesome-svg-core": "1.2.14", + "@fortawesome/free-solid-svg-icons": "5.7.1", + "@ng-bootstrap/ng-bootstrap": "4.0.2", + "@ngx-translate/core": "11.0.1", + "@ngx-translate/http-loader": "4.0.0", + "bootstrap": "4.2.1", + "core-js": "2.6.4", + "moment": "2.24.0", + "ng-jhipster": "0.9.1", + "ngx-cookie": "2.0.1", + "ngx-infinite-scroll": "7.0.1", + "ngx-webstorage": "2.0.1", + "rxjs": "6.4.0", + "swagger-ui": "2.2.10", + "tslib": "1.9.3", + "zone.js": "0.8.29" + }, + "devDependencies": { + "@angular/cli": "7.3.1", + "@angular/compiler-cli": "7.2.4", + "@ngtools/webpack": "7.3.1", + "@types/jest": "24.0.0", + "@types/node": "10.12.24", + "angular-router-loader": "0.8.5", + "angular2-template-loader": "0.6.2", + "autoprefixer": "9.4.7", + "browser-sync": "2.26.3", + "browser-sync-webpack-plugin": "2.2.2", + "cache-loader": "2.0.1", + "codelyzer": "4.5.0", + "copy-webpack-plugin": "4.6.0", + "css-loader": "2.1.0", + "file-loader": "3.0.1", + "fork-ts-checker-webpack-plugin": "0.5.2", + "friendly-errors-webpack-plugin": "1.7.0", + "generator-jhipster": "5.8.2", + "html-loader": "0.5.5", + "html-webpack-plugin": "3.2.0", + "husky": "1.3.1", + "jest": "24.1.0", + "jest-junit": "6.2.1", + "jest-preset-angular": "6.0.2", + "jest-sonar-reporter": "2.0.0", + "lint-staged": "8.1.3", + "mini-css-extract-plugin": "0.5.0", + "moment-locales-webpack-plugin": "1.0.7", + "optimize-css-assets-webpack-plugin": "5.0.1", + "prettier": "1.16.4", + "reflect-metadata": "0.1.13", + "rimraf": "2.6.3", + "simple-progress-webpack-plugin": "1.1.2", + "style-loader": "0.23.1", + "terser-webpack-plugin": "1.2.2", + "thread-loader": "2.1.2", + "to-string-loader": "1.1.5", + "ts-loader": "5.3.3", + "tslint": "5.12.1", + "tslint-config-prettier": "1.18.0", + "tslint-loader": "3.6.0", + "typescript": "3.2.4", + "sass": "1.17.0", + "sass-loader": "7.1.0", + "postcss-loader": "3.0.0", + "xml2js": "0.4.19", + "webpack": "4.29.3", + "webpack-cli": "3.2.3", + "webpack-dev-server": "3.1.14", + "webpack-merge": "4.2.1", + "webpack-notifier": "1.7.0", + "webpack-visualizer-plugin": "0.1.11", + "workbox-webpack-plugin": "3.6.3", + "write-file-webpack-plugin": "4.5.0" + }, + "engines": { + "node": ">=8.9.0" + }, + "lint-staged": { + "{,src/**/}*.{md,json,ts,css,scss}": [ + "prettier --write", + "git add" + ] + }, + "scripts": { + "prettier:format": "prettier --write \"{,src/**/}*.{md,json,ts,css,scss}\"", + "lint": "tslint --project tsconfig.json -e 'node_modules/**'", + "lint:fix": "npm run lint -- --fix", + "ngc": "ngc -p tsconfig-aot.json", + "cleanup": "rimraf target/{aot,www}", + "clean-www": "rimraf target//www/app/{src,target/}", + "start": "npm run webpack:dev", + "start-tls": "npm run webpack:dev -- --env.tls", + "serve": "npm run start", + "build": "npm run webpack:prod", + "test": "npm run lint && jest --coverage --logHeapUsage -w=2 --config src/test/javascript/jest.conf.js", + "test:watch": "npm run test -- --watch", + "webpack:dev": "npm run webpack-dev-server -- --config webpack/webpack.dev.js --inline --hot --port=9060 --watch-content-base --env.stats=minimal", + "webpack:dev-verbose": "npm run webpack-dev-server -- --config webpack/webpack.dev.js --inline --hot --port=9060 --watch-content-base --profile --progress --env.stats=normal", + "webpack:build:main": "npm run webpack -- --config webpack/webpack.dev.js --env.stats=minimal", + "webpack:build": "npm run cleanup && npm run webpack:build:main", + "webpack:prod:main": "npm run webpack -- --config webpack/webpack.prod.js --profile", + "webpack:prod": "npm run cleanup && npm run webpack:prod:main && npm run clean-www", + "webpack:test": "npm run test", + "webpack-dev-server": "node --max_old_space_size=4096 node_modules/webpack-dev-server/bin/webpack-dev-server.js", + "webpack": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js" + }, + "jestSonar": { + "reportPath": "target/test-results/jest", + "reportFile": "TESTS-results-sonar.xml" + } +} diff --git a/jhipster-5/bookstore-monolith/pom.xml b/jhipster-5/bookstore-monolith/pom.xml new file mode 100644 index 0000000000..e46804a04c --- /dev/null +++ b/jhipster-5/bookstore-monolith/pom.xml @@ -0,0 +1,1085 @@ + + + 4.0.0 + + com.baeldung.jhipster5 + bookstore + 0.0.1-SNAPSHOT + war + Bookstore + + + + + + + + + + + + + + 3.0.0 + 1.8 + 2.12.6 + v10.15.0 + 6.4.1 + UTF-8 + UTF-8 + ${project.build.directory}/test-results + yyyyMMddHHmmss + ${java.version} + ${java.version} + -Djava.security.egd=file:/dev/./urandom -Xmx256m + jdt_apt + false + + + + + + + 2.1.1 + + 2.0.8.RELEASE + + 5.2.17.Final + + 3.22.0-GA + + 3.5.5 + 3.6 + 2.0.1.Final + 1.2.0.Final + + + 3.1.0 + 3.8.0 + 2.10 + 3.0.0-M2 + 2.2.1 + 3.1.0 + 2.22.1 + 3.2.2 + 0.9.11 + 1.6 + 0.8.2 + 1.0.0 + 3.4.2 + 3.5.0.1254 + 2.2.5 + + + http://localhost:9001 + src/main/webapp/content/**/*.*, src/main/webapp/i18n/*.js, target/www/**/*.* + S3437,S4502,S4684,UndocumentedApi,BoldAndItalicTagsCheck + + src/main/webapp/app/**/*.* + Web:BoldAndItalicTagsCheck + + src/main/java/**/* + squid:S3437 + + src/main/java/**/* + squid:UndocumentedApi + + src/main/java/**/* + squid:S4502 + + src/main/java/**/* + squid:S4684 + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + jacoco + ${project.testresult.directory}/lcov.info + ${project.basedir}/src/main/ + ${project.testresult.directory} + ${project.basedir}/src/test/ + + + + + + + + io.github.jhipster + jhipster-dependencies + ${jhipster-dependencies.version} + pom + import + + + + + + + + io.github.jhipster + jhipster-framework + + + + com.fasterxml.jackson.datatype + jackson-datatype-hibernate5 + + + com.fasterxml.jackson.datatype + jackson-datatype-hppc + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + com.fasterxml.jackson.module + jackson-module-afterburner + + + com.h2database + h2 + test + + + com.jayway.jsonpath + json-path + test + + + + io.springfox + springfox-swagger2 + + + io.springfox + springfox-bean-validators + + + com.mattbertolini + liquibase-slf4j + + + com.zaxxer + HikariCP + + + commons-io + commons-io + + + org.apache.commons + commons-lang3 + + + mysql + mysql-connector-java + + + org.assertj + assertj-core + test + + + org.hibernate + hibernate-jpamodelgen + provided + + + org.hibernate + hibernate-envers + + + org.hibernate.validator + hibernate-validator + + + org.liquibase + liquibase-core + + + net.logstash.logback + logstash-logback-encoder + + + org.mapstruct + mapstruct-jdk8 + + + org.mapstruct + mapstruct-processor + provided + + + org.springframework.boot + spring-boot-configuration-processor + provided + + + org.springframework.boot + spring-boot-loader-tools + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-logging + + + org.springframework.boot + spring-boot-starter-mail + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-test + test + + + org.springframework.security + spring-security-test + test + + + org.zalando + problem-spring-web + + + io.jsonwebtoken + jjwt-api + + + io.jsonwebtoken + jjwt-impl + runtime + + + io.jsonwebtoken + jjwt-jackson + runtime + + + + org.springframework.boot + spring-boot-starter-cloud-connectors + + + + org.springframework.security + spring-security-data + + + io.micrometer + micrometer-registry-prometheus + + + io.dropwizard.metrics + metrics-core + + + + + + spring-boot:run + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + org.hibernate + hibernate-jpamodelgen + ${hibernate.version} + + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + + + org.apache.maven.plugins + maven-enforcer-plugin + + + org.apache.maven.plugins + maven-idea-plugin + + + org.apache.maven.plugins + maven-resources-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.jacoco + jacoco-maven-plugin + + + org.sonarsource.scanner.maven + sonar-maven-plugin + + + org.liquibase + liquibase-maven-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + ${start-class} + true + true + + + + + com.google.cloud.tools + jib-maven-plugin + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + com.github.eirslett + frontend-maven-plugin + ${frontend-maven-plugin.version} + + + pl.project13.maven + git-commit-id-plugin + ${git-commit-id-plugin.version} + + + + revision + + + + + false + true + + ^git.commit.id.abbrev$ + ^git.commit.id.describe$ + ^git.branch$ + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + pre-unit-tests + + prepare-agent + + + + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + + + + + post-unit-test + test + + report + + + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + ${project.testresult.directory}/coverage/jacoco + + + + + + com.google.cloud.tools + jib-maven-plugin + ${jib-maven-plugin.version} + + + openjdk:8-jre-alpine + + + bookstore:latest + + + + sh + + chmod +x /entrypoint.sh && sync && /entrypoint.sh + + + 8080 + + + ALWAYS + 0 + + true + + + + + org.liquibase + liquibase-maven-plugin + ${liquibase.version} + + ${project.basedir}/src/main/resources/config/liquibase/master.xml + ${project.basedir}/src/main/resources/config/liquibase/changelog/${maven.build.timestamp}_changelog.xml + + + + Bookstore + + hibernate:spring:com.baeldung.jhipster5.domain?dialect=&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + true + debug + + + + org.javassist + javassist + ${javassist.version} + + + org.liquibase.ext + liquibase-hibernate5 + ${liquibase-hibernate5.version} + + + org.springframework.boot + spring-boot-starter-data-jpa + ${spring-boot.version} + + + javax.validation + validation-api + ${validation-api.version} + + + + + maven-clean-plugin + ${maven-clean-plugin.version} + + + org.apache.maven.plugins + maven-eclipse-plugin + ${maven-eclipse-plugin.version} + + true + true + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${maven-enforcer-plugin.version} + + + enforce-versions + + enforce + + + + + + + You are running an older version of Maven. JHipster requires at least Maven ${maven.version} + [${maven.version},) + + + + You are running an incompatible version of Java. JHipster requires JDK ${java.version} + [1.8,1.9) + + + + + + org.apache.maven.plugins + maven-idea-plugin + ${maven-idea-plugin.version} + + node_modules + + + + org.apache.maven.plugins + maven-resources-plugin + ${maven-resources-plugin.version} + + + default-resources + validate + + copy-resources + + + ${project.build.directory}/classes + false + + # + + + + src/main/resources/ + true + + config/*.yml + + + + src/main/resources/ + false + + config/*.yml + + + + + + + jib-www-resources + verify + + copy-resources + + + ${project.build.directory}/classes/static/ + + + ${project.build.directory}/www + false + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + alphabetical + + + false + ${sonar.junit.reportsPath} + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + + net.alchim31.maven + scala-maven-plugin + ${scala-maven-plugin.version} + + + compile + compile + + add-source + compile + + + + test-compile + test-compile + + add-source + testCompile + + + + + incremental + true + ${scala.version} + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + ${sonar-maven-plugin.version} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + + + + no-liquibase + + ,no-liquibase + + + + swagger + + ,swagger + + + + tls + + ,tls + + + + webpack + + + ${basedir}/target/www/app/main.bundle.js + + + + + org.springframework.boot + spring-boot-starter-undertow + + + org.springframework.boot + spring-boot-devtools + true + + + com.h2database + h2 + + + + + + com.github.eirslett + frontend-maven-plugin + + + install node and npm + + install-node-and-npm + + + ${node.version} + ${npm.version} + + + + npm install + + npm + + + + webpack build dev + + npm + + generate-resources + + run webpack:build + false + + + + + + org.apache.maven.plugins + maven-war-plugin + + false + target/www/ + + + src/main/webapp + + WEB-INF/** + + + + + + + + + + dev${profile.no-liquibase} + + + + dev + + true + + + + org.springframework.boot + spring-boot-starter-undertow + + + org.springframework.boot + spring-boot-devtools + true + + + com.h2database + h2 + + + + + + org.apache.maven.plugins + maven-war-plugin + + false + target/www/ + + + src/main/webapp + + WEB-INF/** + + + + + + + + + + dev${profile.tls}${profile.no-liquibase} + + + + prod + + + org.springframework.boot + spring-boot-starter-undertow + + + + + + maven-clean-plugin + + + + target/www/ + + + + + + org.apache.maven.plugins + maven-war-plugin + + false + target/www/ + + + src/main/webapp + + WEB-INF/** + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + ${start-class} + true + + + + + build-info + + + + + + com.github.eirslett + frontend-maven-plugin + + + install node and npm + + install-node-and-npm + + + ${node.version} + ${npm.version} + + + + npm install + + npm + + + install + + + + webpack build test + + npm + + test + + run webpack:test + false + + + + webpack build prod + + npm + + generate-resources + + run webpack:prod + false + + + + + + pl.project13.maven + git-commit-id-plugin + + + + + + prod${profile.swagger}${profile.no-liquibase} + + + + + cc + + + org.springframework.boot + spring-boot-starter-undertow + + + org.springframework.boot + spring-boot-devtools + true + + + + + + org.apache.maven.plugins + maven-war-plugin + + false + src/main/webapp/ + + + + org.springframework.boot + spring-boot-maven-plugin + + ${start-class} + true + true + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + default-compile + none + + + default-testCompile + none + + + + + net.alchim31.maven + scala-maven-plugin + + + + + + dev,swagger + + + + + IDE + + + org.mapstruct + mapstruct-processor + + + org.hibernate + hibernate-jpamodelgen + + + + + + eclipse + + + m2e.version + + + + + + + + org.eclipse.m2e + lifecycle-mapping + ${lifecycle-mapping.version} + + + + + + org.jacoco + + jacoco-maven-plugin + + + ${jacoco-maven-plugin.version} + + + prepare-agent + + + + + + + + + com.github.eirslett + frontend-maven-plugin + ${frontend-maven-plugin.version} + + install-node-and-npm + npm + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/postcss.config.js b/jhipster-5/bookstore-monolith/postcss.config.js new file mode 100644 index 0000000000..a26de7e9f1 --- /dev/null +++ b/jhipster-5/bookstore-monolith/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + require('autoprefixer') + ] +} diff --git a/jhipster-5/bookstore-monolith/proxy.conf.json b/jhipster-5/bookstore-monolith/proxy.conf.json new file mode 100644 index 0000000000..8b41fdf7fa --- /dev/null +++ b/jhipster-5/bookstore-monolith/proxy.conf.json @@ -0,0 +1,7 @@ +{ + "*": { + "target": "http://localhost:8080", + "secure": false, + "loglevel": "debug" + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/docker/.dockerignore b/jhipster-5/bookstore-monolith/src/main/docker/.dockerignore new file mode 100644 index 0000000000..b03bdc71ee --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/.dockerignore @@ -0,0 +1,14 @@ +# https://docs.docker.com/engine/reference/builder/#dockerignore-file +classes/ +generated-sources/ +generated-test-sources/ +h2db/ +maven-archiver/ +maven-status/ +reports/ +surefire-reports/ +test-classes/ +test-results/ +www/ +!*.jar +!*.war diff --git a/jhipster-5/bookstore-monolith/src/main/docker/Dockerfile b/jhipster-5/bookstore-monolith/src/main/docker/Dockerfile new file mode 100644 index 0000000000..43fadcb6f8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/Dockerfile @@ -0,0 +1,20 @@ +FROM openjdk:8-jre-alpine + +ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \ + JHIPSTER_SLEEP=0 \ + JAVA_OPTS="" + +# Add a jhipster user to run our application so that it doesn't need to run as root +RUN adduser -D -s /bin/sh jhipster +WORKDIR /home/jhipster + +ADD entrypoint.sh entrypoint.sh +RUN chmod 755 entrypoint.sh && chown jhipster:jhipster entrypoint.sh +USER jhipster + +ENTRYPOINT ["./entrypoint.sh"] + +EXPOSE 8080 + +ADD *.war app.war + diff --git a/jhipster-5/bookstore-monolith/src/main/docker/app.yml b/jhipster-5/bookstore-monolith/src/main/docker/app.yml new file mode 100644 index 0000000000..f60f0f5038 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/app.yml @@ -0,0 +1,15 @@ +version: '2' +services: + bookstore-app: + image: bookstore + environment: + - _JAVA_OPTIONS=-Xmx512m -Xms256m + - SPRING_PROFILES_ACTIVE=prod,swagger + - SPRING_DATASOURCE_URL=jdbc:mysql://bookstore-mysql:3306/bookstore?useUnicode=true&characterEncoding=utf8&useSSL=false + - JHIPSTER_SLEEP=10 # gives time for the database to boot before the application + ports: + - 8080:8080 + bookstore-mysql: + extends: + file: mysql.yml + service: bookstore-mysql diff --git a/jhipster-5/bookstore-monolith/src/main/docker/entrypoint.sh b/jhipster-5/bookstore-monolith/src/main/docker/entrypoint.sh new file mode 100644 index 0000000000..ccffafb5a4 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "The application will start in ${JHIPSTER_SLEEP}s..." && sleep ${JHIPSTER_SLEEP} +exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar "${HOME}/app.war" "$@" diff --git a/jhipster-5/bookstore-monolith/src/main/docker/mysql.yml b/jhipster-5/bookstore-monolith/src/main/docker/mysql.yml new file mode 100644 index 0000000000..13faba0457 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/mysql.yml @@ -0,0 +1,13 @@ +version: '2' +services: + bookstore-mysql: + image: mysql:5.7.20 + # volumes: + # - ~/volumes/jhipster/Bookstore/mysql/:/var/lib/mysql/ + environment: + - MYSQL_USER=root + - MYSQL_ALLOW_EMPTY_PASSWORD=yes + - MYSQL_DATABASE=bookstore + ports: + - 3306:3306 + command: mysqld --lower_case_table_names=1 --skip-ssl --character_set_server=utf8mb4 --explicit_defaults_for_timestamp diff --git a/jhipster-5/bookstore-monolith/src/main/docker/sonar.yml b/jhipster-5/bookstore-monolith/src/main/docker/sonar.yml new file mode 100644 index 0000000000..756175b7d0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/docker/sonar.yml @@ -0,0 +1,7 @@ +version: '2' +services: + bookstore-sonar: + image: sonarqube:7.1 + ports: + - 9001:9000 + - 9092:9092 diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/ApplicationWebXml.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/ApplicationWebXml.java new file mode 100644 index 0000000000..ca65727e77 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/ApplicationWebXml.java @@ -0,0 +1,21 @@ +package com.baeldung.jhipster5; + +import com.baeldung.jhipster5.config.DefaultProfileUtil; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +/** + * This is a helper Java class that provides an alternative to creating a web.xml. + * This will be invoked only when the application is deployed to a Servlet container like Tomcat, JBoss etc. + */ +public class ApplicationWebXml extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + /** + * set a default to use when no profile is configured. + */ + DefaultProfileUtil.addDefaultProfile(application.application()); + return application.sources(BookstoreApp.class); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/BookstoreApp.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/BookstoreApp.java new file mode 100644 index 0000000000..e7ca925228 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/BookstoreApp.java @@ -0,0 +1,98 @@ +package com.baeldung.jhipster5; + +import com.baeldung.jhipster5.config.ApplicationProperties; +import com.baeldung.jhipster5.config.DefaultProfileUtil; + +import io.github.jhipster.config.JHipsterConstants; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.core.env.Environment; + +import javax.annotation.PostConstruct; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Collection; + +@SpringBootApplication +@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class}) +public class BookstoreApp { + + private static final Logger log = LoggerFactory.getLogger(BookstoreApp.class); + + private final Environment env; + + public BookstoreApp(Environment env) { + this.env = env; + } + + /** + * Initializes Bookstore. + *

+ * Spring profiles can be configured with a program argument --spring.profiles.active=your-active-profile + *

+ * You can find more information on how profiles work with JHipster on https://www.jhipster.tech/profiles/. + */ + @PostConstruct + public void initApplication() { + Collection activeProfiles = Arrays.asList(env.getActiveProfiles()); + if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) { + log.error("You have misconfigured your application! It should not run " + + "with both the 'dev' and 'prod' profiles at the same time."); + } + if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)) { + log.error("You have misconfigured your application! It should not " + + "run with both the 'dev' and 'cloud' profiles at the same time."); + } + } + + /** + * Main method, used to run the application. + * + * @param args the command line arguments + */ + public static void main(String[] args) { + SpringApplication app = new SpringApplication(BookstoreApp.class); + DefaultProfileUtil.addDefaultProfile(app); + Environment env = app.run(args).getEnvironment(); + logApplicationStartup(env); + } + + private static void logApplicationStartup(Environment env) { + String protocol = "http"; + if (env.getProperty("server.ssl.key-store") != null) { + protocol = "https"; + } + String serverPort = env.getProperty("server.port"); + String contextPath = env.getProperty("server.servlet.context-path"); + if (StringUtils.isBlank(contextPath)) { + contextPath = "/"; + } + String hostAddress = "localhost"; + try { + hostAddress = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + log.warn("The host name could not be determined, using `localhost` as fallback"); + } + log.info("\n----------------------------------------------------------\n\t" + + "Application '{}' is running! Access URLs:\n\t" + + "Local: \t\t{}://localhost:{}{}\n\t" + + "External: \t{}://{}:{}{}\n\t" + + "Profile(s): \t{}\n----------------------------------------------------------", + env.getProperty("spring.application.name"), + protocol, + serverPort, + contextPath, + protocol, + hostAddress, + serverPort, + contextPath, + env.getActiveProfiles()); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/aop/logging/LoggingAspect.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/aop/logging/LoggingAspect.java new file mode 100644 index 0000000000..0379637061 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/aop/logging/LoggingAspect.java @@ -0,0 +1,98 @@ +package com.baeldung.jhipster5.aop.logging; + +import io.github.jhipster.config.JHipsterConstants; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +import java.util.Arrays; + +/** + * Aspect for logging execution of service and repository Spring components. + * + * By default, it only runs with the "dev" profile. + */ +@Aspect +public class LoggingAspect { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private final Environment env; + + public LoggingAspect(Environment env) { + this.env = env; + } + + /** + * Pointcut that matches all repositories, services and Web REST endpoints. + */ + @Pointcut("within(@org.springframework.stereotype.Repository *)" + + " || within(@org.springframework.stereotype.Service *)" + + " || within(@org.springframework.web.bind.annotation.RestController *)") + public void springBeanPointcut() { + // Method is empty as this is just a Pointcut, the implementations are in the advices. + } + + /** + * Pointcut that matches all Spring beans in the application's main packages. + */ + @Pointcut("within(com.baeldung.jhipster5.repository..*)"+ + " || within(com.baeldung.jhipster5.service..*)"+ + " || within(com.baeldung.jhipster5.web.rest..*)") + public void applicationPackagePointcut() { + // Method is empty as this is just a Pointcut, the implementations are in the advices. + } + + /** + * Advice that logs methods throwing exceptions. + * + * @param joinPoint join point for advice + * @param e exception + */ + @AfterThrowing(pointcut = "applicationPackagePointcut() && springBeanPointcut()", throwing = "e") + public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) { + log.error("Exception in {}.{}() with cause = \'{}\' and exception = \'{}\'", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL", e.getMessage(), e); + + } else { + log.error("Exception in {}.{}() with cause = {}", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL"); + } + } + + /** + * Advice that logs when a method is entered and exited. + * + * @param joinPoint join point for advice + * @return result + * @throws Throwable throws IllegalArgumentException + */ + @Around("applicationPackagePointcut() && springBeanPointcut()") + public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { + if (log.isDebugEnabled()) { + log.debug("Enter: {}.{}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs())); + } + try { + Object result = joinPoint.proceed(); + if (log.isDebugEnabled()) { + log.debug("Exit: {}.{}() with result = {}", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), result); + } + return result; + } catch (IllegalArgumentException e) { + log.error("Illegal argument: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()), + joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); + + throw e; + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/ApplicationProperties.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/ApplicationProperties.java new file mode 100644 index 0000000000..4ca3e9bd85 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/ApplicationProperties.java @@ -0,0 +1,14 @@ +package com.baeldung.jhipster5.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Properties specific to Bookstore. + *

+ * Properties are configured in the application.yml file. + * See {@link io.github.jhipster.config.JHipsterProperties} for a good example. + */ +@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false) +public class ApplicationProperties { + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/AsyncConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/AsyncConfiguration.java new file mode 100644 index 0000000000..414fe152bf --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/AsyncConfiguration.java @@ -0,0 +1,59 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.async.ExceptionHandlingAsyncTaskExecutor; +import io.github.jhipster.config.JHipsterProperties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.*; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +@Configuration +@EnableAsync +@EnableScheduling +public class AsyncConfiguration implements AsyncConfigurer, SchedulingConfigurer { + + private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class); + + private final JHipsterProperties jHipsterProperties; + + public AsyncConfiguration(JHipsterProperties jHipsterProperties) { + this.jHipsterProperties = jHipsterProperties; + } + + @Override + @Bean(name = "taskExecutor") + public Executor getAsyncExecutor() { + log.debug("Creating Async Task Executor"); + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize()); + executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize()); + executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity()); + executor.setThreadNamePrefix("bookstore-Executor-"); + return new ExceptionHandlingAsyncTaskExecutor(executor); + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return new SimpleAsyncUncaughtExceptionHandler(); + } + + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + taskRegistrar.setScheduler(scheduledTaskExecutor()); + } + + @Bean + public Executor scheduledTaskExecutor() { + return Executors.newScheduledThreadPool(jHipsterProperties.getAsync().getCorePoolSize()); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/CloudDatabaseConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/CloudDatabaseConfiguration.java new file mode 100644 index 0000000000..887a1bae89 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/CloudDatabaseConfiguration.java @@ -0,0 +1,28 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.JHipsterConstants; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.config.java.AbstractCloudConfig; +import org.springframework.context.annotation.*; + +import javax.sql.DataSource; +import org.springframework.boot.context.properties.ConfigurationProperties; + + +@Configuration +@Profile(JHipsterConstants.SPRING_PROFILE_CLOUD) +public class CloudDatabaseConfiguration extends AbstractCloudConfig { + + private final Logger log = LoggerFactory.getLogger(CloudDatabaseConfiguration.class); + + private static final String CLOUD_CONFIGURATION_HIKARI_PREFIX = "spring.datasource.hikari"; + + @Bean + @ConfigurationProperties(CLOUD_CONFIGURATION_HIKARI_PREFIX) + public DataSource dataSource() { + log.info("Configuring JDBC datasource from a cloud provider"); + return connectionFactory().dataSource(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/Constants.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/Constants.java new file mode 100644 index 0000000000..dd8f717f98 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/Constants.java @@ -0,0 +1,17 @@ +package com.baeldung.jhipster5.config; + +/** + * Application constants. + */ +public final class Constants { + + // Regex for acceptable logins + public static final String LOGIN_REGEX = "^[_.@A-Za-z0-9-]*$"; + + public static final String SYSTEM_ACCOUNT = "system"; + public static final String ANONYMOUS_USER = "anonymoususer"; + public static final String DEFAULT_LANGUAGE = "en"; + + private Constants() { + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DatabaseConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DatabaseConfiguration.java new file mode 100644 index 0000000000..007b1d6431 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DatabaseConfiguration.java @@ -0,0 +1,59 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.JHipsterConstants; +import io.github.jhipster.config.h2.H2ConfigurationHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.sql.SQLException; + +@Configuration +@EnableJpaRepositories("com.baeldung.jhipster5.repository") +@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware") +@EnableTransactionManagement +public class DatabaseConfiguration { + + private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class); + + private final Environment env; + + public DatabaseConfiguration(Environment env) { + this.env = env; + } + + /** + * Open the TCP port for the H2 database, so it is available remotely. + * + * @return the H2 database TCP server + * @throws SQLException if the server failed to start + */ + @Bean(initMethod = "start", destroyMethod = "stop") + @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) + public Object h2TCPServer() throws SQLException { + String port = getValidPortForH2(); + log.debug("H2 database is available on port {}", port); + return H2ConfigurationHelper.createServer(port); + } + + private String getValidPortForH2() { + int port = Integer.parseInt(env.getProperty("server.port")); + if (port < 10000) { + port = 10000 + port; + } else { + if (port < 63536) { + port = port + 2000; + } else { + port = port - 2000; + } + } + return String.valueOf(port); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DateTimeFormatConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DateTimeFormatConfiguration.java new file mode 100644 index 0000000000..4415ce0b1e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DateTimeFormatConfiguration.java @@ -0,0 +1,20 @@ +package com.baeldung.jhipster5.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * Configure the converters to use the ISO format for dates by default. + */ +@Configuration +public class DateTimeFormatConfiguration implements WebMvcConfigurer { + + @Override + public void addFormatters(FormatterRegistry registry) { + DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); + registrar.setUseIsoFormat(true); + registrar.registerFormatters(registry); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DefaultProfileUtil.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DefaultProfileUtil.java new file mode 100644 index 0000000000..2cfe16a1ae --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/DefaultProfileUtil.java @@ -0,0 +1,51 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.JHipsterConstants; + +import org.springframework.boot.SpringApplication; +import org.springframework.core.env.Environment; + +import java.util.*; + +/** + * Utility class to load a Spring profile to be used as default + * when there is no spring.profiles.active set in the environment or as command line argument. + * If the value is not available in application.yml then dev profile will be used as default. + */ +public final class DefaultProfileUtil { + + private static final String SPRING_PROFILE_DEFAULT = "spring.profiles.default"; + + private DefaultProfileUtil() { + } + + /** + * Set a default to use when no profile is configured. + * + * @param app the Spring application + */ + public static void addDefaultProfile(SpringApplication app) { + Map defProperties = new HashMap<>(); + /* + * The default profile to use when no other profiles are defined + * This cannot be set in the application.yml file. + * See https://github.com/spring-projects/spring-boot/issues/1219 + */ + defProperties.put(SPRING_PROFILE_DEFAULT, JHipsterConstants.SPRING_PROFILE_DEVELOPMENT); + app.setDefaultProperties(defProperties); + } + + /** + * Get the profiles that are applied else get default profiles. + * + * @param env spring environment + * @return profiles + */ + public static String[] getActiveProfiles(Environment env) { + String[] profiles = env.getActiveProfiles(); + if (profiles.length == 0) { + return env.getDefaultProfiles(); + } + return profiles; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/JacksonConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/JacksonConfiguration.java new file mode 100644 index 0000000000..119cd5f0c6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/JacksonConfiguration.java @@ -0,0 +1,63 @@ +package com.baeldung.jhipster5.config; + +import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.module.afterburner.AfterburnerModule; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.zalando.problem.ProblemModule; +import org.zalando.problem.violations.ConstraintViolationProblemModule; + +@Configuration +public class JacksonConfiguration { + + /** + * Support for Java date and time API. + * @return the corresponding Jackson module. + */ + @Bean + public JavaTimeModule javaTimeModule() { + return new JavaTimeModule(); + } + + @Bean + public Jdk8Module jdk8TimeModule() { + return new Jdk8Module(); + } + + + /* + * Support for Hibernate types in Jackson. + */ + @Bean + public Hibernate5Module hibernate5Module() { + return new Hibernate5Module(); + } + + /* + * Jackson Afterburner module to speed up serialization/deserialization. + */ + @Bean + public AfterburnerModule afterburnerModule() { + return new AfterburnerModule(); + } + + /* + * Module for serialization/deserialization of RFC7807 Problem. + */ + @Bean + ProblemModule problemModule() { + return new ProblemModule(); + } + + /* + * Module for serialization/deserialization of ConstraintViolationProblem. + */ + @Bean + ConstraintViolationProblemModule constraintViolationProblemModule() { + return new ConstraintViolationProblemModule(); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LiquibaseConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LiquibaseConfiguration.java new file mode 100644 index 0000000000..4b2a7b1e66 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LiquibaseConfiguration.java @@ -0,0 +1,50 @@ +package com.baeldung.jhipster5.config; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.core.task.TaskExecutor; + +import io.github.jhipster.config.JHipsterConstants; +import io.github.jhipster.config.liquibase.AsyncSpringLiquibase; +import liquibase.integration.spring.SpringLiquibase; + +@Configuration +public class LiquibaseConfiguration { + + private final Logger log = LoggerFactory.getLogger(LiquibaseConfiguration.class); + + private final Environment env; + + + public LiquibaseConfiguration(Environment env) { + this.env = env; + } + + @Bean + public SpringLiquibase liquibase(@Qualifier("taskExecutor") TaskExecutor taskExecutor, + DataSource dataSource, LiquibaseProperties liquibaseProperties) { + + // Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously + SpringLiquibase liquibase = new AsyncSpringLiquibase(taskExecutor, env); + liquibase.setDataSource(dataSource); + liquibase.setChangeLog("classpath:config/liquibase/master.xml"); + liquibase.setContexts(liquibaseProperties.getContexts()); + liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema()); + liquibase.setDropFirst(liquibaseProperties.isDropFirst()); + liquibase.setChangeLogParameters(liquibaseProperties.getParameters()); + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE)) { + liquibase.setShouldRun(false); + } else { + liquibase.setShouldRun(liquibaseProperties.isEnabled()); + log.debug("Configuring Liquibase"); + } + return liquibase; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LocaleConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LocaleConfiguration.java new file mode 100644 index 0000000000..256c6b77b9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LocaleConfiguration.java @@ -0,0 +1,27 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.locale.AngularCookieLocaleResolver; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.*; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; + +@Configuration +public class LocaleConfiguration implements WebMvcConfigurer { + + @Bean(name = "localeResolver") + public LocaleResolver localeResolver() { + AngularCookieLocaleResolver cookieLocaleResolver = new AngularCookieLocaleResolver(); + cookieLocaleResolver.setCookieName("NG_TRANSLATE_LANG_KEY"); + return cookieLocaleResolver; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); + localeChangeInterceptor.setParamName("language"); + registry.addInterceptor(localeChangeInterceptor); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingAspectConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingAspectConfiguration.java new file mode 100644 index 0000000000..25d7ba3792 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingAspectConfiguration.java @@ -0,0 +1,19 @@ +package com.baeldung.jhipster5.config; + +import com.baeldung.jhipster5.aop.logging.LoggingAspect; + +import io.github.jhipster.config.JHipsterConstants; + +import org.springframework.context.annotation.*; +import org.springframework.core.env.Environment; + +@Configuration +@EnableAspectJAutoProxy +public class LoggingAspectConfiguration { + + @Bean + @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) + public LoggingAspect loggingAspect(Environment env) { + return new LoggingAspect(env); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingConfiguration.java new file mode 100644 index 0000000000..9402a1bc36 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/LoggingConfiguration.java @@ -0,0 +1,154 @@ +package com.baeldung.jhipster5.config; + +import java.net.InetSocketAddress; +import java.util.Iterator; + +import io.github.jhipster.config.JHipsterProperties; + +import ch.qos.logback.classic.AsyncAppender; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.boolex.OnMarkerEvaluator; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.LoggerContextListener; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.filter.EvaluatorFilter; +import ch.qos.logback.core.spi.ContextAwareBase; +import ch.qos.logback.core.spi.FilterReply; +import net.logstash.logback.appender.LogstashTcpSocketAppender; +import net.logstash.logback.encoder.LogstashEncoder; +import net.logstash.logback.stacktrace.ShortenedThrowableConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LoggingConfiguration { + + private static final String LOGSTASH_APPENDER_NAME = "LOGSTASH"; + + private static final String ASYNC_LOGSTASH_APPENDER_NAME = "ASYNC_LOGSTASH"; + + private final Logger log = LoggerFactory.getLogger(LoggingConfiguration.class); + + private LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + + private final String appName; + + private final String serverPort; + + private final JHipsterProperties jHipsterProperties; + + public LoggingConfiguration(@Value("${spring.application.name}") String appName, @Value("${server.port}") String serverPort, + JHipsterProperties jHipsterProperties) { + this.appName = appName; + this.serverPort = serverPort; + this.jHipsterProperties = jHipsterProperties; + if (jHipsterProperties.getLogging().getLogstash().isEnabled()) { + addLogstashAppender(context); + addContextListener(context); + } + if (jHipsterProperties.getMetrics().getLogs().isEnabled()) { + setMetricsMarkerLogbackFilter(context); + } + } + + private void addContextListener(LoggerContext context) { + LogbackLoggerContextListener loggerContextListener = new LogbackLoggerContextListener(); + loggerContextListener.setContext(context); + context.addListener(loggerContextListener); + } + + private void addLogstashAppender(LoggerContext context) { + log.info("Initializing Logstash logging"); + + LogstashTcpSocketAppender logstashAppender = new LogstashTcpSocketAppender(); + logstashAppender.setName(LOGSTASH_APPENDER_NAME); + logstashAppender.setContext(context); + String customFields = "{\"app_name\":\"" + appName + "\",\"app_port\":\"" + serverPort + "\"}"; + + // More documentation is available at: https://github.com/logstash/logstash-logback-encoder + LogstashEncoder logstashEncoder = new LogstashEncoder(); + // Set the Logstash appender config from JHipster properties + logstashAppender.addDestinations(new InetSocketAddress(jHipsterProperties.getLogging().getLogstash().getHost(), jHipsterProperties.getLogging().getLogstash().getPort())); + + ShortenedThrowableConverter throwableConverter = new ShortenedThrowableConverter(); + throwableConverter.setRootCauseFirst(true); + logstashEncoder.setThrowableConverter(throwableConverter); + logstashEncoder.setCustomFields(customFields); + + logstashAppender.setEncoder(logstashEncoder); + logstashAppender.start(); + + // Wrap the appender in an Async appender for performance + AsyncAppender asyncLogstashAppender = new AsyncAppender(); + asyncLogstashAppender.setContext(context); + asyncLogstashAppender.setName(ASYNC_LOGSTASH_APPENDER_NAME); + asyncLogstashAppender.setQueueSize(jHipsterProperties.getLogging().getLogstash().getQueueSize()); + asyncLogstashAppender.addAppender(logstashAppender); + asyncLogstashAppender.start(); + + context.getLogger("ROOT").addAppender(asyncLogstashAppender); + } + + // Configure a log filter to remove "metrics" logs from all appenders except the "LOGSTASH" appender + private void setMetricsMarkerLogbackFilter(LoggerContext context) { + log.info("Filtering metrics logs from all appenders except the {} appender", LOGSTASH_APPENDER_NAME); + OnMarkerEvaluator onMarkerMetricsEvaluator = new OnMarkerEvaluator(); + onMarkerMetricsEvaluator.setContext(context); + onMarkerMetricsEvaluator.addMarker("metrics"); + onMarkerMetricsEvaluator.start(); + EvaluatorFilter metricsFilter = new EvaluatorFilter<>(); + metricsFilter.setContext(context); + metricsFilter.setEvaluator(onMarkerMetricsEvaluator); + metricsFilter.setOnMatch(FilterReply.DENY); + metricsFilter.start(); + + for (ch.qos.logback.classic.Logger logger : context.getLoggerList()) { + for (Iterator> it = logger.iteratorForAppenders(); it.hasNext();) { + Appender appender = it.next(); + if (!appender.getName().equals(ASYNC_LOGSTASH_APPENDER_NAME)) { + log.debug("Filter metrics logs from the {} appender", appender.getName()); + appender.setContext(context); + appender.addFilter(metricsFilter); + appender.start(); + } + } + } + } + + /** + * Logback configuration is achieved by configuration file and API. + * When configuration file change is detected, the configuration is reset. + * This listener ensures that the programmatic configuration is also re-applied after reset. + */ + class LogbackLoggerContextListener extends ContextAwareBase implements LoggerContextListener { + + @Override + public boolean isResetResistant() { + return true; + } + + @Override + public void onStart(LoggerContext context) { + addLogstashAppender(context); + } + + @Override + public void onReset(LoggerContext context) { + addLogstashAppender(context); + } + + @Override + public void onStop(LoggerContext context) { + // Nothing to do. + } + + @Override + public void onLevelChange(ch.qos.logback.classic.Logger logger, Level level) { + // Nothing to do. + } + } + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/SecurityConfiguration.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/SecurityConfiguration.java new file mode 100644 index 0000000000..f07944271e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/SecurityConfiguration.java @@ -0,0 +1,122 @@ +package com.baeldung.jhipster5.config; + +import com.baeldung.jhipster5.security.*; +import com.baeldung.jhipster5.security.jwt.*; + +import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.filter.CorsFilter; +import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport; + +import javax.annotation.PostConstruct; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +@Import(SecurityProblemSupport.class) +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + private final AuthenticationManagerBuilder authenticationManagerBuilder; + + private final UserDetailsService userDetailsService; + + private final TokenProvider tokenProvider; + + private final CorsFilter corsFilter; + + private final SecurityProblemSupport problemSupport; + + public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService, TokenProvider tokenProvider, CorsFilter corsFilter, SecurityProblemSupport problemSupport) { + this.authenticationManagerBuilder = authenticationManagerBuilder; + this.userDetailsService = userDetailsService; + this.tokenProvider = tokenProvider; + this.corsFilter = corsFilter; + this.problemSupport = problemSupport; + } + + @PostConstruct + public void init() { + try { + authenticationManagerBuilder + .userDetailsService(userDetailsService) + .passwordEncoder(passwordEncoder()); + } catch (Exception e) { + throw new BeanInitializationException("Security configuration failed", e); + } + } + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring() + .antMatchers(HttpMethod.OPTIONS, "/**") + .antMatchers("/app/**/*.{js,html}") + .antMatchers("/i18n/**") + .antMatchers("/content/**") + .antMatchers("/h2-console/**") + .antMatchers("/swagger-ui/index.html") + .antMatchers("/test/**"); + } + + @Override + public void configure(HttpSecurity http) throws Exception { + http + .csrf() + .disable() + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + .exceptionHandling() + .authenticationEntryPoint(problemSupport) + .accessDeniedHandler(problemSupport) + .and() + .headers() + .frameOptions() + .disable() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + .antMatchers("/api/books/purchase/**").authenticated() + .antMatchers("/api/register").permitAll() + .antMatchers("/api/activate").permitAll() + .antMatchers("/api/authenticate").permitAll() + .antMatchers("/api/account/reset-password/init").permitAll() + .antMatchers("/api/account/reset-password/finish").permitAll() + .antMatchers("/api/**").authenticated() + .antMatchers("/management/health").permitAll() + .antMatchers("/management/info").permitAll() + .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN) + .and() + .apply(securityConfigurerAdapter()); + + } + + private JWTConfigurer securityConfigurerAdapter() { + return new JWTConfigurer(tokenProvider); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/WebConfigurer.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/WebConfigurer.java new file mode 100644 index 0000000000..26cfc92487 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/WebConfigurer.java @@ -0,0 +1,170 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.JHipsterConstants; +import io.github.jhipster.config.JHipsterProperties; +import io.github.jhipster.config.h2.H2ConfigurationHelper; +import io.github.jhipster.web.filter.CachingHttpHeadersFilter; +import io.undertow.UndertowOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; +import org.springframework.boot.web.server.*; +import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.http.MediaType; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import javax.servlet.*; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.*; + +import static java.net.URLDecoder.decode; + +/** + * Configuration of web application with Servlet 3.0 APIs. + */ +@Configuration +public class WebConfigurer implements ServletContextInitializer, WebServerFactoryCustomizer { + + private final Logger log = LoggerFactory.getLogger(WebConfigurer.class); + + private final Environment env; + + private final JHipsterProperties jHipsterProperties; + + public WebConfigurer(Environment env, JHipsterProperties jHipsterProperties) { + + this.env = env; + this.jHipsterProperties = jHipsterProperties; + } + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + if (env.getActiveProfiles().length != 0) { + log.info("Web application configuration, using profiles: {}", (Object[]) env.getActiveProfiles()); + } + EnumSet disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC); + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) { + initCachingHttpHeadersFilter(servletContext, disps); + } + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) { + initH2Console(servletContext); + } + log.info("Web application fully configured"); + } + + /** + * Customize the Servlet engine: Mime types, the document root, the cache. + */ + @Override + public void customize(WebServerFactory server) { + setMimeMappings(server); + // When running in an IDE or with ./mvnw spring-boot:run, set location of the static web assets. + setLocationForStaticAssets(server); + + /* + * Enable HTTP/2 for Undertow - https://twitter.com/ankinson/status/829256167700492288 + * HTTP/2 requires HTTPS, so HTTP requests will fallback to HTTP/1.1. + * See the JHipsterProperties class and your application-*.yml configuration files + * for more information. + */ + if (jHipsterProperties.getHttp().getVersion().equals(JHipsterProperties.Http.Version.V_2_0) && + server instanceof UndertowServletWebServerFactory) { + + ((UndertowServletWebServerFactory) server) + .addBuilderCustomizers(builder -> + builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true)); + } + } + + private void setMimeMappings(WebServerFactory server) { + if (server instanceof ConfigurableServletWebServerFactory) { + MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT); + // IE issue, see https://github.com/jhipster/generator-jhipster/pull/711 + mappings.add("html", MediaType.TEXT_HTML_VALUE + ";charset=" + StandardCharsets.UTF_8.name().toLowerCase()); + // CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64 + mappings.add("json", MediaType.TEXT_HTML_VALUE + ";charset=" + StandardCharsets.UTF_8.name().toLowerCase()); + ConfigurableServletWebServerFactory servletWebServer = (ConfigurableServletWebServerFactory) server; + servletWebServer.setMimeMappings(mappings); + } + } + + private void setLocationForStaticAssets(WebServerFactory server) { + if (server instanceof ConfigurableServletWebServerFactory) { + ConfigurableServletWebServerFactory servletWebServer = (ConfigurableServletWebServerFactory) server; + File root; + String prefixPath = resolvePathPrefix(); + root = new File(prefixPath + "target/www/"); + if (root.exists() && root.isDirectory()) { + servletWebServer.setDocumentRoot(root); + } + } + } + + /** + * Resolve path prefix to static resources. + */ + private String resolvePathPrefix() { + String fullExecutablePath; + try { + fullExecutablePath = decode(this.getClass().getResource("").getPath(), StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + /* try without decoding if this ever happens */ + fullExecutablePath = this.getClass().getResource("").getPath(); + } + String rootPath = Paths.get(".").toUri().normalize().getPath(); + String extractedPath = fullExecutablePath.replace(rootPath, ""); + int extractionEndIndex = extractedPath.indexOf("target/"); + if (extractionEndIndex <= 0) { + return ""; + } + return extractedPath.substring(0, extractionEndIndex); + } + + /** + * Initializes the caching HTTP Headers Filter. + */ + private void initCachingHttpHeadersFilter(ServletContext servletContext, + EnumSet disps) { + log.debug("Registering Caching HTTP Headers Filter"); + FilterRegistration.Dynamic cachingHttpHeadersFilter = + servletContext.addFilter("cachingHttpHeadersFilter", + new CachingHttpHeadersFilter(jHipsterProperties)); + + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/i18n/*"); + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/content/*"); + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/app/*"); + cachingHttpHeadersFilter.setAsyncSupported(true); + } + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = jHipsterProperties.getCors(); + if (config.getAllowedOrigins() != null && !config.getAllowedOrigins().isEmpty()) { + log.debug("Registering CORS filter"); + source.registerCorsConfiguration("/api/**", config); + source.registerCorsConfiguration("/management/**", config); + source.registerCorsConfiguration("/v2/api-docs", config); + } + return new CorsFilter(source); + } + + /** + * Initializes H2 console. + */ + private void initH2Console(ServletContext servletContext) { + log.debug("Initialize H2 console"); + H2ConfigurationHelper.initH2Console(servletContext); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/AuditEventConverter.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/AuditEventConverter.java new file mode 100644 index 0000000000..6dd87bb82d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/AuditEventConverter.java @@ -0,0 +1,86 @@ +package com.baeldung.jhipster5.config.audit; + +import com.baeldung.jhipster5.domain.PersistentAuditEvent; + +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component +public class AuditEventConverter { + + /** + * Convert a list of PersistentAuditEvent to a list of AuditEvent + * + * @param persistentAuditEvents the list to convert + * @return the converted list. + */ + public List convertToAuditEvent(Iterable persistentAuditEvents) { + if (persistentAuditEvents == null) { + return Collections.emptyList(); + } + List auditEvents = new ArrayList<>(); + for (PersistentAuditEvent persistentAuditEvent : persistentAuditEvents) { + auditEvents.add(convertToAuditEvent(persistentAuditEvent)); + } + return auditEvents; + } + + /** + * Convert a PersistentAuditEvent to an AuditEvent + * + * @param persistentAuditEvent the event to convert + * @return the converted list. + */ + public AuditEvent convertToAuditEvent(PersistentAuditEvent persistentAuditEvent) { + if (persistentAuditEvent == null) { + return null; + } + return new AuditEvent(persistentAuditEvent.getAuditEventDate(), persistentAuditEvent.getPrincipal(), + persistentAuditEvent.getAuditEventType(), convertDataToObjects(persistentAuditEvent.getData())); + } + + /** + * Internal conversion. This is needed to support the current SpringBoot actuator AuditEventRepository interface + * + * @param data the data to convert + * @return a map of String, Object + */ + public Map convertDataToObjects(Map data) { + Map results = new HashMap<>(); + + if (data != null) { + for (Map.Entry entry : data.entrySet()) { + results.put(entry.getKey(), entry.getValue()); + } + } + return results; + } + + /** + * Internal conversion. This method will allow to save additional data. + * By default, it will save the object as string + * + * @param data the data to convert + * @return a map of String, String + */ + public Map convertDataToStrings(Map data) { + Map results = new HashMap<>(); + + if (data != null) { + for (Map.Entry entry : data.entrySet()) { + // Extract the data that will be saved. + if (entry.getValue() instanceof WebAuthenticationDetails) { + WebAuthenticationDetails authenticationDetails = (WebAuthenticationDetails) entry.getValue(); + results.put("remoteAddress", authenticationDetails.getRemoteAddress()); + results.put("sessionId", authenticationDetails.getSessionId()); + } else { + results.put(entry.getKey(), Objects.toString(entry.getValue())); + } + } + } + return results; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/package-info.java new file mode 100644 index 0000000000..49a2a73a61 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/audit/package-info.java @@ -0,0 +1,4 @@ +/** + * Audit specific code. + */ +package com.baeldung.jhipster5.config.audit; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/package-info.java new file mode 100644 index 0000000000..868155ce9f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/config/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring Framework configuration files. + */ +package com.baeldung.jhipster5.config; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/AbstractAuditingEntity.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/AbstractAuditingEntity.java new file mode 100644 index 0000000000..861674ccc9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/AbstractAuditingEntity.java @@ -0,0 +1,79 @@ +package com.baeldung.jhipster5.domain; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.hibernate.envers.Audited; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.io.Serializable; +import java.time.Instant; +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; + +/** + * Base abstract class for entities which will hold definitions for created, last modified by and created, + * last modified by date. + */ +@MappedSuperclass +@Audited +@EntityListeners(AuditingEntityListener.class) +public abstract class AbstractAuditingEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + @CreatedBy + @Column(name = "created_by", nullable = false, length = 50, updatable = false) + @JsonIgnore + private String createdBy; + + @CreatedDate + @Column(name = "created_date", updatable = false) + @JsonIgnore + private Instant createdDate = Instant.now(); + + @LastModifiedBy + @Column(name = "last_modified_by", length = 50) + @JsonIgnore + private String lastModifiedBy; + + @LastModifiedDate + @Column(name = "last_modified_date") + @JsonIgnore + private Instant lastModifiedDate = Instant.now(); + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Instant getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Instant createdDate) { + this.createdDate = createdDate; + } + + public String getLastModifiedBy() { + return lastModifiedBy; + } + + public void setLastModifiedBy(String lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + public Instant getLastModifiedDate() { + return lastModifiedDate; + } + + public void setLastModifiedDate(Instant lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Authority.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Authority.java new file mode 100644 index 0000000000..fbd4596fc7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Authority.java @@ -0,0 +1,59 @@ +package com.baeldung.jhipster5.domain; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Column; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; + +/** + * An authority (a security role) used by Spring Security. + */ +@Entity +@Table(name = "jhi_authority") +public class Authority implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull + @Size(max = 50) + @Id + @Column(length = 50) + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Authority authority = (Authority) o; + + return !(name != null ? !name.equals(authority.name) : authority.name != null); + } + + @Override + public int hashCode() { + return name != null ? name.hashCode() : 0; + } + + @Override + public String toString() { + return "Authority{" + + "name='" + name + '\'' + + "}"; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Book.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Book.java new file mode 100644 index 0000000000..16771d9e09 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/Book.java @@ -0,0 +1,153 @@ +package com.baeldung.jhipster5.domain; + + + +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.io.Serializable; +import java.time.LocalDate; +import java.util.Objects; + +/** + * A Book. + */ +@Entity +@Table(name = "book") +public class Book implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @Column(name = "title", nullable = false) + private String title; + + @NotNull + @Column(name = "author", nullable = false) + private String author; + + @NotNull + @Column(name = "published", nullable = false) + private LocalDate published; + + @NotNull + @Min(value = 0) + @Column(name = "quantity", nullable = false) + private Integer quantity; + + @NotNull + @DecimalMin(value = "0") + @Column(name = "price", nullable = false) + private Double price; + + // jhipster-needle-entity-add-field - JHipster will add fields here, do not remove + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public Book title(String title) { + this.title = title; + return this; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public Book author(String author) { + this.author = author; + return this; + } + + public void setAuthor(String author) { + this.author = author; + } + + public LocalDate getPublished() { + return published; + } + + public Book published(LocalDate published) { + this.published = published; + return this; + } + + public void setPublished(LocalDate published) { + this.published = published; + } + + public Integer getQuantity() { + return quantity; + } + + public Book quantity(Integer quantity) { + this.quantity = quantity; + return this; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public Double getPrice() { + return price; + } + + public Book price(Double price) { + this.price = price; + return this; + } + + public void setPrice(Double price) { + this.price = price; + } + // jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Book book = (Book) o; + if (book.getId() == null || getId() == null) { + return false; + } + return Objects.equals(getId(), book.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getId()); + } + + @Override + public String toString() { + return "Book{" + + "id=" + getId() + + ", title='" + getTitle() + "'" + + ", author='" + getAuthor() + "'" + + ", published='" + getPublished() + "'" + + ", quantity=" + getQuantity() + + ", price=" + getPrice() + + "}"; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/PersistentAuditEvent.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/PersistentAuditEvent.java new file mode 100644 index 0000000000..15e2eeda5a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/PersistentAuditEvent.java @@ -0,0 +1,109 @@ +package com.baeldung.jhipster5.domain; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.time.Instant; +import java.util.HashMap; +import java.util.Objects; +import java.util.Map; + +/** + * Persist AuditEvent managed by the Spring Boot actuator. + * + * @see org.springframework.boot.actuate.audit.AuditEvent + */ +@Entity +@Table(name = "jhi_persistent_audit_event") +public class PersistentAuditEvent implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "event_id") + private Long id; + + @NotNull + @Column(nullable = false) + private String principal; + + @Column(name = "event_date") + private Instant auditEventDate; + + @Column(name = "event_type") + private String auditEventType; + + @ElementCollection + @MapKeyColumn(name = "name") + @Column(name = "value") + @CollectionTable(name = "jhi_persistent_audit_evt_data", joinColumns=@JoinColumn(name="event_id")) + private Map data = new HashMap<>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getPrincipal() { + return principal; + } + + public void setPrincipal(String principal) { + this.principal = principal; + } + + public Instant getAuditEventDate() { + return auditEventDate; + } + + public void setAuditEventDate(Instant auditEventDate) { + this.auditEventDate = auditEventDate; + } + + public String getAuditEventType() { + return auditEventType; + } + + public void setAuditEventType(String auditEventType) { + this.auditEventType = auditEventType; + } + + public Map getData() { + return data; + } + + public void setData(Map data) { + this.data = data; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PersistentAuditEvent persistentAuditEvent = (PersistentAuditEvent) o; + return !(persistentAuditEvent.getId() == null || getId() == null) && Objects.equals(getId(), persistentAuditEvent.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getId()); + } + + @Override + public String toString() { + return "PersistentAuditEvent{" + + "principal='" + principal + '\'' + + ", auditEventDate=" + auditEventDate + + ", auditEventType='" + auditEventType + '\'' + + '}'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/User.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/User.java new file mode 100644 index 0000000000..ff12d1ca9c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/User.java @@ -0,0 +1,231 @@ +package com.baeldung.jhipster5.domain; + +import com.baeldung.jhipster5.config.Constants; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.apache.commons.lang3.StringUtils; +import org.hibernate.annotations.BatchSize; +import javax.validation.constraints.Email; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; +import java.time.Instant; + +/** + * A user. + */ +@Entity +@Table(name = "jhi_user") + +public class User extends AbstractAuditingEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @Pattern(regexp = Constants.LOGIN_REGEX) + @Size(min = 1, max = 50) + @Column(length = 50, unique = true, nullable = false) + private String login; + + @JsonIgnore + @NotNull + @Size(min = 60, max = 60) + @Column(name = "password_hash", length = 60, nullable = false) + private String password; + + @Size(max = 50) + @Column(name = "first_name", length = 50) + private String firstName; + + @Size(max = 50) + @Column(name = "last_name", length = 50) + private String lastName; + + @Email + @Size(min = 5, max = 254) + @Column(length = 254, unique = true) + private String email; + + @NotNull + @Column(nullable = false) + private boolean activated = false; + + @Size(min = 2, max = 6) + @Column(name = "lang_key", length = 6) + private String langKey; + + @Size(max = 256) + @Column(name = "image_url", length = 256) + private String imageUrl; + + @Size(max = 20) + @Column(name = "activation_key", length = 20) + @JsonIgnore + private String activationKey; + + @Size(max = 20) + @Column(name = "reset_key", length = 20) + @JsonIgnore + private String resetKey; + + @Column(name = "reset_date") + private Instant resetDate = null; + + @JsonIgnore + @ManyToMany + @JoinTable( + name = "jhi_user_authority", + joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")}, + inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "name")}) + + @BatchSize(size = 20) + private Set authorities = new HashSet<>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getLogin() { + return login; + } + + // Lowercase the login before saving it in database + public void setLogin(String login) { + this.login = StringUtils.lowerCase(login, Locale.ENGLISH); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + public boolean getActivated() { + return activated; + } + + public void setActivated(boolean activated) { + this.activated = activated; + } + + public String getActivationKey() { + return activationKey; + } + + public void setActivationKey(String activationKey) { + this.activationKey = activationKey; + } + + public String getResetKey() { + return resetKey; + } + + public void setResetKey(String resetKey) { + this.resetKey = resetKey; + } + + public Instant getResetDate() { + return resetDate; + } + + public void setResetDate(Instant resetDate) { + this.resetDate = resetDate; + } + + public String getLangKey() { + return langKey; + } + + public void setLangKey(String langKey) { + this.langKey = langKey; + } + + public Set getAuthorities() { + return authorities; + } + + public void setAuthorities(Set authorities) { + this.authorities = authorities; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + User user = (User) o; + return !(user.getId() == null || getId() == null) && Objects.equals(getId(), user.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getId()); + } + + @Override + public String toString() { + return "User{" + + "login='" + login + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", imageUrl='" + imageUrl + '\'' + + ", activated='" + activated + '\'' + + ", langKey='" + langKey + '\'' + + ", activationKey='" + activationKey + '\'' + + "}"; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/package-info.java new file mode 100644 index 0000000000..eba92a598e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/domain/package-info.java @@ -0,0 +1,4 @@ +/** + * JPA domain objects. + */ +package com.baeldung.jhipster5.domain; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/AuthorityRepository.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/AuthorityRepository.java new file mode 100644 index 0000000000..310735eb57 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/AuthorityRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.domain.Authority; + +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * Spring Data JPA repository for the Authority entity. + */ +public interface AuthorityRepository extends JpaRepository { +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/BookRepository.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/BookRepository.java new file mode 100644 index 0000000000..ebd3117e65 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/BookRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.domain.Book; +import org.springframework.data.jpa.repository.*; +import org.springframework.stereotype.Repository; + + +/** + * Spring Data repository for the Book entity. + */ +@SuppressWarnings("unused") +@Repository +public interface BookRepository extends JpaRepository { + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/CustomAuditEventRepository.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/CustomAuditEventRepository.java new file mode 100644 index 0000000000..faa788ff5f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/CustomAuditEventRepository.java @@ -0,0 +1,89 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.config.audit.AuditEventConverter; +import com.baeldung.jhipster5.domain.PersistentAuditEvent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.actuate.audit.AuditEventRepository; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.*; + +/** + * An implementation of Spring Boot's AuditEventRepository. + */ +@Repository +public class CustomAuditEventRepository implements AuditEventRepository { + + private static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE"; + + /** + * Should be the same as in Liquibase migration. + */ + protected static final int EVENT_DATA_COLUMN_MAX_LENGTH = 255; + + private final PersistenceAuditEventRepository persistenceAuditEventRepository; + + private final AuditEventConverter auditEventConverter; + + private final Logger log = LoggerFactory.getLogger(getClass()); + + public CustomAuditEventRepository(PersistenceAuditEventRepository persistenceAuditEventRepository, + AuditEventConverter auditEventConverter) { + + this.persistenceAuditEventRepository = persistenceAuditEventRepository; + this.auditEventConverter = auditEventConverter; + } + + @Override + public List find(String principal, Instant after, String type) { + Iterable persistentAuditEvents = + persistenceAuditEventRepository.findByPrincipalAndAuditEventDateAfterAndAuditEventType(principal, after, type); + return auditEventConverter.convertToAuditEvent(persistentAuditEvents); + } + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void add(AuditEvent event) { + if (!AUTHORIZATION_FAILURE.equals(event.getType()) && + !Constants.ANONYMOUS_USER.equals(event.getPrincipal())) { + + PersistentAuditEvent persistentAuditEvent = new PersistentAuditEvent(); + persistentAuditEvent.setPrincipal(event.getPrincipal()); + persistentAuditEvent.setAuditEventType(event.getType()); + persistentAuditEvent.setAuditEventDate(event.getTimestamp()); + Map eventData = auditEventConverter.convertDataToStrings(event.getData()); + persistentAuditEvent.setData(truncate(eventData)); + persistenceAuditEventRepository.save(persistentAuditEvent); + } + } + + /** + * Truncate event data that might exceed column length. + */ + private Map truncate(Map data) { + Map results = new HashMap<>(); + + if (data != null) { + for (Map.Entry entry : data.entrySet()) { + String value = entry.getValue(); + if (value != null) { + int length = value.length(); + if (length > EVENT_DATA_COLUMN_MAX_LENGTH) { + value = value.substring(0, EVENT_DATA_COLUMN_MAX_LENGTH); + log.warn("Event data for {} too long ({}) has been truncated to {}. Consider increasing column width.", + entry.getKey(), length, EVENT_DATA_COLUMN_MAX_LENGTH); + } + } + results.put(entry.getKey(), value); + } + } + return results; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/PersistenceAuditEventRepository.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/PersistenceAuditEventRepository.java new file mode 100644 index 0000000000..2eb6f3b847 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/PersistenceAuditEventRepository.java @@ -0,0 +1,25 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.domain.PersistentAuditEvent; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.time.Instant; +import java.util.List; + +/** + * Spring Data JPA repository for the PersistentAuditEvent entity. + */ +public interface PersistenceAuditEventRepository extends JpaRepository { + + List findByPrincipal(String principal); + + List findByAuditEventDateAfter(Instant after); + + List findByPrincipalAndAuditEventDateAfter(String principal, Instant after); + + List findByPrincipalAndAuditEventDateAfterAndAuditEventType(String principal, Instant after, String type); + + Page findAllByAuditEventDateBetween(Instant fromDate, Instant toDate, Pageable pageable); +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/UserRepository.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/UserRepository.java new file mode 100644 index 0000000000..42a5588b22 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/UserRepository.java @@ -0,0 +1,40 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.domain.User; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; +import java.time.Instant; + +/** + * Spring Data JPA repository for the User entity. + */ +@Repository +public interface UserRepository extends JpaRepository { + + Optional findOneByActivationKey(String activationKey); + + List findAllByActivatedIsFalseAndCreatedDateBefore(Instant dateTime); + + Optional findOneByResetKey(String resetKey); + + Optional findOneByEmailIgnoreCase(String email); + + Optional findOneByLogin(String login); + + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesById(Long id); + + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesByLogin(String login); + + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesByEmail(String email); + + Page findAllByLoginNot(Pageable pageable, String login); +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/package-info.java new file mode 100644 index 0000000000..a5002eb201 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/repository/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring Data JPA repositories. + */ +package com.baeldung.jhipster5.repository; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/AuthoritiesConstants.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/AuthoritiesConstants.java new file mode 100644 index 0000000000..6ecf44394f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/AuthoritiesConstants.java @@ -0,0 +1,16 @@ +package com.baeldung.jhipster5.security; + +/** + * Constants for Spring Security authorities. + */ +public final class AuthoritiesConstants { + + public static final String ADMIN = "ROLE_ADMIN"; + + public static final String USER = "ROLE_USER"; + + public static final String ANONYMOUS = "ROLE_ANONYMOUS"; + + private AuthoritiesConstants() { + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/DomainUserDetailsService.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/DomainUserDetailsService.java new file mode 100644 index 0000000000..d0014096df --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/DomainUserDetailsService.java @@ -0,0 +1,62 @@ +package com.baeldung.jhipster5.security; + +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Authenticate a user from the database. + */ +@Component("userDetailsService") +public class DomainUserDetailsService implements UserDetailsService { + + private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class); + + private final UserRepository userRepository; + + public DomainUserDetailsService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + @Transactional + public UserDetails loadUserByUsername(final String login) { + log.debug("Authenticating {}", login); + + if (new EmailValidator().isValid(login, null)) { + return userRepository.findOneWithAuthoritiesByEmail(login) + .map(user -> createSpringSecurityUser(login, user)) + .orElseThrow(() -> new UsernameNotFoundException("User with email " + login + " was not found in the database")); + } + + String lowercaseLogin = login.toLowerCase(Locale.ENGLISH); + return userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin) + .map(user -> createSpringSecurityUser(lowercaseLogin, user)) + .orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the database")); + + } + + private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) { + if (!user.getActivated()) { + throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated"); + } + List grantedAuthorities = user.getAuthorities().stream() + .map(authority -> new SimpleGrantedAuthority(authority.getName())) + .collect(Collectors.toList()); + return new org.springframework.security.core.userdetails.User(user.getLogin(), + user.getPassword(), + grantedAuthorities); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SecurityUtils.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SecurityUtils.java new file mode 100644 index 0000000000..462bb8abc9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SecurityUtils.java @@ -0,0 +1,76 @@ +package com.baeldung.jhipster5.security; + +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Optional; + +/** + * Utility class for Spring Security. + */ +public final class SecurityUtils { + + private SecurityUtils() { + } + + /** + * Get the login of the current user. + * + * @return the login of the current user + */ + public static Optional getCurrentUserLogin() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return Optional.ofNullable(securityContext.getAuthentication()) + .map(authentication -> { + if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); + return springSecurityUser.getUsername(); + } else if (authentication.getPrincipal() instanceof String) { + return (String) authentication.getPrincipal(); + } + return null; + }); + } + + /** + * Get the JWT of the current user. + * + * @return the JWT of the current user + */ + public static Optional getCurrentUserJWT() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return Optional.ofNullable(securityContext.getAuthentication()) + .filter(authentication -> authentication.getCredentials() instanceof String) + .map(authentication -> (String) authentication.getCredentials()); + } + + /** + * Check if a user is authenticated. + * + * @return true if the user is authenticated, false otherwise + */ + public static boolean isAuthenticated() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return Optional.ofNullable(securityContext.getAuthentication()) + .map(authentication -> authentication.getAuthorities().stream() + .noneMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(AuthoritiesConstants.ANONYMOUS))) + .orElse(false); + } + + /** + * If the current user has a specific authority (security role). + *

+ * The name of this method comes from the isUserInRole() method in the Servlet API + * + * @param authority the authority to check + * @return true if the current user has the authority, false otherwise + */ + public static boolean isCurrentUserInRole(String authority) { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return Optional.ofNullable(securityContext.getAuthentication()) + .map(authentication -> authentication.getAuthorities().stream() + .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(authority))) + .orElse(false); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SpringSecurityAuditorAware.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SpringSecurityAuditorAware.java new file mode 100644 index 0000000000..c1d6405ae3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/SpringSecurityAuditorAware.java @@ -0,0 +1,20 @@ +package com.baeldung.jhipster5.security; + +import com.baeldung.jhipster5.config.Constants; + +import java.util.Optional; + +import org.springframework.data.domain.AuditorAware; +import org.springframework.stereotype.Component; + +/** + * Implementation of AuditorAware based on Spring Security. + */ +@Component +public class SpringSecurityAuditorAware implements AuditorAware { + + @Override + public Optional getCurrentAuditor() { + return Optional.of(SecurityUtils.getCurrentUserLogin().orElse(Constants.SYSTEM_ACCOUNT)); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/UserNotActivatedException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/UserNotActivatedException.java new file mode 100644 index 0000000000..4b2d91983c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/UserNotActivatedException.java @@ -0,0 +1,19 @@ +package com.baeldung.jhipster5.security; + +import org.springframework.security.core.AuthenticationException; + +/** + * This exception is thrown in case of a not activated user trying to authenticate. + */ +public class UserNotActivatedException extends AuthenticationException { + + private static final long serialVersionUID = 1L; + + public UserNotActivatedException(String message) { + super(message); + } + + public UserNotActivatedException(String message, Throwable t) { + super(message, t); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTConfigurer.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTConfigurer.java new file mode 100644 index 0000000000..944255e37d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTConfigurer.java @@ -0,0 +1,21 @@ +package com.baeldung.jhipster5.security.jwt; + +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +public class JWTConfigurer extends SecurityConfigurerAdapter { + + private TokenProvider tokenProvider; + + public JWTConfigurer(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void configure(HttpSecurity http) throws Exception { + JWTFilter customFilter = new JWTFilter(tokenProvider); + http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTFilter.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTFilter.java new file mode 100644 index 0000000000..cf1060282c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/JWTFilter.java @@ -0,0 +1,48 @@ +package com.baeldung.jhipster5.security.jwt; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is + * found. + */ +public class JWTFilter extends GenericFilterBean { + + public static final String AUTHORIZATION_HEADER = "Authorization"; + + private TokenProvider tokenProvider; + + public JWTFilter(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + String jwt = resolveToken(httpServletRequest); + if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) { + Authentication authentication = this.tokenProvider.getAuthentication(jwt); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + filterChain.doFilter(servletRequest, servletResponse); + } + + private String resolveToken(HttpServletRequest request){ + String bearerToken = request.getHeader(AUTHORIZATION_HEADER); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/TokenProvider.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/TokenProvider.java new file mode 100644 index 0000000000..248d45e050 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/jwt/TokenProvider.java @@ -0,0 +1,119 @@ +package com.baeldung.jhipster5.security.jwt; + +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import io.github.jhipster.config.JHipsterProperties; +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +@Component +public class TokenProvider { + + private final Logger log = LoggerFactory.getLogger(TokenProvider.class); + + private static final String AUTHORITIES_KEY = "auth"; + + private Key key; + + private long tokenValidityInMilliseconds; + + private long tokenValidityInMillisecondsForRememberMe; + + private final JHipsterProperties jHipsterProperties; + + public TokenProvider(JHipsterProperties jHipsterProperties) { + this.jHipsterProperties = jHipsterProperties; + } + + @PostConstruct + public void init() { + byte[] keyBytes; + String secret = jHipsterProperties.getSecurity().getAuthentication().getJwt().getSecret(); + if (!StringUtils.isEmpty(secret)) { + log.warn("Warning: the JWT key used is not Base64-encoded. " + + "We recommend using the `jhipster.security.authentication.jwt.base64-secret` key for optimum security."); + keyBytes = secret.getBytes(StandardCharsets.UTF_8); + } else { + log.debug("Using a Base64-encoded JWT secret key"); + keyBytes = Decoders.BASE64.decode(jHipsterProperties.getSecurity().getAuthentication().getJwt().getBase64Secret()); + } + this.key = Keys.hmacShaKeyFor(keyBytes); + this.tokenValidityInMilliseconds = + 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSeconds(); + this.tokenValidityInMillisecondsForRememberMe = + 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt() + .getTokenValidityInSecondsForRememberMe(); + } + + public String createToken(Authentication authentication, boolean rememberMe) { + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + long now = (new Date()).getTime(); + Date validity; + if (rememberMe) { + validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe); + } else { + validity = new Date(now + this.tokenValidityInMilliseconds); + } + + return Jwts.builder() + .setSubject(authentication.getName()) + .claim(AUTHORITIES_KEY, authorities) + .signWith(key, SignatureAlgorithm.HS512) + .setExpiration(validity) + .compact(); + } + + public Authentication getAuthentication(String token) { + Claims claims = Jwts.parser() + .setSigningKey(key) + .parseClaimsJws(token) + .getBody(); + + Collection authorities = + Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + User principal = new User(claims.getSubject(), "", authorities); + + return new UsernamePasswordAuthenticationToken(principal, token, authorities); + } + + public boolean validateToken(String authToken) { + try { + Jwts.parser().setSigningKey(key).parseClaimsJws(authToken); + return true; + } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { + log.info("Invalid JWT signature."); + log.trace("Invalid JWT signature trace: {}", e); + } catch (ExpiredJwtException e) { + log.info("Expired JWT token."); + log.trace("Expired JWT token trace: {}", e); + } catch (UnsupportedJwtException e) { + log.info("Unsupported JWT token."); + log.trace("Unsupported JWT token trace: {}", e); + } catch (IllegalArgumentException e) { + log.info("JWT token compact of handler are invalid."); + log.trace("JWT token compact of handler are invalid trace: {}", e); + } + return false; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/package-info.java new file mode 100644 index 0000000000..4759050c56 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/security/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring Security configuration. + */ +package com.baeldung.jhipster5.security; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/AuditEventService.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/AuditEventService.java new file mode 100644 index 0000000000..852eb951c9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/AuditEventService.java @@ -0,0 +1,51 @@ +package com.baeldung.jhipster5.service; + +import com.baeldung.jhipster5.config.audit.AuditEventConverter; +import com.baeldung.jhipster5.repository.PersistenceAuditEventRepository; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.Optional; + +/** + * Service for managing audit events. + *

+ * This is the default implementation to support SpringBoot Actuator AuditEventRepository + */ +@Service +@Transactional +public class AuditEventService { + + private final PersistenceAuditEventRepository persistenceAuditEventRepository; + + private final AuditEventConverter auditEventConverter; + + public AuditEventService( + PersistenceAuditEventRepository persistenceAuditEventRepository, + AuditEventConverter auditEventConverter) { + + this.persistenceAuditEventRepository = persistenceAuditEventRepository; + this.auditEventConverter = auditEventConverter; + } + + public Page findAll(Pageable pageable) { + return persistenceAuditEventRepository.findAll(pageable) + .map(auditEventConverter::convertToAuditEvent); + } + + public Page findByDates(Instant fromDate, Instant toDate, Pageable pageable) { + return persistenceAuditEventRepository.findAllByAuditEventDateBetween(fromDate, toDate, pageable) + .map(auditEventConverter::convertToAuditEvent); + } + + public Optional find(Long id) { + return Optional.ofNullable(persistenceAuditEventRepository.findById(id)) + .filter(Optional::isPresent) + .map(Optional::get) + .map(auditEventConverter::convertToAuditEvent); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/BookService.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/BookService.java new file mode 100644 index 0000000000..6422d1a424 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/BookService.java @@ -0,0 +1,50 @@ +package com.baeldung.jhipster5.service; + +import com.baeldung.jhipster5.service.dto.BookDTO; + +import java.util.List; +import java.util.Optional; + +/** + * Service Interface for managing Book. + */ +public interface BookService { + + /** + * Save a book. + * + * @param bookDTO the entity to save + * @return the persisted entity + */ + BookDTO save(BookDTO bookDTO); + + /** + * Get all the books. + * + * @return the list of entities + */ + List findAll(); + + + /** + * Get the "id" book. + * + * @param id the id of the entity + * @return the entity + */ + Optional findOne(Long id); + + /** + * Delete the "id" book. + * + * @param id the id of the entity + */ + void delete(Long id); + + /** + * Simulates purchasing a book by reducing the stock of a book by 1. + * @param id the id of the book + * @return Updated BookDTO, empty if not found, or throws exception if an error occurs. + */ + Optional purchase(Long id); +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/MailService.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/MailService.java new file mode 100644 index 0000000000..b15a7faff2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/MailService.java @@ -0,0 +1,105 @@ +package com.baeldung.jhipster5.service; + +import com.baeldung.jhipster5.domain.User; + +import io.github.jhipster.config.JHipsterProperties; + +import java.nio.charset.StandardCharsets; +import java.util.Locale; +import javax.mail.internet.MimeMessage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.MessageSource; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.thymeleaf.context.Context; +import org.thymeleaf.spring5.SpringTemplateEngine; + +/** + * Service for sending emails. + *

+ * We use the @Async annotation to send emails asynchronously. + */ +@Service +public class MailService { + + private final Logger log = LoggerFactory.getLogger(MailService.class); + + private static final String USER = "user"; + + private static final String BASE_URL = "baseUrl"; + + private final JHipsterProperties jHipsterProperties; + + private final JavaMailSender javaMailSender; + + private final MessageSource messageSource; + + private final SpringTemplateEngine templateEngine; + + public MailService(JHipsterProperties jHipsterProperties, JavaMailSender javaMailSender, + MessageSource messageSource, SpringTemplateEngine templateEngine) { + + this.jHipsterProperties = jHipsterProperties; + this.javaMailSender = javaMailSender; + this.messageSource = messageSource; + this.templateEngine = templateEngine; + } + + @Async + public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) { + log.debug("Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}", + isMultipart, isHtml, to, subject, content); + + // Prepare message using a Spring helper + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + try { + MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, StandardCharsets.UTF_8.name()); + message.setTo(to); + message.setFrom(jHipsterProperties.getMail().getFrom()); + message.setSubject(subject); + message.setText(content, isHtml); + javaMailSender.send(mimeMessage); + log.debug("Sent email to User '{}'", to); + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.warn("Email could not be sent to user '{}'", to, e); + } else { + log.warn("Email could not be sent to user '{}': {}", to, e.getMessage()); + } + } + } + + @Async + public void sendEmailFromTemplate(User user, String templateName, String titleKey) { + Locale locale = Locale.forLanguageTag(user.getLangKey()); + Context context = new Context(locale); + context.setVariable(USER, user); + context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl()); + String content = templateEngine.process(templateName, context); + String subject = messageSource.getMessage(titleKey, null, locale); + sendEmail(user.getEmail(), subject, content, false, true); + + } + + @Async + public void sendActivationEmail(User user) { + log.debug("Sending activation email to '{}'", user.getEmail()); + sendEmailFromTemplate(user, "mail/activationEmail", "email.activation.title"); + } + + @Async + public void sendCreationEmail(User user) { + log.debug("Sending creation email to '{}'", user.getEmail()); + sendEmailFromTemplate(user, "mail/creationEmail", "email.activation.title"); + } + + @Async + public void sendPasswordResetMail(User user) { + log.debug("Sending password reset email to '{}'", user.getEmail()); + sendEmailFromTemplate(user, "mail/passwordResetEmail", "email.reset.title"); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/UserService.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/UserService.java new file mode 100644 index 0000000000..82d028f3ca --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/UserService.java @@ -0,0 +1,273 @@ +package com.baeldung.jhipster5.service; + +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.domain.Authority; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.AuthorityRepository; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.AuthoritiesConstants; +import com.baeldung.jhipster5.security.SecurityUtils; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.service.util.RandomUtil; +import com.baeldung.jhipster5.web.rest.errors.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Service class for managing users. + */ +@Service +@Transactional +public class UserService { + + private final Logger log = LoggerFactory.getLogger(UserService.class); + + private final UserRepository userRepository; + + private final PasswordEncoder passwordEncoder; + + private final AuthorityRepository authorityRepository; + + public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, AuthorityRepository authorityRepository) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + this.authorityRepository = authorityRepository; + } + + public Optional activateRegistration(String key) { + log.debug("Activating user for activation key {}", key); + return userRepository.findOneByActivationKey(key) + .map(user -> { + // activate given user for the registration key. + user.setActivated(true); + user.setActivationKey(null); + log.debug("Activated user: {}", user); + return user; + }); + } + + public Optional completePasswordReset(String newPassword, String key) { + log.debug("Reset user password for reset key {}", key); + return userRepository.findOneByResetKey(key) + .filter(user -> user.getResetDate().isAfter(Instant.now().minusSeconds(86400))) + .map(user -> { + user.setPassword(passwordEncoder.encode(newPassword)); + user.setResetKey(null); + user.setResetDate(null); + return user; + }); + } + + public Optional requestPasswordReset(String mail) { + return userRepository.findOneByEmailIgnoreCase(mail) + .filter(User::getActivated) + .map(user -> { + user.setResetKey(RandomUtil.generateResetKey()); + user.setResetDate(Instant.now()); + return user; + }); + } + + public User registerUser(UserDTO userDTO, String password) { + userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()).ifPresent(existingUser -> { + boolean removed = removeNonActivatedUser(existingUser); + if (!removed) { + throw new LoginAlreadyUsedException(); + } + }); + userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).ifPresent(existingUser -> { + boolean removed = removeNonActivatedUser(existingUser); + if (!removed) { + throw new EmailAlreadyUsedException(); + } + }); + User newUser = new User(); + String encryptedPassword = passwordEncoder.encode(password); + newUser.setLogin(userDTO.getLogin().toLowerCase()); + // new user gets initially a generated password + newUser.setPassword(encryptedPassword); + newUser.setFirstName(userDTO.getFirstName()); + newUser.setLastName(userDTO.getLastName()); + newUser.setEmail(userDTO.getEmail().toLowerCase()); + newUser.setImageUrl(userDTO.getImageUrl()); + newUser.setLangKey(userDTO.getLangKey()); + // new user is not active + newUser.setActivated(false); + // new user gets registration key + newUser.setActivationKey(RandomUtil.generateActivationKey()); + Set authorities = new HashSet<>(); + authorityRepository.findById(AuthoritiesConstants.USER).ifPresent(authorities::add); + newUser.setAuthorities(authorities); + userRepository.save(newUser); + log.debug("Created Information for User: {}", newUser); + return newUser; + } + + private boolean removeNonActivatedUser(User existingUser){ + if (existingUser.getActivated()) { + return false; + } + userRepository.delete(existingUser); + userRepository.flush(); + return true; + } + + public User createUser(UserDTO userDTO) { + User user = new User(); + user.setLogin(userDTO.getLogin().toLowerCase()); + user.setFirstName(userDTO.getFirstName()); + user.setLastName(userDTO.getLastName()); + user.setEmail(userDTO.getEmail().toLowerCase()); + user.setImageUrl(userDTO.getImageUrl()); + if (userDTO.getLangKey() == null) { + user.setLangKey(Constants.DEFAULT_LANGUAGE); // default language + } else { + user.setLangKey(userDTO.getLangKey()); + } + String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword()); + user.setPassword(encryptedPassword); + user.setResetKey(RandomUtil.generateResetKey()); + user.setResetDate(Instant.now()); + user.setActivated(true); + if (userDTO.getAuthorities() != null) { + Set authorities = userDTO.getAuthorities().stream() + .map(authorityRepository::findById) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet()); + user.setAuthorities(authorities); + } + userRepository.save(user); + log.debug("Created Information for User: {}", user); + return user; + } + + /** + * Update basic information (first name, last name, email, language) for the current user. + * + * @param firstName first name of user + * @param lastName last name of user + * @param email email id of user + * @param langKey language key + * @param imageUrl image URL of user + */ + public void updateUser(String firstName, String lastName, String email, String langKey, String imageUrl) { + SecurityUtils.getCurrentUserLogin() + .flatMap(userRepository::findOneByLogin) + .ifPresent(user -> { + user.setFirstName(firstName); + user.setLastName(lastName); + user.setEmail(email.toLowerCase()); + user.setLangKey(langKey); + user.setImageUrl(imageUrl); + log.debug("Changed Information for User: {}", user); + }); + } + + /** + * Update all information for a specific user, and return the modified user. + * + * @param userDTO user to update + * @return updated user + */ + public Optional updateUser(UserDTO userDTO) { + return Optional.of(userRepository + .findById(userDTO.getId())) + .filter(Optional::isPresent) + .map(Optional::get) + .map(user -> { + user.setLogin(userDTO.getLogin().toLowerCase()); + user.setFirstName(userDTO.getFirstName()); + user.setLastName(userDTO.getLastName()); + user.setEmail(userDTO.getEmail().toLowerCase()); + user.setImageUrl(userDTO.getImageUrl()); + user.setActivated(userDTO.isActivated()); + user.setLangKey(userDTO.getLangKey()); + Set managedAuthorities = user.getAuthorities(); + managedAuthorities.clear(); + userDTO.getAuthorities().stream() + .map(authorityRepository::findById) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(managedAuthorities::add); + log.debug("Changed Information for User: {}", user); + return user; + }) + .map(UserDTO::new); + } + + public void deleteUser(String login) { + userRepository.findOneByLogin(login).ifPresent(user -> { + userRepository.delete(user); + log.debug("Deleted User: {}", user); + }); + } + + public void changePassword(String currentClearTextPassword, String newPassword) { + SecurityUtils.getCurrentUserLogin() + .flatMap(userRepository::findOneByLogin) + .ifPresent(user -> { + String currentEncryptedPassword = user.getPassword(); + if (!passwordEncoder.matches(currentClearTextPassword, currentEncryptedPassword)) { + throw new InvalidPasswordException(); + } + String encryptedPassword = passwordEncoder.encode(newPassword); + user.setPassword(encryptedPassword); + log.debug("Changed password for User: {}", user); + }); + } + + @Transactional(readOnly = true) + public Page getAllManagedUsers(Pageable pageable) { + return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER).map(UserDTO::new); + } + + @Transactional(readOnly = true) + public Optional getUserWithAuthoritiesByLogin(String login) { + return userRepository.findOneWithAuthoritiesByLogin(login); + } + + @Transactional(readOnly = true) + public Optional getUserWithAuthorities(Long id) { + return userRepository.findOneWithAuthoritiesById(id); + } + + @Transactional(readOnly = true) + public Optional getUserWithAuthorities() { + return SecurityUtils.getCurrentUserLogin().flatMap(userRepository::findOneWithAuthoritiesByLogin); + } + + /** + * Not activated users should be automatically deleted after 3 days. + *

+ * This is scheduled to get fired everyday, at 01:00 (am). + */ + @Scheduled(cron = "0 0 1 * * ?") + public void removeNotActivatedUsers() { + userRepository + .findAllByActivatedIsFalseAndCreatedDateBefore(Instant.now().minus(3, ChronoUnit.DAYS)) + .forEach(user -> { + log.debug("Deleting not activated user {}", user.getLogin()); + userRepository.delete(user); + }); + } + + /** + * @return a list of all the authorities + */ + public List getAuthorities() { + return authorityRepository.findAll().stream().map(Authority::getName).collect(Collectors.toList()); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/BookDTO.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/BookDTO.java new file mode 100644 index 0000000000..5aa550e989 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/BookDTO.java @@ -0,0 +1,112 @@ +package com.baeldung.jhipster5.service.dto; +import java.time.LocalDate; +import javax.validation.constraints.*; +import java.io.Serializable; +import java.util.Objects; + +/** + * A DTO for the Book entity. + */ +public class BookDTO implements Serializable { + + private Long id; + + @NotNull + private String title; + + @NotNull + private String author; + + @NotNull + private LocalDate published; + + @NotNull + @Min(value = 0) + private Integer quantity; + + @NotNull + @DecimalMin(value = "0") + private Double price; + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public LocalDate getPublished() { + return published; + } + + public void setPublished(LocalDate published) { + this.published = published; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + BookDTO bookDTO = (BookDTO) o; + if (bookDTO.getId() == null || getId() == null) { + return false; + } + return Objects.equals(getId(), bookDTO.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getId()); + } + + @Override + public String toString() { + return "BookDTO{" + + "id=" + getId() + + ", title='" + getTitle() + "'" + + ", author='" + getAuthor() + "'" + + ", published='" + getPublished() + "'" + + ", quantity=" + getQuantity() + + ", price=" + getPrice() + + "}"; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/PasswordChangeDTO.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/PasswordChangeDTO.java new file mode 100644 index 0000000000..0711c97f44 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/PasswordChangeDTO.java @@ -0,0 +1,35 @@ +package com.baeldung.jhipster5.service.dto; + +/** + * A DTO representing a password change required data - current and new password. + */ +public class PasswordChangeDTO { + private String currentPassword; + private String newPassword; + + public PasswordChangeDTO() { + // Empty constructor needed for Jackson. + } + + public PasswordChangeDTO(String currentPassword, String newPassword) { + this.currentPassword = currentPassword; + this.newPassword = newPassword; + } + + public String getCurrentPassword() { + + return currentPassword; + } + + public void setCurrentPassword(String currentPassword) { + this.currentPassword = currentPassword; + } + + public String getNewPassword() { + return newPassword; + } + + public void setNewPassword(String newPassword) { + this.newPassword = newPassword; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/UserDTO.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/UserDTO.java new file mode 100644 index 0000000000..9142b3825e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/UserDTO.java @@ -0,0 +1,199 @@ +package com.baeldung.jhipster5.service.dto; + +import com.baeldung.jhipster5.config.Constants; + +import com.baeldung.jhipster5.domain.Authority; +import com.baeldung.jhipster5.domain.User; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; + +import javax.validation.constraints.*; +import java.time.Instant; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * A DTO representing a user, with his authorities. + */ +public class UserDTO { + + private Long id; + + @NotBlank + @Pattern(regexp = Constants.LOGIN_REGEX) + @Size(min = 1, max = 50) + private String login; + + @Size(max = 50) + private String firstName; + + @Size(max = 50) + private String lastName; + + @Email + @Size(min = 5, max = 254) + private String email; + + @Size(max = 256) + private String imageUrl; + + private boolean activated = false; + + @Size(min = 2, max = 6) + private String langKey; + + private String createdBy; + + private Instant createdDate; + + private String lastModifiedBy; + + private Instant lastModifiedDate; + + private Set authorities; + + public UserDTO() { + // Empty constructor needed for Jackson. + } + + public UserDTO(User user) { + this.id = user.getId(); + this.login = user.getLogin(); + this.firstName = user.getFirstName(); + this.lastName = user.getLastName(); + this.email = user.getEmail(); + this.activated = user.getActivated(); + this.imageUrl = user.getImageUrl(); + this.langKey = user.getLangKey(); + this.createdBy = user.getCreatedBy(); + this.createdDate = user.getCreatedDate(); + this.lastModifiedBy = user.getLastModifiedBy(); + this.lastModifiedDate = user.getLastModifiedDate(); + this.authorities = user.getAuthorities().stream() + .map(Authority::getName) + .collect(Collectors.toSet()); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + public boolean isActivated() { + return activated; + } + + public void setActivated(boolean activated) { + this.activated = activated; + } + + public String getLangKey() { + return langKey; + } + + public void setLangKey(String langKey) { + this.langKey = langKey; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Instant getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Instant createdDate) { + this.createdDate = createdDate; + } + + public String getLastModifiedBy() { + return lastModifiedBy; + } + + public void setLastModifiedBy(String lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + public Instant getLastModifiedDate() { + return lastModifiedDate; + } + + public void setLastModifiedDate(Instant lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public Set getAuthorities() { + return authorities; + } + + public void setAuthorities(Set authorities) { + this.authorities = authorities; + } + + @Override + public String toString() { + return "UserDTO{" + + "login='" + login + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", imageUrl='" + imageUrl + '\'' + + ", activated=" + activated + + ", langKey='" + langKey + '\'' + + ", createdBy=" + createdBy + + ", createdDate=" + createdDate + + ", lastModifiedBy='" + lastModifiedBy + '\'' + + ", lastModifiedDate=" + lastModifiedDate + + ", authorities=" + authorities + + "}"; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/package-info.java new file mode 100644 index 0000000000..87951796ea --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/dto/package-info.java @@ -0,0 +1,4 @@ +/** + * Data Transfer Objects. + */ +package com.baeldung.jhipster5.service.dto; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/impl/BookServiceImpl.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/impl/BookServiceImpl.java new file mode 100644 index 0000000000..23cd59584c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/impl/BookServiceImpl.java @@ -0,0 +1,109 @@ +package com.baeldung.jhipster5.service.impl; + +import com.baeldung.jhipster5.service.BookService; +import com.baeldung.jhipster5.domain.Book; +import com.baeldung.jhipster5.repository.BookRepository; +import com.baeldung.jhipster5.service.dto.BookDTO; +import com.baeldung.jhipster5.service.mapper.BookMapper; +import com.baeldung.jhipster5.web.rest.errors.BadRequestAlertException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Service Implementation for managing Book. + */ +@Service +@Transactional +public class BookServiceImpl implements BookService { + + private final Logger log = LoggerFactory.getLogger(BookServiceImpl.class); + + private final BookRepository bookRepository; + + private final BookMapper bookMapper; + + public BookServiceImpl(BookRepository bookRepository, BookMapper bookMapper) { + this.bookRepository = bookRepository; + this.bookMapper = bookMapper; + } + + /** + * Save a book. + * + * @param bookDTO the entity to save + * @return the persisted entity + */ + @Override + public BookDTO save(BookDTO bookDTO) { + log.debug("Request to save Book : {}", bookDTO); + Book book = bookMapper.toEntity(bookDTO); + book = bookRepository.save(book); + return bookMapper.toDto(book); + } + + /** + * Get all the books. + * + * @return the list of entities + */ + @Override + @Transactional(readOnly = true) + public List findAll() { + log.debug("Request to get all Books"); + return bookRepository.findAll().stream() + .map(bookMapper::toDto) + .collect(Collectors.toCollection(LinkedList::new)); + } + + + /** + * Get one book by id. + * + * @param id the id of the entity + * @return the entity + */ + @Override + @Transactional(readOnly = true) + public Optional findOne(Long id) { + log.debug("Request to get Book : {}", id); + return bookRepository.findById(id) + .map(bookMapper::toDto); + } + + /** + * Delete the book by id. + * + * @param id the id of the entity + */ + @Override + public void delete(Long id) { + log.debug("Request to delete Book : {}", id); + bookRepository.deleteById(id); + } + + @Override + public Optional purchase(Long id) { + Optional bookDTO = findOne(id); + if(bookDTO.isPresent()) { + int quantity = bookDTO.get().getQuantity(); + if(quantity > 0) { + bookDTO.get().setQuantity(quantity - 1); + Book book = bookMapper.toEntity(bookDTO.get()); + book = bookRepository.save(book); + return bookDTO; + } + else { + throw new BadRequestAlertException("Book is not in stock", "book", "notinstock"); + } + } + return Optional.empty(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/BookMapper.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/BookMapper.java new file mode 100644 index 0000000000..cd24c7088e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/BookMapper.java @@ -0,0 +1,24 @@ +package com.baeldung.jhipster5.service.mapper; + +import com.baeldung.jhipster5.domain.*; +import com.baeldung.jhipster5.service.dto.BookDTO; + +import org.mapstruct.*; + +/** + * Mapper for the entity Book and its DTO BookDTO. + */ +@Mapper(componentModel = "spring", uses = {}) +public interface BookMapper extends EntityMapper { + + + + default Book fromId(Long id) { + if (id == null) { + return null; + } + Book book = new Book(); + book.setId(id); + return book; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/EntityMapper.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/EntityMapper.java new file mode 100644 index 0000000000..68af78179d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/EntityMapper.java @@ -0,0 +1,21 @@ +package com.baeldung.jhipster5.service.mapper; + +import java.util.List; + +/** + * Contract for a generic dto to entity mapper. + * + * @param - DTO type parameter. + * @param - Entity type parameter. + */ + +public interface EntityMapper { + + E toEntity(D dto); + + D toDto(E entity); + + List toEntity(List dtoList); + + List toDto(List entityList); +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/UserMapper.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/UserMapper.java new file mode 100644 index 0000000000..485c03813e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/UserMapper.java @@ -0,0 +1,81 @@ +package com.baeldung.jhipster5.service.mapper; + +import com.baeldung.jhipster5.domain.Authority; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.service.dto.UserDTO; + +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Mapper for the entity User and its DTO called UserDTO. + * + * Normal mappers are generated using MapStruct, this one is hand-coded as MapStruct + * support is still in beta, and requires a manual step with an IDE. + */ +@Service +public class UserMapper { + + public List usersToUserDTOs(List users) { + return users.stream() + .filter(Objects::nonNull) + .map(this::userToUserDTO) + .collect(Collectors.toList()); + } + + public UserDTO userToUserDTO(User user) { + return new UserDTO(user); + } + + public List userDTOsToUsers(List userDTOs) { + return userDTOs.stream() + .filter(Objects::nonNull) + .map(this::userDTOToUser) + .collect(Collectors.toList()); + } + + public User userDTOToUser(UserDTO userDTO) { + if (userDTO == null) { + return null; + } else { + User user = new User(); + user.setId(userDTO.getId()); + user.setLogin(userDTO.getLogin()); + user.setFirstName(userDTO.getFirstName()); + user.setLastName(userDTO.getLastName()); + user.setEmail(userDTO.getEmail()); + user.setImageUrl(userDTO.getImageUrl()); + user.setActivated(userDTO.isActivated()); + user.setLangKey(userDTO.getLangKey()); + Set authorities = this.authoritiesFromStrings(userDTO.getAuthorities()); + user.setAuthorities(authorities); + return user; + } + } + + + private Set authoritiesFromStrings(Set authoritiesAsString) { + Set authorities = new HashSet<>(); + + if(authoritiesAsString != null){ + authorities = authoritiesAsString.stream().map(string -> { + Authority auth = new Authority(); + auth.setName(string); + return auth; + }).collect(Collectors.toSet()); + } + + return authorities; + } + + public User userFromId(Long id) { + if (id == null) { + return null; + } + User user = new User(); + user.setId(id); + return user; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/package-info.java new file mode 100644 index 0000000000..7d402321e7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/mapper/package-info.java @@ -0,0 +1,4 @@ +/** + * MapStruct mappers for mapping domain objects and Data Transfer Objects. + */ +package com.baeldung.jhipster5.service.mapper; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/package-info.java new file mode 100644 index 0000000000..a54ed5cca0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/package-info.java @@ -0,0 +1,4 @@ +/** + * Service layer beans. + */ +package com.baeldung.jhipster5.service; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/util/RandomUtil.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/util/RandomUtil.java new file mode 100644 index 0000000000..97e4d9c672 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/service/util/RandomUtil.java @@ -0,0 +1,41 @@ +package com.baeldung.jhipster5.service.util; + +import org.apache.commons.lang3.RandomStringUtils; + +/** + * Utility class for generating random Strings. + */ +public final class RandomUtil { + + private static final int DEF_COUNT = 20; + + private RandomUtil() { + } + + /** + * Generate a password. + * + * @return the generated password + */ + public static String generatePassword() { + return RandomStringUtils.randomAlphanumeric(DEF_COUNT); + } + + /** + * Generate an activation key. + * + * @return the generated activation key + */ + public static String generateActivationKey() { + return RandomStringUtils.randomNumeric(DEF_COUNT); + } + + /** + * Generate a reset key. + * + * @return the generated reset key + */ + public static String generateResetKey() { + return RandomStringUtils.randomNumeric(DEF_COUNT); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AccountResource.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AccountResource.java new file mode 100644 index 0000000000..2109e93999 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AccountResource.java @@ -0,0 +1,179 @@ +package com.baeldung.jhipster5.web.rest; + + +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.SecurityUtils; +import com.baeldung.jhipster5.service.MailService; +import com.baeldung.jhipster5.service.UserService; +import com.baeldung.jhipster5.service.dto.PasswordChangeDTO; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.web.rest.errors.*; +import com.baeldung.jhipster5.web.rest.vm.KeyAndPasswordVM; +import com.baeldung.jhipster5.web.rest.vm.ManagedUserVM; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.*; + +/** + * REST controller for managing the current user's account. + */ +@RestController +@RequestMapping("/api") +public class AccountResource { + + private final Logger log = LoggerFactory.getLogger(AccountResource.class); + + private final UserRepository userRepository; + + private final UserService userService; + + private final MailService mailService; + + public AccountResource(UserRepository userRepository, UserService userService, MailService mailService) { + + this.userRepository = userRepository; + this.userService = userService; + this.mailService = mailService; + } + + /** + * POST /register : register the user. + * + * @param managedUserVM the managed user View Model + * @throws InvalidPasswordException 400 (Bad Request) if the password is incorrect + * @throws EmailAlreadyUsedException 400 (Bad Request) if the email is already used + * @throws LoginAlreadyUsedException 400 (Bad Request) if the login is already used + */ + @PostMapping("/register") + @ResponseStatus(HttpStatus.CREATED) + public void registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) { + if (!checkPasswordLength(managedUserVM.getPassword())) { + throw new InvalidPasswordException(); + } + User user = userService.registerUser(managedUserVM, managedUserVM.getPassword()); + mailService.sendActivationEmail(user); + } + + /** + * GET /activate : activate the registered user. + * + * @param key the activation key + * @throws RuntimeException 500 (Internal Server Error) if the user couldn't be activated + */ + @GetMapping("/activate") + public void activateAccount(@RequestParam(value = "key") String key) { + Optional user = userService.activateRegistration(key); + if (!user.isPresent()) { + throw new InternalServerErrorException("No user was found for this activation key"); + } + } + + /** + * GET /authenticate : check if the user is authenticated, and return its login. + * + * @param request the HTTP request + * @return the login if the user is authenticated + */ + @GetMapping("/authenticate") + public String isAuthenticated(HttpServletRequest request) { + log.debug("REST request to check if the current user is authenticated"); + return request.getRemoteUser(); + } + + /** + * GET /account : get the current user. + * + * @return the current user + * @throws RuntimeException 500 (Internal Server Error) if the user couldn't be returned + */ + @GetMapping("/account") + public UserDTO getAccount() { + return userService.getUserWithAuthorities() + .map(UserDTO::new) + .orElseThrow(() -> new InternalServerErrorException("User could not be found")); + } + + /** + * POST /account : update the current user information. + * + * @param userDTO the current user information + * @throws EmailAlreadyUsedException 400 (Bad Request) if the email is already used + * @throws RuntimeException 500 (Internal Server Error) if the user login wasn't found + */ + @PostMapping("/account") + public void saveAccount(@Valid @RequestBody UserDTO userDTO) { + String userLogin = SecurityUtils.getCurrentUserLogin().orElseThrow(() -> new InternalServerErrorException("Current user login not found")); + Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); + if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) { + throw new EmailAlreadyUsedException(); + } + Optional user = userRepository.findOneByLogin(userLogin); + if (!user.isPresent()) { + throw new InternalServerErrorException("User could not be found"); + } + userService.updateUser(userDTO.getFirstName(), userDTO.getLastName(), userDTO.getEmail(), + userDTO.getLangKey(), userDTO.getImageUrl()); + } + + /** + * POST /account/change-password : changes the current user's password + * + * @param passwordChangeDto current and new password + * @throws InvalidPasswordException 400 (Bad Request) if the new password is incorrect + */ + @PostMapping(path = "/account/change-password") + public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) { + if (!checkPasswordLength(passwordChangeDto.getNewPassword())) { + throw new InvalidPasswordException(); + } + userService.changePassword(passwordChangeDto.getCurrentPassword(), passwordChangeDto.getNewPassword()); + } + + /** + * POST /account/reset-password/init : Send an email to reset the password of the user + * + * @param mail the mail of the user + * @throws EmailNotFoundException 400 (Bad Request) if the email address is not registered + */ + @PostMapping(path = "/account/reset-password/init") + public void requestPasswordReset(@RequestBody String mail) { + mailService.sendPasswordResetMail( + userService.requestPasswordReset(mail) + .orElseThrow(EmailNotFoundException::new) + ); + } + + /** + * POST /account/reset-password/finish : Finish to reset the password of the user + * + * @param keyAndPassword the generated key and the new password + * @throws InvalidPasswordException 400 (Bad Request) if the password is incorrect + * @throws RuntimeException 500 (Internal Server Error) if the password could not be reset + */ + @PostMapping(path = "/account/reset-password/finish") + public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) { + if (!checkPasswordLength(keyAndPassword.getNewPassword())) { + throw new InvalidPasswordException(); + } + Optional user = + userService.completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey()); + + if (!user.isPresent()) { + throw new InternalServerErrorException("No user was found for this reset key"); + } + } + + private static boolean checkPasswordLength(String password) { + return !StringUtils.isEmpty(password) && + password.length() >= ManagedUserVM.PASSWORD_MIN_LENGTH && + password.length() <= ManagedUserVM.PASSWORD_MAX_LENGTH; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AuditResource.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AuditResource.java new file mode 100644 index 0000000000..d0182d5d9d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/AuditResource.java @@ -0,0 +1,77 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.service.AuditEventService; +import com.baeldung.jhipster5.web.rest.util.PaginationUtil; + +import io.github.jhipster.web.util.ResponseUtil; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.List; + +/** + * REST controller for getting the audit events. + */ +@RestController +@RequestMapping("/management/audits") +public class AuditResource { + + private final AuditEventService auditEventService; + + public AuditResource(AuditEventService auditEventService) { + this.auditEventService = auditEventService; + } + + /** + * GET /audits : get a page of AuditEvents. + * + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body + */ + @GetMapping + public ResponseEntity> getAll(Pageable pageable) { + Page page = auditEventService.findAll(pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * GET /audits : get a page of AuditEvents between the fromDate and toDate. + * + * @param fromDate the start of the time period of AuditEvents to get + * @param toDate the end of the time period of AuditEvents to get + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body + */ + @GetMapping(params = {"fromDate", "toDate"}) + public ResponseEntity> getByDates( + @RequestParam(value = "fromDate") LocalDate fromDate, + @RequestParam(value = "toDate") LocalDate toDate, + Pageable pageable) { + + Page page = auditEventService.findByDates( + fromDate.atStartOfDay(ZoneId.systemDefault()).toInstant(), + toDate.atStartOfDay(ZoneId.systemDefault()).plusDays(1).toInstant(), + pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * GET /audits/:id : get an AuditEvent by id. + * + * @param id the id of the entity to get + * @return the ResponseEntity with status 200 (OK) and the AuditEvent in body, or status 404 (Not Found) + */ + @GetMapping("/{id:.+}") + public ResponseEntity get(@PathVariable Long id) { + return ResponseUtil.wrapOrNotFound(auditEventService.find(id)); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/BookResource.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/BookResource.java new file mode 100644 index 0000000000..0360ea05ed --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/BookResource.java @@ -0,0 +1,118 @@ +package com.baeldung.jhipster5.web.rest; +import com.baeldung.jhipster5.service.BookService; +import com.baeldung.jhipster5.web.rest.errors.BadRequestAlertException; +import com.baeldung.jhipster5.web.rest.util.HeaderUtil; +import com.baeldung.jhipster5.service.dto.BookDTO; +import io.github.jhipster.web.util.ResponseUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.List; +import java.util.Optional; + +/** + * REST controller for managing Book. + */ +@RestController +@RequestMapping("/api") +public class BookResource { + + private final Logger log = LoggerFactory.getLogger(BookResource.class); + + private static final String ENTITY_NAME = "book"; + + private final BookService bookService; + + public BookResource(BookService bookService) { + this.bookService = bookService; + } + + /** + * POST /books : Create a new book. + * + * @param bookDTO the bookDTO to create + * @return the ResponseEntity with status 201 (Created) and with body the new bookDTO, or with status 400 (Bad Request) if the book has already an ID + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/books") + public ResponseEntity createBook(@Valid @RequestBody BookDTO bookDTO) throws URISyntaxException { + log.debug("REST request to save Book : {}", bookDTO); + if (bookDTO.getId() != null) { + throw new BadRequestAlertException("A new book cannot already have an ID", ENTITY_NAME, "idexists"); + } + BookDTO result = bookService.save(bookDTO); + return ResponseEntity.created(new URI("/api/books/" + result.getId())) + .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString())) + .body(result); + } + + /** + * PUT /books : Updates an existing book. + * + * @param bookDTO the bookDTO to update + * @return the ResponseEntity with status 200 (OK) and with body the updated bookDTO, + * or with status 400 (Bad Request) if the bookDTO is not valid, + * or with status 500 (Internal Server Error) if the bookDTO couldn't be updated + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PutMapping("/books") + public ResponseEntity updateBook(@Valid @RequestBody BookDTO bookDTO) throws URISyntaxException { + log.debug("REST request to update Book : {}", bookDTO); + if (bookDTO.getId() == null) { + throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); + } + BookDTO result = bookService.save(bookDTO); + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, bookDTO.getId().toString())) + .body(result); + } + + /** + * GET /books : get all the books. + * + * @return the ResponseEntity with status 200 (OK) and the list of books in body + */ + @GetMapping("/books") + public List getAllBooks() { + log.debug("REST request to get all Books"); + return bookService.findAll(); + } + + /** + * GET /books/:id : get the "id" book. + * + * @param id the id of the bookDTO to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the bookDTO, or with status 404 (Not Found) + */ + @GetMapping("/books/{id}") + public ResponseEntity getBook(@PathVariable Long id) { + log.debug("REST request to get Book : {}", id); + Optional bookDTO = bookService.findOne(id); + return ResponseUtil.wrapOrNotFound(bookDTO); + } + + /** + * DELETE /books/:id : delete the "id" book. + * + * @param id the id of the bookDTO to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/books/{id}") + public ResponseEntity deleteBook(@PathVariable Long id) { + log.debug("REST request to delete Book : {}", id); + bookService.delete(id); + return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build(); + } + + @GetMapping("/books/purchase/{id}") + public ResponseEntity purchase(@PathVariable Long id) { + Optional bookDTO = bookService.purchase(id); + return ResponseUtil.wrapOrNotFound(bookDTO); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/LogsResource.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/LogsResource.java new file mode 100644 index 0000000000..f35b5f2d5c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/LogsResource.java @@ -0,0 +1,36 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.web.rest.vm.LoggerVM; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Controller for view and managing Log Level at runtime. + */ +@RestController +@RequestMapping("/management") +public class LogsResource { + + @GetMapping("/logs") + public List getList() { + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + return context.getLoggerList() + .stream() + .map(LoggerVM::new) + .collect(Collectors.toList()); + } + + @PutMapping("/logs") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void changeLevel(@RequestBody LoggerVM jsonLogger) { + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel())); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserJWTController.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserJWTController.java new file mode 100644 index 0000000000..aeea587089 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserJWTController.java @@ -0,0 +1,71 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.security.jwt.JWTFilter; +import com.baeldung.jhipster5.security.jwt.TokenProvider; +import com.baeldung.jhipster5.web.rest.vm.LoginVM; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * Controller to authenticate users. + */ +@RestController +@RequestMapping("/api") +public class UserJWTController { + + private final TokenProvider tokenProvider; + + private final AuthenticationManager authenticationManager; + + public UserJWTController(TokenProvider tokenProvider, AuthenticationManager authenticationManager) { + this.tokenProvider = tokenProvider; + this.authenticationManager = authenticationManager; + } + + @PostMapping("/authenticate") + public ResponseEntity authorize(@Valid @RequestBody LoginVM loginVM) { + + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword()); + + Authentication authentication = this.authenticationManager.authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + boolean rememberMe = (loginVM.isRememberMe() == null) ? false : loginVM.isRememberMe(); + String jwt = tokenProvider.createToken(authentication, rememberMe); + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + return new ResponseEntity<>(new JWTToken(jwt), httpHeaders, HttpStatus.OK); + } + + /** + * Object to return as body in JWT Authentication. + */ + static class JWTToken { + + private String idToken; + + JWTToken(String idToken) { + this.idToken = idToken; + } + + @JsonProperty("id_token") + String getIdToken() { + return idToken; + } + + void setIdToken(String idToken) { + this.idToken = idToken; + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserResource.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserResource.java new file mode 100644 index 0000000000..a95acf6759 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/UserResource.java @@ -0,0 +1,183 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.AuthoritiesConstants; +import com.baeldung.jhipster5.service.MailService; +import com.baeldung.jhipster5.service.UserService; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.web.rest.errors.BadRequestAlertException; +import com.baeldung.jhipster5.web.rest.errors.EmailAlreadyUsedException; +import com.baeldung.jhipster5.web.rest.errors.LoginAlreadyUsedException; +import com.baeldung.jhipster5.web.rest.util.HeaderUtil; +import com.baeldung.jhipster5.web.rest.util.PaginationUtil; +import io.github.jhipster.web.util.ResponseUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; + +/** + * REST controller for managing users. + *

+ * This class accesses the User entity, and needs to fetch its collection of authorities. + *

+ * For a normal use-case, it would be better to have an eager relationship between User and Authority, + * and send everything to the client side: there would be no View Model and DTO, a lot less code, and an outer-join + * which would be good for performance. + *

+ * We use a View Model and a DTO for 3 reasons: + *

    + *
  • We want to keep a lazy association between the user and the authorities, because people will + * quite often do relationships with the user, and we don't want them to get the authorities all + * the time for nothing (for performance reasons). This is the #1 goal: we should not impact our users' + * application because of this use-case.
  • + *
  • Not having an outer join causes n+1 requests to the database. This is not a real issue as + * we have by default a second-level cache. This means on the first HTTP call we do the n+1 requests, + * but then all authorities come from the cache, so in fact it's much better than doing an outer join + * (which will get lots of data from the database, for each HTTP call).
  • + *
  • As this manages users, for security reasons, we'd rather have a DTO layer.
  • + *
+ *

+ * Another option would be to have a specific JPA entity graph to handle this case. + */ +@RestController +@RequestMapping("/api") +public class UserResource { + + private final Logger log = LoggerFactory.getLogger(UserResource.class); + + private final UserService userService; + + private final UserRepository userRepository; + + private final MailService mailService; + + public UserResource(UserService userService, UserRepository userRepository, MailService mailService) { + + this.userService = userService; + this.userRepository = userRepository; + this.mailService = mailService; + } + + /** + * POST /users : Creates a new user. + *

+ * Creates a new user if the login and email are not already used, and sends an + * mail with an activation link. + * The user needs to be activated on creation. + * + * @param userDTO the user to create + * @return the ResponseEntity with status 201 (Created) and with body the new user, or with status 400 (Bad Request) if the login or email is already in use + * @throws URISyntaxException if the Location URI syntax is incorrect + * @throws BadRequestAlertException 400 (Bad Request) if the login or email is already in use + */ + @PostMapping("/users") + @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + public ResponseEntity createUser(@Valid @RequestBody UserDTO userDTO) throws URISyntaxException { + log.debug("REST request to save User : {}", userDTO); + + if (userDTO.getId() != null) { + throw new BadRequestAlertException("A new user cannot already have an ID", "userManagement", "idexists"); + // Lowercase the user login before comparing with database + } else if (userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()).isPresent()) { + throw new LoginAlreadyUsedException(); + } else if (userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).isPresent()) { + throw new EmailAlreadyUsedException(); + } else { + User newUser = userService.createUser(userDTO); + mailService.sendCreationEmail(newUser); + return ResponseEntity.created(new URI("/api/users/" + newUser.getLogin())) + .headers(HeaderUtil.createAlert( "A user is created with identifier " + newUser.getLogin(), newUser.getLogin())) + .body(newUser); + } + } + + /** + * PUT /users : Updates an existing User. + * + * @param userDTO the user to update + * @return the ResponseEntity with status 200 (OK) and with body the updated user + * @throws EmailAlreadyUsedException 400 (Bad Request) if the email is already in use + * @throws LoginAlreadyUsedException 400 (Bad Request) if the login is already in use + */ + @PutMapping("/users") + @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + public ResponseEntity updateUser(@Valid @RequestBody UserDTO userDTO) { + log.debug("REST request to update User : {}", userDTO); + Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); + if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) { + throw new EmailAlreadyUsedException(); + } + existingUser = userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()); + if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) { + throw new LoginAlreadyUsedException(); + } + Optional updatedUser = userService.updateUser(userDTO); + + return ResponseUtil.wrapOrNotFound(updatedUser, + HeaderUtil.createAlert("A user is updated with identifier " + userDTO.getLogin(), userDTO.getLogin())); + } + + /** + * GET /users : get all users. + * + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and with body all users + */ + @GetMapping("/users") + public ResponseEntity> getAllUsers(Pageable pageable) { + final Page page = userService.getAllManagedUsers(pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/users"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * @return a string list of the all of the roles + */ + @GetMapping("/users/authorities") + @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + public List getAuthorities() { + return userService.getAuthorities(); + } + + /** + * GET /users/:login : get the "login" user. + * + * @param login the login of the user to find + * @return the ResponseEntity with status 200 (OK) and with body the "login" user, or with status 404 (Not Found) + */ + @GetMapping("/users/{login:" + Constants.LOGIN_REGEX + "}") + public ResponseEntity getUser(@PathVariable String login) { + log.debug("REST request to get User : {}", login); + return ResponseUtil.wrapOrNotFound( + userService.getUserWithAuthoritiesByLogin(login) + .map(UserDTO::new)); + } + + /** + * DELETE /users/:login : delete the "login" User. + * + * @param login the login of the user to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/users/{login:" + Constants.LOGIN_REGEX + "}") + @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + public ResponseEntity deleteUser(@PathVariable String login) { + log.debug("REST request to delete User: {}", login); + userService.deleteUser(login); + return ResponseEntity.ok().headers(HeaderUtil.createAlert( "A user is deleted with identifier " + login, login)).build(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/BadRequestAlertException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/BadRequestAlertException.java new file mode 100644 index 0000000000..c4c403351a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/BadRequestAlertException.java @@ -0,0 +1,42 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +public class BadRequestAlertException extends AbstractThrowableProblem { + + private static final long serialVersionUID = 1L; + + private final String entityName; + + private final String errorKey; + + public BadRequestAlertException(String defaultMessage, String entityName, String errorKey) { + this(ErrorConstants.DEFAULT_TYPE, defaultMessage, entityName, errorKey); + } + + public BadRequestAlertException(URI type, String defaultMessage, String entityName, String errorKey) { + super(type, defaultMessage, Status.BAD_REQUEST, null, null, null, getAlertParameters(entityName, errorKey)); + this.entityName = entityName; + this.errorKey = errorKey; + } + + public String getEntityName() { + return entityName; + } + + public String getErrorKey() { + return errorKey; + } + + private static Map getAlertParameters(String entityName, String errorKey) { + Map parameters = new HashMap<>(); + parameters.put("message", "error." + errorKey); + parameters.put("params", entityName); + return parameters; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/CustomParameterizedException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/CustomParameterizedException.java new file mode 100644 index 0000000000..8c3df82b83 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/CustomParameterizedException.java @@ -0,0 +1,54 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.zalando.problem.AbstractThrowableProblem; + +import java.util.HashMap; +import java.util.Map; + +import static org.zalando.problem.Status.BAD_REQUEST; + +/** + * Custom, parameterized exception, which can be translated on the client side. + * For example: + * + *

+ * throw new CustomParameterizedException("myCustomError", "hello", "world");
+ * 
+ * + * Can be translated with: + * + *
+ * "error.myCustomError" :  "The server says {{param0}} to {{param1}}"
+ * 
+ */ +public class CustomParameterizedException extends AbstractThrowableProblem { + + private static final long serialVersionUID = 1L; + + private static final String PARAM = "param"; + + public CustomParameterizedException(String message, String... params) { + this(message, toParamMap(params)); + } + + public CustomParameterizedException(String message, Map paramMap) { + super(ErrorConstants.PARAMETERIZED_TYPE, "Parameterized Exception", BAD_REQUEST, null, null, null, toProblemParameters(message, paramMap)); + } + + public static Map toParamMap(String... params) { + Map paramMap = new HashMap<>(); + if (params != null && params.length > 0) { + for (int i = 0; i < params.length; i++) { + paramMap.put(PARAM + i, params[i]); + } + } + return paramMap; + } + + public static Map toProblemParameters(String message, Map paramMap) { + Map parameters = new HashMap<>(); + parameters.put("message", message); + parameters.put("params", paramMap); + return parameters; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailAlreadyUsedException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailAlreadyUsedException.java new file mode 100644 index 0000000000..b3dcc0279e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailAlreadyUsedException.java @@ -0,0 +1,10 @@ +package com.baeldung.jhipster5.web.rest.errors; + +public class EmailAlreadyUsedException extends BadRequestAlertException { + + private static final long serialVersionUID = 1L; + + public EmailAlreadyUsedException() { + super(ErrorConstants.EMAIL_ALREADY_USED_TYPE, "Email is already in use!", "userManagement", "emailexists"); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailNotFoundException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailNotFoundException.java new file mode 100644 index 0000000000..b93081cacb --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/EmailNotFoundException.java @@ -0,0 +1,13 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; + +public class EmailNotFoundException extends AbstractThrowableProblem { + + private static final long serialVersionUID = 1L; + + public EmailNotFoundException() { + super(ErrorConstants.EMAIL_NOT_FOUND_TYPE, "Email address not registered", Status.BAD_REQUEST); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ErrorConstants.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ErrorConstants.java new file mode 100644 index 0000000000..06be9254a9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ErrorConstants.java @@ -0,0 +1,21 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import java.net.URI; + +public final class ErrorConstants { + + public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure"; + public static final String ERR_VALIDATION = "error.validation"; + public static final String PROBLEM_BASE_URL = "https://www.jhipster.tech/problem"; + public static final URI DEFAULT_TYPE = URI.create(PROBLEM_BASE_URL + "/problem-with-message"); + public static final URI CONSTRAINT_VIOLATION_TYPE = URI.create(PROBLEM_BASE_URL + "/constraint-violation"); + public static final URI PARAMETERIZED_TYPE = URI.create(PROBLEM_BASE_URL + "/parameterized"); + public static final URI ENTITY_NOT_FOUND_TYPE = URI.create(PROBLEM_BASE_URL + "/entity-not-found"); + public static final URI INVALID_PASSWORD_TYPE = URI.create(PROBLEM_BASE_URL + "/invalid-password"); + public static final URI EMAIL_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/email-already-used"); + public static final URI LOGIN_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/login-already-used"); + public static final URI EMAIL_NOT_FOUND_TYPE = URI.create(PROBLEM_BASE_URL + "/email-not-found"); + + private ErrorConstants() { + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslator.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslator.java new file mode 100644 index 0000000000..3f7cc6b565 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslator.java @@ -0,0 +1,112 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import com.baeldung.jhipster5.web.rest.util.HeaderUtil; + +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.NativeWebRequest; +import org.zalando.problem.DefaultProblem; +import org.zalando.problem.Problem; +import org.zalando.problem.ProblemBuilder; +import org.zalando.problem.Status; +import org.zalando.problem.spring.web.advice.ProblemHandling; +import org.zalando.problem.violations.ConstraintViolationProblem; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +/** + * Controller advice to translate the server side exceptions to client-friendly json structures. + * The error response follows RFC7807 - Problem Details for HTTP APIs (https://tools.ietf.org/html/rfc7807) + */ +@ControllerAdvice +public class ExceptionTranslator implements ProblemHandling { + + private static final String FIELD_ERRORS_KEY = "fieldErrors"; + private static final String MESSAGE_KEY = "message"; + private static final String PATH_KEY = "path"; + private static final String VIOLATIONS_KEY = "violations"; + + /** + * Post-process the Problem payload to add the message key for the front-end if needed + */ + @Override + public ResponseEntity process(@Nullable ResponseEntity entity, NativeWebRequest request) { + if (entity == null) { + return entity; + } + Problem problem = entity.getBody(); + if (!(problem instanceof ConstraintViolationProblem || problem instanceof DefaultProblem)) { + return entity; + } + ProblemBuilder builder = Problem.builder() + .withType(Problem.DEFAULT_TYPE.equals(problem.getType()) ? ErrorConstants.DEFAULT_TYPE : problem.getType()) + .withStatus(problem.getStatus()) + .withTitle(problem.getTitle()) + .with(PATH_KEY, request.getNativeRequest(HttpServletRequest.class).getRequestURI()); + + if (problem instanceof ConstraintViolationProblem) { + builder + .with(VIOLATIONS_KEY, ((ConstraintViolationProblem) problem).getViolations()) + .with(MESSAGE_KEY, ErrorConstants.ERR_VALIDATION); + } else { + builder + .withCause(((DefaultProblem) problem).getCause()) + .withDetail(problem.getDetail()) + .withInstance(problem.getInstance()); + problem.getParameters().forEach(builder::with); + if (!problem.getParameters().containsKey(MESSAGE_KEY) && problem.getStatus() != null) { + builder.with(MESSAGE_KEY, "error.http." + problem.getStatus().getStatusCode()); + } + } + return new ResponseEntity<>(builder.build(), entity.getHeaders(), entity.getStatusCode()); + } + + @Override + public ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, @Nonnull NativeWebRequest request) { + BindingResult result = ex.getBindingResult(); + List fieldErrors = result.getFieldErrors().stream() + .map(f -> new FieldErrorVM(f.getObjectName(), f.getField(), f.getCode())) + .collect(Collectors.toList()); + + Problem problem = Problem.builder() + .withType(ErrorConstants.CONSTRAINT_VIOLATION_TYPE) + .withTitle("Method argument not valid") + .withStatus(defaultConstraintViolationStatus()) + .with(MESSAGE_KEY, ErrorConstants.ERR_VALIDATION) + .with(FIELD_ERRORS_KEY, fieldErrors) + .build(); + return create(ex, problem, request); + } + + @ExceptionHandler + public ResponseEntity handleNoSuchElementException(NoSuchElementException ex, NativeWebRequest request) { + Problem problem = Problem.builder() + .withStatus(Status.NOT_FOUND) + .with(MESSAGE_KEY, ErrorConstants.ENTITY_NOT_FOUND_TYPE) + .build(); + return create(ex, problem, request); + } + + @ExceptionHandler + public ResponseEntity handleBadRequestAlertException(BadRequestAlertException ex, NativeWebRequest request) { + return create(ex, request, HeaderUtil.createFailureAlert(ex.getEntityName(), ex.getErrorKey(), ex.getMessage())); + } + + @ExceptionHandler + public ResponseEntity handleConcurrencyFailure(ConcurrencyFailureException ex, NativeWebRequest request) { + Problem problem = Problem.builder() + .withStatus(Status.CONFLICT) + .with(MESSAGE_KEY, ErrorConstants.ERR_CONCURRENCY_FAILURE) + .build(); + return create(ex, problem, request); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/FieldErrorVM.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/FieldErrorVM.java new file mode 100644 index 0000000000..349f548850 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/FieldErrorVM.java @@ -0,0 +1,33 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import java.io.Serializable; + +public class FieldErrorVM implements Serializable { + + private static final long serialVersionUID = 1L; + + private final String objectName; + + private final String field; + + private final String message; + + public FieldErrorVM(String dto, String field, String message) { + this.objectName = dto; + this.field = field; + this.message = message; + } + + public String getObjectName() { + return objectName; + } + + public String getField() { + return field; + } + + public String getMessage() { + return message; + } + +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InternalServerErrorException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InternalServerErrorException.java new file mode 100644 index 0000000000..13e128237b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InternalServerErrorException.java @@ -0,0 +1,16 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; + +/** + * Simple exception with a message, that returns an Internal Server Error code. + */ +public class InternalServerErrorException extends AbstractThrowableProblem { + + private static final long serialVersionUID = 1L; + + public InternalServerErrorException(String message) { + super(ErrorConstants.DEFAULT_TYPE, message, Status.INTERNAL_SERVER_ERROR); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InvalidPasswordException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InvalidPasswordException.java new file mode 100644 index 0000000000..6bb91247ff --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/InvalidPasswordException.java @@ -0,0 +1,13 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; + +public class InvalidPasswordException extends AbstractThrowableProblem { + + private static final long serialVersionUID = 1L; + + public InvalidPasswordException() { + super(ErrorConstants.INVALID_PASSWORD_TYPE, "Incorrect password", Status.BAD_REQUEST); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/LoginAlreadyUsedException.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/LoginAlreadyUsedException.java new file mode 100644 index 0000000000..987a94193d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/LoginAlreadyUsedException.java @@ -0,0 +1,10 @@ +package com.baeldung.jhipster5.web.rest.errors; + +public class LoginAlreadyUsedException extends BadRequestAlertException { + + private static final long serialVersionUID = 1L; + + public LoginAlreadyUsedException() { + super(ErrorConstants.LOGIN_ALREADY_USED_TYPE, "Login name already used!", "userManagement", "userexists"); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/package-info.java new file mode 100644 index 0000000000..7f57af4429 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/errors/package-info.java @@ -0,0 +1,6 @@ +/** + * Specific errors used with Zalando's "problem-spring-web" library. + * + * More information on https://github.com/zalando/problem-spring-web + */ +package com.baeldung.jhipster5.web.rest.errors; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/package-info.java new file mode 100644 index 0000000000..75bf6840f6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring MVC REST controllers. + */ +package com.baeldung.jhipster5.web.rest; diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/HeaderUtil.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/HeaderUtil.java new file mode 100644 index 0000000000..91fdd68261 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/HeaderUtil.java @@ -0,0 +1,45 @@ +package com.baeldung.jhipster5.web.rest.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; + +/** + * Utility class for HTTP headers creation. + */ +public final class HeaderUtil { + + private static final Logger log = LoggerFactory.getLogger(HeaderUtil.class); + + private static final String APPLICATION_NAME = "bookstoreApp"; + + private HeaderUtil() { + } + + public static HttpHeaders createAlert(String message, String param) { + HttpHeaders headers = new HttpHeaders(); + headers.add("X-" + APPLICATION_NAME + "-alert", message); + headers.add("X-" + APPLICATION_NAME + "-params", param); + return headers; + } + + public static HttpHeaders createEntityCreationAlert(String entityName, String param) { + return createAlert("A new " + entityName + " is created with identifier " + param, param); + } + + public static HttpHeaders createEntityUpdateAlert(String entityName, String param) { + return createAlert("A " + entityName + " is updated with identifier " + param, param); + } + + public static HttpHeaders createEntityDeletionAlert(String entityName, String param) { + return createAlert("A " + entityName + " is deleted with identifier " + param, param); + } + + public static HttpHeaders createFailureAlert(String entityName, String errorKey, String defaultMessage) { + log.error("Entity processing failed, {}", defaultMessage); + HttpHeaders headers = new HttpHeaders(); + headers.add("X-" + APPLICATION_NAME + "-error", defaultMessage); + headers.add("X-" + APPLICATION_NAME + "-params", entityName); + return headers; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/PaginationUtil.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/PaginationUtil.java new file mode 100644 index 0000000000..9928dbe171 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/util/PaginationUtil.java @@ -0,0 +1,45 @@ +package com.baeldung.jhipster5.web.rest.util; + +import org.springframework.data.domain.Page; +import org.springframework.http.HttpHeaders; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * Utility class for handling pagination. + * + *

+ * Pagination uses the same principles as the GitHub API, + * and follow RFC 5988 (Link header). + */ +public final class PaginationUtil { + + private PaginationUtil() { + } + + public static HttpHeaders generatePaginationHttpHeaders(Page page, String baseUrl) { + + HttpHeaders headers = new HttpHeaders(); + headers.add("X-Total-Count", Long.toString(page.getTotalElements())); + String link = ""; + if ((page.getNumber() + 1) < page.getTotalPages()) { + link = "<" + generateUri(baseUrl, page.getNumber() + 1, page.getSize()) + ">; rel=\"next\","; + } + // prev link + if ((page.getNumber()) > 0) { + link += "<" + generateUri(baseUrl, page.getNumber() - 1, page.getSize()) + ">; rel=\"prev\","; + } + // last and first link + int lastPage = 0; + if (page.getTotalPages() > 0) { + lastPage = page.getTotalPages() - 1; + } + link += "<" + generateUri(baseUrl, lastPage, page.getSize()) + ">; rel=\"last\","; + link += "<" + generateUri(baseUrl, 0, page.getSize()) + ">; rel=\"first\""; + headers.add(HttpHeaders.LINK, link); + return headers; + } + + private static String generateUri(String baseUrl, int page, int size) { + return UriComponentsBuilder.fromUriString(baseUrl).queryParam("page", page).queryParam("size", size).toUriString(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/KeyAndPasswordVM.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/KeyAndPasswordVM.java new file mode 100644 index 0000000000..840fa02cfc --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/KeyAndPasswordVM.java @@ -0,0 +1,27 @@ +package com.baeldung.jhipster5.web.rest.vm; + +/** + * View Model object for storing the user's key and password. + */ +public class KeyAndPasswordVM { + + private String key; + + private String newPassword; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getNewPassword() { + return newPassword; + } + + public void setNewPassword(String newPassword) { + this.newPassword = newPassword; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoggerVM.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoggerVM.java new file mode 100644 index 0000000000..952e7df298 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoggerVM.java @@ -0,0 +1,46 @@ +package com.baeldung.jhipster5.web.rest.vm; + +import ch.qos.logback.classic.Logger; + +/** + * View Model object for storing a Logback logger. + */ +public class LoggerVM { + + private String name; + + private String level; + + public LoggerVM(Logger logger) { + this.name = logger.getName(); + this.level = logger.getEffectiveLevel().toString(); + } + + public LoggerVM() { + // Empty public constructor used by Jackson. + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + @Override + public String toString() { + return "LoggerVM{" + + "name='" + name + '\'' + + ", level='" + level + '\'' + + '}'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoginVM.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoginVM.java new file mode 100644 index 0000000000..8fc119ab69 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/LoginVM.java @@ -0,0 +1,52 @@ +package com.baeldung.jhipster5.web.rest.vm; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * View Model object for storing a user's credentials. + */ +public class LoginVM { + + @NotNull + @Size(min = 1, max = 50) + private String username; + + @NotNull + @Size(min = ManagedUserVM.PASSWORD_MIN_LENGTH, max = ManagedUserVM.PASSWORD_MAX_LENGTH) + private String password; + + private Boolean rememberMe; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Boolean isRememberMe() { + return rememberMe; + } + + public void setRememberMe(Boolean rememberMe) { + this.rememberMe = rememberMe; + } + + @Override + public String toString() { + return "LoginVM{" + + "username='" + username + '\'' + + ", rememberMe=" + rememberMe + + '}'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/ManagedUserVM.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/ManagedUserVM.java new file mode 100644 index 0000000000..314577c456 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/ManagedUserVM.java @@ -0,0 +1,35 @@ +package com.baeldung.jhipster5.web.rest.vm; + +import com.baeldung.jhipster5.service.dto.UserDTO; +import javax.validation.constraints.Size; + +/** + * View Model extending the UserDTO, which is meant to be used in the user management UI. + */ +public class ManagedUserVM extends UserDTO { + + public static final int PASSWORD_MIN_LENGTH = 4; + + public static final int PASSWORD_MAX_LENGTH = 100; + + @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH) + private String password; + + public ManagedUserVM() { + // Empty constructor needed for Jackson. + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public String toString() { + return "ManagedUserVM{" + + "} " + super.toString(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/package-info.java b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/package-info.java new file mode 100644 index 0000000000..ff58799037 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/java/com/baeldung/jhipster5/web/rest/vm/package-info.java @@ -0,0 +1,4 @@ +/** + * View Models used by Spring MVC REST controllers. + */ +package com.baeldung.jhipster5.web.rest.vm; diff --git a/jhipster-5/bookstore-monolith/src/main/jib/entrypoint.sh b/jhipster-5/bookstore-monolith/src/main/jib/entrypoint.sh new file mode 100644 index 0000000000..b3c4541011 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/jib/entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "The application will start in ${JHIPSTER_SLEEP}s..." && sleep ${JHIPSTER_SLEEP} +exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -cp /app/resources/:/app/classes/:/app/libs/* "com.baeldung.jhipster5.BookstoreApp" "$@" diff --git a/jhipster-5/bookstore-monolith/src/main/resources/.h2.server.properties b/jhipster-5/bookstore-monolith/src/main/resources/.h2.server.properties new file mode 100644 index 0000000000..99767b3a8a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/.h2.server.properties @@ -0,0 +1,5 @@ +#H2 Server Properties +0=JHipster H2 (Memory)|org.h2.Driver|jdbc\:h2\:mem\:bookstore|Bookstore +webAllowOthers=true +webPort=8082 +webSSL=false diff --git a/jhipster-5/bookstore-monolith/src/main/resources/banner.txt b/jhipster-5/bookstore-monolith/src/main/resources/banner.txt new file mode 100644 index 0000000000..e0bc55aaff --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/banner.txt @@ -0,0 +1,10 @@ + + ${AnsiColor.GREEN} ██╗${AnsiColor.RED} ██╗ ██╗ ████████╗ ███████╗ ██████╗ ████████╗ ████████╗ ███████╗ + ${AnsiColor.GREEN} ██║${AnsiColor.RED} ██║ ██║ ╚══██╔══╝ ██╔═══██╗ ██╔════╝ ╚══██╔══╝ ██╔═════╝ ██╔═══██╗ + ${AnsiColor.GREEN} ██║${AnsiColor.RED} ████████║ ██║ ███████╔╝ ╚█████╗ ██║ ██████╗ ███████╔╝ + ${AnsiColor.GREEN}██╗ ██║${AnsiColor.RED} ██╔═══██║ ██║ ██╔════╝ ╚═══██╗ ██║ ██╔═══╝ ██╔══██║ + ${AnsiColor.GREEN}╚██████╔╝${AnsiColor.RED} ██║ ██║ ████████╗ ██║ ██████╔╝ ██║ ████████╗ ██║ ╚██╗ + ${AnsiColor.GREEN} ╚═════╝ ${AnsiColor.RED} ╚═╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═╝ + +${AnsiColor.BRIGHT_BLUE}:: JHipster 🤓 :: Running Spring Boot ${spring-boot.version} :: +:: https://www.jhipster.tech ::${AnsiColor.DEFAULT} diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/application-dev.yml b/jhipster-5/bookstore-monolith/src/main/resources/config/application-dev.yml new file mode 100644 index 0000000000..64742feb45 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/application-dev.yml @@ -0,0 +1,122 @@ +# =================================================================== +# Spring Boot configuration for the "dev" profile. +# +# This configuration overrides the application.yml file. +# +# More information on profiles: https://www.jhipster.tech/profiles/ +# More information on configuration properties: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + +logging: + level: + ROOT: DEBUG + io.github.jhipster: DEBUG + com.baeldung.jhipster5: DEBUG + +spring: + profiles: + active: dev + include: + - swagger + # Uncomment to activate TLS for the dev profile + #- tls + devtools: + restart: + enabled: true + additional-exclude: .h2.server.properties + livereload: + enabled: false # we use Webpack dev server + BrowserSync for livereload + jackson: + serialization: + indent-output: true + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:h2:mem:bookstore;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + username: Bookstore + password: + hikari: + poolName: Hikari + auto-commit: false + h2: + console: + enabled: false + jpa: + database-platform: io.github.jhipster.domain.util.FixedH2Dialect + database: H2 + show-sql: true + properties: + hibernate.id.new_generator_mappings: true + hibernate.connection.provider_disables_autocommit: true + hibernate.cache.use_second_level_cache: false + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: true + liquibase: + contexts: dev + mail: + host: localhost + port: 25 + username: + password: + messages: + cache-duration: PT1S # 1 second, see the ISO 8601 standard + thymeleaf: + cache: false + +server: + port: 8080 + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +jhipster: + http: + version: V_1_1 # To use HTTP/2 you will need to activate TLS (see application-tls.yml) + # CORS is only enabled by default with the "dev" profile, so BrowserSync can access the API + cors: + allowed-origins: "*" + allowed-methods: "*" + allowed-headers: "*" + exposed-headers: "Authorization,Link,X-Total-Count" + allow-credentials: true + max-age: 1800 + security: + authentication: + jwt: + # This token must be encoded using Base64 and be at least 256 bits long (you can type `openssl rand -base64 64` on your command line to generate a 512 bits one) + base64-secret: NDJmOTVlZjI2NzhlZDRjNmVkNTM1NDE2NjkyNDljZDJiNzBlMjI5YmZjMjY3MzdjZmZlMjI3NjE4OTRkNzc5MWYzNDNlYWMzYmJjOWRmMjc5ZWQyZTZmOWZkOTMxZWZhNWE1MTVmM2U2NjFmYjhlNDc2Y2Q3NzliMGY0YzFkNmI= + # Token is valid 24 hours + token-validity-in-seconds: 86400 + token-validity-in-seconds-for-remember-me: 2592000 + mail: # specific JHipster mail property, for standard properties see MailProperties + from: Bookstore@localhost + base-url: http://127.0.0.1:8080 + metrics: + logs: # Reports metrics in the logs + enabled: false + report-frequency: 60 # in seconds + logging: + logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration + enabled: false + host: localhost + port: 5000 + queue-size: 512 + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# application: diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/application-prod.yml b/jhipster-5/bookstore-monolith/src/main/resources/config/application-prod.yml new file mode 100644 index 0000000000..d698099fac --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/application-prod.yml @@ -0,0 +1,133 @@ +# =================================================================== +# Spring Boot configuration for the "prod" profile. +# +# This configuration overrides the application.yml file. +# +# More information on profiles: https://www.jhipster.tech/profiles/ +# More information on configuration properties: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + +logging: + level: + ROOT: INFO + com.baeldung.jhipster5: INFO + io.github.jhipster: INFO + +spring: + devtools: + restart: + enabled: false + livereload: + enabled: false + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:mysql://localhost:3306/Bookstore?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC + username: root + password: + hikari: + poolName: Hikari + auto-commit: false + data-source-properties: + cachePrepStmts: true + prepStmtCacheSize: 250 + prepStmtCacheSqlLimit: 2048 + useServerPrepStmts: true + jpa: + database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + database: MYSQL + show-sql: false + properties: + hibernate.id.new_generator_mappings: true + hibernate.connection.provider_disables_autocommit: true + hibernate.cache.use_second_level_cache: false + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: true + liquibase: + contexts: prod + mail: + host: localhost + port: 25 + username: + password: + thymeleaf: + cache: true + +# =================================================================== +# To enable TLS in production, generate a certificate using: +# keytool -genkey -alias bookstore -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650 +# +# You can also use Let's Encrypt: +# https://maximilian-boehm.com/hp2121/Create-a-Java-Keystore-JKS-from-Let-s-Encrypt-Certificates.htm +# +# Then, modify the server.ssl properties so your "server" configuration looks like: +# +# server: +# port: 443 +# ssl: +# key-store: classpath:config/tls/keystore.p12 +# key-store-password: password +# key-store-type: PKCS12 +# key-alias: bookstore +# # The ciphers suite enforce the security by deactivating some old and deprecated SSL cipher, this list was tested against SSL Labs (https://www.ssllabs.com/ssltest/) +# ciphers: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,TLS_RSA_WITH_CAMELLIA_128_CBC_SHA +# =================================================================== +server: + port: 8080 + compression: + enabled: true + mime-types: text/html,text/xml,text/plain,text/css, application/javascript, application/json + min-response-size: 1024 + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +jhipster: + http: + version: V_1_1 # To use HTTP/2 you will need SSL support (see above the "server.ssl" configuration) + cache: # Used by the CachingHttpHeadersFilter + timeToLiveInDays: 1461 + security: + authentication: + jwt: + # This token must be encoded using Base64 and be at least 256 bits long (you can type `openssl rand -base64 64` on your command line to generate a 512 bits one) + # As this is the PRODUCTION configuration, you MUST change the default key, and store it securely: + # - In the JHipster Registry (which includes a Spring Cloud Config server) + # - In a separate `application-prod.yml` file, in the same folder as your executable WAR file + # - In the `JHIPSTER_SECURITY_AUTHENTICATION_JWT_BASE64_SECRET` environment variable + base64-secret: NDJmOTVlZjI2NzhlZDRjNmVkNTM1NDE2NjkyNDljZDJiNzBlMjI5YmZjMjY3MzdjZmZlMjI3NjE4OTRkNzc5MWYzNDNlYWMzYmJjOWRmMjc5ZWQyZTZmOWZkOTMxZWZhNWE1MTVmM2U2NjFmYjhlNDc2Y2Q3NzliMGY0YzFkNmI= + # Token is valid 24 hours + token-validity-in-seconds: 86400 + token-validity-in-seconds-for-remember-me: 2592000 + mail: # specific JHipster mail property, for standard properties see MailProperties + from: Bookstore@localhost + base-url: http://my-server-url-to-change # Modify according to your server's URL + metrics: + logs: # Reports metrics in the logs + enabled: false + report-frequency: 60 # in seconds + logging: + logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration + enabled: false + host: localhost + port: 5000 + queue-size: 512 + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# application: diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/application-tls.yml b/jhipster-5/bookstore-monolith/src/main/resources/config/application-tls.yml new file mode 100644 index 0000000000..c4e0565cc7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/application-tls.yml @@ -0,0 +1,20 @@ +# =================================================================== +# Activate this profile to enable TLS and HTTP/2. +# +# JHipster has generated a self-signed certificate, which will be used to encrypt traffic. +# As your browser will not understand this certificate, you will need to import it. +# +# Another (easiest) solution with Chrome is to enable the "allow-insecure-localhost" flag +# at chrome://flags/#allow-insecure-localhost +# =================================================================== +server: + ssl: + key-store: classpath:config/tls/keystore.p12 + key-store-password: password + key-store-type: PKCS12 + key-alias: selfsigned + ciphers: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + enabled-protocols: TLSv1.2 +jhipster: + http: + version: V_2_0 diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/application.yml b/jhipster-5/bookstore-monolith/src/main/resources/config/application.yml new file mode 100644 index 0000000000..5b28b7f00d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/application.yml @@ -0,0 +1,140 @@ +# =================================================================== +# Spring Boot configuration. +# +# This configuration will be overridden by the Spring profile you use, +# for example application-dev.yml if you use the "dev" profile. +# +# More information on profiles: https://www.jhipster.tech/profiles/ +# More information on configuration properties: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + +management: + endpoints: + web: + base-path: /management + exposure: + include: ["configprops", "env", "health", "info", "threaddump", "logfile", "jhi-metrics", "prometheus" ] + endpoint: + health: + show-details: when-authorized + jhi-metrics: + enabled: true + info: + git: + mode: full + health: + mail: + enabled: false # When using the MailService, configure an SMTP server and set this to true + metrics: + export: + # Prometheus is the default metrics backend + prometheus: + enabled: true + step: 60 + binders: + jvm: + enabled: true + processor: + enabled: true + uptime: + enabled: true + logback: + enabled: true + files: + enabled: true + integration: + enabled: true + distribution: + percentiles-histogram: + all: true + percentiles: + all: 0, 0.5, 0.75, 0.95, 0.99, 1.0 + web: + server: + auto-time-requests: true + +spring: + application: + name: Bookstore + profiles: + # The commented value for `active` can be replaced with valid Spring profiles to load. + # Otherwise, it will be filled in by maven when building the WAR file + # Either way, it can be overridden by `--spring.profiles.active` value passed in the commandline or `-Dspring.profiles.active` set in `JAVA_OPTS` + active: #spring.profiles.active# + jpa: + open-in-view: false + properties: + hibernate.jdbc.time_zone: UTC + hibernate: + ddl-auto: none + naming: + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + messages: + basename: i18n/messages + mvc: + favicon: + enabled: false + thymeleaf: + mode: HTML + +server: + servlet: + session: + cookie: + http-only: true + +# Properties to be exposed on the /info management endpoint +info: + # Comma separated list of profiles that will trigger the ribbon to show + display-ribbon-on-profiles: "dev" + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +jhipster: + async: + core-pool-size: 2 + max-pool-size: 50 + queue-capacity: 10000 + # By default CORS is disabled. Uncomment to enable. + #cors: + #allowed-origins: "*" + #allowed-methods: "*" + #allowed-headers: "*" + #exposed-headers: "Authorization,Link,X-Total-Count" + #allow-credentials: true + #max-age: 1800 + mail: + from: Bookstore@localhost + swagger: + default-include-pattern: /api/.* + title: Bookstore API + description: Bookstore API documentation + version: 0.0.1 + terms-of-service-url: + contact-name: + contact-url: + contact-email: + license: + license-url: + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# application: diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/authorities.csv b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/authorities.csv new file mode 100644 index 0000000000..af5c6dfa18 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/authorities.csv @@ -0,0 +1,3 @@ +name +ROLE_ADMIN +ROLE_USER diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml new file mode 100644 index 0000000000..dd4b01d487 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/20190319124041_added_entity_Book.xml b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/20190319124041_added_entity_Book.xml new file mode 100644 index 0000000000..f040387cf1 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/changelog/20190319124041_added_entity_Book.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/master.xml b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/master.xml new file mode 100644 index 0000000000..e045ee0100 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/master.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users.csv b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users.csv new file mode 100644 index 0000000000..b25922b699 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users.csv @@ -0,0 +1,5 @@ +id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;system;$2a$10$mE.qmcV0mFU5NcKh73TZx.z4ueI/.bDWbj0T1BYyqP481kGGarKLG;System;System;system@localhost;;true;en;system;system +2;anonymoususer;$2a$10$j8S5d7Sr7.8VTOYNviDPOeWX8KcYILUVJBsYV83Y5NtECayypx9lO;Anonymous;User;anonymous@localhost;;true;en;system;system +3;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +4;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users_authorities.csv b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users_authorities.csv new file mode 100644 index 0000000000..06c5feeeea --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/config/liquibase/users_authorities.csv @@ -0,0 +1,6 @@ +user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +3;ROLE_ADMIN +3;ROLE_USER +4;ROLE_USER diff --git a/jhipster-5/bookstore-monolith/src/main/resources/config/tls/keystore.p12 b/jhipster-5/bookstore-monolith/src/main/resources/config/tls/keystore.p12 new file mode 100644 index 0000000000..364fad7435 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/resources/config/tls/keystore.p12 differ diff --git a/jhipster-5/bookstore-monolith/src/main/resources/i18n/messages.properties b/jhipster-5/bookstore-monolith/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000000..52a60093c5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/i18n/messages.properties @@ -0,0 +1,21 @@ +# Error page +error.title=Your request cannot be processed +error.subtitle=Sorry, an error has occurred. +error.status=Status: +error.message=Message: + +# Activation email +email.activation.title=Bookstore account activation +email.activation.greeting=Dear {0} +email.activation.text1=Your Bookstore account has been created, please click on the URL below to activate it: +email.activation.text2=Regards, +email.signature=Bookstore Team. + +# Creation email +email.creation.text1=Your Bookstore account has been created, please click on the URL below to access it: + +# Reset email +email.reset.title=Bookstore password reset +email.reset.greeting=Dear {0} +email.reset.text1=For your Bookstore account a password reset was requested, please click on the URL below to reset it: +email.reset.text2=Regards, diff --git a/jhipster-5/bookstore-monolith/src/main/resources/logback-spring.xml b/jhipster-5/bookstore-monolith/src/main/resources/logback-spring.xml new file mode 100644 index 0000000000..4aa548af35 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/logback-spring.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/templates/error.html b/jhipster-5/bookstore-monolith/src/main/resources/templates/error.html new file mode 100644 index 0000000000..08616bcf1e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/templates/error.html @@ -0,0 +1,163 @@ + + + + + + Your request cannot be processed + + + +

+

Your request cannot be processed :(

+ +

Sorry, an error has occurred.

+ + Status:  ()
+ + Message: 
+
+ + + +
+ + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/activationEmail.html b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/activationEmail.html new file mode 100644 index 0000000000..cb021d8e6a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/activationEmail.html @@ -0,0 +1,25 @@ + + + + JHipster activation + + + + +

+ Dear +

+

+ Your JHipster account has been created, please click on the URL below to activate it: +

+

+ Activation link +

+

+ Regards, +
+ JHipster. +

+ + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/creationEmail.html b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/creationEmail.html new file mode 100644 index 0000000000..dc0cff5883 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/creationEmail.html @@ -0,0 +1,25 @@ + + + + JHipster creation + + + + +

+ Dear +

+

+ Your JHipster account has been created, please click on the URL below to access it: +

+

+ Login link +

+

+ Regards, +
+ JHipster. +

+ + diff --git a/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/passwordResetEmail.html b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/passwordResetEmail.html new file mode 100644 index 0000000000..f44511265b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/resources/templates/mail/passwordResetEmail.html @@ -0,0 +1,25 @@ + + + + JHipster password reset + + + + +

+ Dear +

+

+ For your JHipster account a password reset was requested, please click on the URL below to reset it: +

+

+ Login link +

+

+ Regards, +
+ JHipster. +

+ + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/404.html b/jhipster-5/bookstore-monolith/src/main/webapp/404.html new file mode 100644 index 0000000000..3fdc0bee1a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/404.html @@ -0,0 +1,61 @@ + + + + + Page Not Found + + + + + +

Page Not Found

+

Sorry, but the page you were trying to view does not exist.

+ + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.module.ts new file mode 100644 index 0000000000..a167cab1c2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.module.ts @@ -0,0 +1,30 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { BookstoreSharedModule } from 'app/shared'; + +import { + PasswordStrengthBarComponent, + RegisterComponent, + ActivateComponent, + PasswordComponent, + PasswordResetInitComponent, + PasswordResetFinishComponent, + SettingsComponent, + accountState +} from './'; + +@NgModule({ + imports: [BookstoreSharedModule, RouterModule.forChild(accountState)], + declarations: [ + ActivateComponent, + RegisterComponent, + PasswordComponent, + PasswordStrengthBarComponent, + PasswordResetInitComponent, + PasswordResetFinishComponent, + SettingsComponent + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreAccountModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.route.ts new file mode 100644 index 0000000000..f849342e69 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/account.route.ts @@ -0,0 +1,12 @@ +import { Routes } from '@angular/router'; + +import { activateRoute, passwordRoute, passwordResetFinishRoute, passwordResetInitRoute, registerRoute, settingsRoute } from './'; + +const ACCOUNT_ROUTES = [activateRoute, passwordRoute, passwordResetFinishRoute, passwordResetInitRoute, registerRoute, settingsRoute]; + +export const accountState: Routes = [ + { + path: '', + children: ACCOUNT_ROUTES + } +]; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.html new file mode 100644 index 0000000000..c7078ede86 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.html @@ -0,0 +1,17 @@ +
+
+
+

Activation

+ +
+ Your user account has been activated. Please + sign in. +
+ +
+ Your user could not be activated. Please use the registration form to sign up. +
+ +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.ts new file mode 100644 index 0000000000..5c398073c3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.component.ts @@ -0,0 +1,37 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { ActivatedRoute } from '@angular/router'; + +import { LoginModalService } from 'app/core'; +import { ActivateService } from './activate.service'; + +@Component({ + selector: 'jhi-activate', + templateUrl: './activate.component.html' +}) +export class ActivateComponent implements OnInit { + error: string; + success: string; + modalRef: NgbModalRef; + + constructor(private activateService: ActivateService, private loginModalService: LoginModalService, private route: ActivatedRoute) {} + + ngOnInit() { + this.route.queryParams.subscribe(params => { + this.activateService.get(params['key']).subscribe( + () => { + this.error = null; + this.success = 'OK'; + }, + () => { + this.success = null; + this.error = 'ERROR'; + } + ); + }); + } + + login() { + this.modalRef = this.loginModalService.open(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.route.ts new file mode 100644 index 0000000000..b415b17a18 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { ActivateComponent } from './activate.component'; + +export const activateRoute: Route = { + path: 'activate', + component: ActivateComponent, + data: { + authorities: [], + pageTitle: 'Activation' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.service.ts new file mode 100644 index 0000000000..adade9efad --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/activate/activate.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class ActivateService { + constructor(private http: HttpClient) {} + + get(key: string): Observable { + return this.http.get(SERVER_API_URL + 'api/activate', { + params: new HttpParams().set('key', key) + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/index.ts new file mode 100644 index 0000000000..aeada0551c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/index.ts @@ -0,0 +1,19 @@ +export * from './activate/activate.component'; +export * from './activate/activate.service'; +export * from './activate/activate.route'; +export * from './password/password.component'; +export * from './password/password-strength-bar.component'; +export * from './password/password.service'; +export * from './password/password.route'; +export * from './password-reset/finish/password-reset-finish.component'; +export * from './password-reset/finish/password-reset-finish.service'; +export * from './password-reset/finish/password-reset-finish.route'; +export * from './password-reset/init/password-reset-init.component'; +export * from './password-reset/init/password-reset-init.service'; +export * from './password-reset/init/password-reset-init.route'; +export * from './register/register.component'; +export * from './register/register.service'; +export * from './register/register.route'; +export * from './settings/settings.component'; +export * from './settings/settings.route'; +export * from './account.route'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html new file mode 100644 index 0000000000..6d6baea694 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html @@ -0,0 +1,77 @@ +
+
+
+

Reset password

+ +
+ The password reset key is missing. +
+ +
+

Choose a new password

+
+ +
+

Your password couldn't be reset. Remember a password request is only valid for 24 hours.

+
+ +

+ Your password has been reset. Please + sign in. +

+ +
+ The password and its confirmation do not match! +
+ +
+
+
+ + +
+ + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + +
+ +
+ +
+ + +
+ + Your password confirmation is required. + + + Your password confirmation is required to be at least 4 characters. + + + Your password confirmation cannot be longer than 50 characters. + +
+
+ +
+
+ +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts new file mode 100644 index 0000000000..72aac25c96 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { ActivatedRoute } from '@angular/router'; + +import { LoginModalService } from 'app/core'; +import { PasswordResetFinishService } from './password-reset-finish.service'; + +@Component({ + selector: 'jhi-password-reset-finish', + templateUrl: './password-reset-finish.component.html' +}) +export class PasswordResetFinishComponent implements OnInit, AfterViewInit { + confirmPassword: string; + doNotMatch: string; + error: string; + keyMissing: boolean; + resetAccount: any; + success: string; + modalRef: NgbModalRef; + key: string; + + constructor( + private passwordResetFinishService: PasswordResetFinishService, + private loginModalService: LoginModalService, + private route: ActivatedRoute, + private elementRef: ElementRef, + private renderer: Renderer + ) {} + + ngOnInit() { + this.route.queryParams.subscribe(params => { + this.key = params['key']; + }); + this.resetAccount = {}; + this.keyMissing = !this.key; + } + + ngAfterViewInit() { + if (this.elementRef.nativeElement.querySelector('#password') != null) { + this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#password'), 'focus', []); + } + } + + finishReset() { + this.doNotMatch = null; + this.error = null; + if (this.resetAccount.password !== this.confirmPassword) { + this.doNotMatch = 'ERROR'; + } else { + this.passwordResetFinishService.save({ key: this.key, newPassword: this.resetAccount.password }).subscribe( + () => { + this.success = 'OK'; + }, + () => { + this.success = null; + this.error = 'ERROR'; + } + ); + } + } + + login() { + this.modalRef = this.loginModalService.open(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts new file mode 100644 index 0000000000..a09cba9377 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { PasswordResetFinishComponent } from './password-reset-finish.component'; + +export const passwordResetFinishRoute: Route = { + path: 'reset/finish', + component: PasswordResetFinishComponent, + data: { + authorities: [], + pageTitle: 'Password' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts new file mode 100644 index 0000000000..706bdaa5b1 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class PasswordResetFinishService { + constructor(private http: HttpClient) {} + + save(keyAndPassword: any): Observable { + return this.http.post(SERVER_API_URL + 'api/account/reset-password/finish', keyAndPassword); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html new file mode 100644 index 0000000000..7fe7b0bdec --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html @@ -0,0 +1,46 @@ +
+
+
+

Reset your password

+ +
+ Email address isn't registered! Please check and try again. +
+ +
+

Enter the email address you used to register.

+
+ +
+

Check your emails for details on how to reset your password.

+
+ +
+
+ + +
+ + Your email is required. + + + Your email is invalid. + + + Your email is required to be at least 5 characters. + + + Your email cannot be longer than 100 characters. + +
+
+ +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts new file mode 100644 index 0000000000..e32617341c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { EMAIL_NOT_FOUND_TYPE } from 'app/shared'; +import { PasswordResetInitService } from './password-reset-init.service'; + +@Component({ + selector: 'jhi-password-reset-init', + templateUrl: './password-reset-init.component.html' +}) +export class PasswordResetInitComponent implements OnInit, AfterViewInit { + error: string; + errorEmailNotExists: string; + resetAccount: any; + success: string; + + constructor(private passwordResetInitService: PasswordResetInitService, private elementRef: ElementRef, private renderer: Renderer) {} + + ngOnInit() { + this.resetAccount = {}; + } + + ngAfterViewInit() { + this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#email'), 'focus', []); + } + + requestReset() { + this.error = null; + this.errorEmailNotExists = null; + + this.passwordResetInitService.save(this.resetAccount.email).subscribe( + () => { + this.success = 'OK'; + }, + response => { + this.success = null; + if (response.status === 400 && response.error.type === EMAIL_NOT_FOUND_TYPE) { + this.errorEmailNotExists = 'ERROR'; + } else { + this.error = 'ERROR'; + } + } + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts new file mode 100644 index 0000000000..a1708c98b3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { PasswordResetInitComponent } from './password-reset-init.component'; + +export const passwordResetInitRoute: Route = { + path: 'reset/request', + component: PasswordResetInitComponent, + data: { + authorities: [], + pageTitle: 'Password' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts new file mode 100644 index 0000000000..c24ccf94d2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class PasswordResetInitService { + constructor(private http: HttpClient) {} + + save(mail: string): Observable { + return this.http.post(SERVER_API_URL + 'api/account/reset-password/init', mail); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.component.ts new file mode 100644 index 0000000000..4159fde882 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.component.ts @@ -0,0 +1,85 @@ +import { Component, ElementRef, Input, Renderer } from '@angular/core'; + +@Component({ + selector: 'jhi-password-strength-bar', + template: ` +
+ Password strength: +
    +
  • +
  • +
  • +
  • +
  • +
+
+ `, + styleUrls: ['password-strength-bar.scss'] +}) +export class PasswordStrengthBarComponent { + colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0']; + + constructor(private renderer: Renderer, private elementRef: ElementRef) {} + + measureStrength(p: string): number { + let force = 0; + const regex = /[$-/:-?{-~!"^_`\[\]]/g; // " + const lowerLetters = /[a-z]+/.test(p); + const upperLetters = /[A-Z]+/.test(p); + const numbers = /[0-9]+/.test(p); + const symbols = regex.test(p); + + const flags = [lowerLetters, upperLetters, numbers, symbols]; + const passedMatches = flags.filter((isMatchedFlag: boolean) => { + return isMatchedFlag === true; + }).length; + + force += 2 * p.length + (p.length >= 10 ? 1 : 0); + force += passedMatches * 10; + + // penalty (short password) + force = p.length <= 6 ? Math.min(force, 10) : force; + + // penalty (poor variety of characters) + force = passedMatches === 1 ? Math.min(force, 10) : force; + force = passedMatches === 2 ? Math.min(force, 20) : force; + force = passedMatches === 3 ? Math.min(force, 40) : force; + + return force; + } + + getColor(s: number): any { + let idx = 0; + if (s <= 10) { + idx = 0; + } else if (s <= 20) { + idx = 1; + } else if (s <= 30) { + idx = 2; + } else if (s <= 40) { + idx = 3; + } else { + idx = 4; + } + return { idx: idx + 1, col: this.colors[idx] }; + } + + @Input() + set passwordToCheck(password: string) { + if (password) { + const c = this.getColor(this.measureStrength(password)); + const element = this.elementRef.nativeElement; + if (element.className) { + this.renderer.setElementClass(element, element.className, false); + } + const lis = element.getElementsByTagName('li'); + for (let i = 0; i < lis.length; i++) { + if (i < c.idx) { + this.renderer.setElementStyle(lis[i], 'backgroundColor', c.col); + } else { + this.renderer.setElementStyle(lis[i], 'backgroundColor', '#DDD'); + } + } + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.scss b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.scss new file mode 100644 index 0000000000..9744b9b784 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password-strength-bar.scss @@ -0,0 +1,23 @@ +/* ========================================================================== +start Password strength bar style +========================================================================== */ +ul#strength { + display: inline; + list-style: none; + margin: 0; + margin-left: 15px; + padding: 0; + vertical-align: 2px; +} + +.point { + background: #ddd; + border-radius: 2px; + display: inline-block; + height: 5px; + margin-right: 1px; + width: 20px; + &:last-child { + margin: 0 !important; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.html new file mode 100644 index 0000000000..79fb60c3bc --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.html @@ -0,0 +1,77 @@ +
+
+
+

Password for [{{account.login}}]

+ +
+ Password changed! +
+
+ An error has occurred! The password could not be changed. +
+ +
+ The password and its confirmation do not match! +
+ +
+ +
+ + +
+ + Your password is required. + +
+
+
+ + +
+ + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + +
+ +
+
+ + +
+ + Your confirmation password is required. + + + Your confirmation password is required to be at least 4 characters. + + + Your confirmation password cannot be longer than 50 characters. + +
+
+ + +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.ts new file mode 100644 index 0000000000..3004effa57 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.component.ts @@ -0,0 +1,46 @@ +import { Component, OnInit } from '@angular/core'; + +import { AccountService } from 'app/core'; +import { PasswordService } from './password.service'; + +@Component({ + selector: 'jhi-password', + templateUrl: './password.component.html' +}) +export class PasswordComponent implements OnInit { + doNotMatch: string; + error: string; + success: string; + account: any; + currentPassword: string; + newPassword: string; + confirmPassword: string; + + constructor(private passwordService: PasswordService, private accountService: AccountService) {} + + ngOnInit() { + this.accountService.identity().then(account => { + this.account = account; + }); + } + + changePassword() { + if (this.newPassword !== this.confirmPassword) { + this.error = null; + this.success = null; + this.doNotMatch = 'ERROR'; + } else { + this.doNotMatch = null; + this.passwordService.save(this.newPassword, this.currentPassword).subscribe( + () => { + this.error = null; + this.success = 'OK'; + }, + () => { + this.success = null; + this.error = 'ERROR'; + } + ); + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.route.ts new file mode 100644 index 0000000000..4bb115fd44 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from 'app/core'; +import { PasswordComponent } from './password.component'; + +export const passwordRoute: Route = { + path: 'password', + component: PasswordComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Password' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.service.ts new file mode 100644 index 0000000000..028df7b0e4 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/password/password.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class PasswordService { + constructor(private http: HttpClient) {} + + save(newPassword: string, currentPassword: string): Observable { + return this.http.post(SERVER_API_URL + 'api/account/change-password', { currentPassword, newPassword }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.html new file mode 100644 index 0000000000..596f782828 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.html @@ -0,0 +1,124 @@ +
+
+
+

Registration

+ +
+ Registration saved! Please check your email for confirmation. +
+ +
+ Registration failed! Please try again later. +
+ +
+ Login name already registered! Please choose another one. +
+ +
+ Email is already in use! Please choose another one. +
+ +
+ The password and its confirmation do not match! +
+
+
+
+
+
+
+ + +
+ + Your username is required. + + + Your username is required to be at least 1 character. + + + Your username cannot be longer than 50 characters. + + + Your username can only contain letters and digits. + +
+
+
+ + +
+ + Your email is required. + + + Your email is invalid. + + + Your email is required to be at least 5 characters. + + + Your email cannot be longer than 100 characters. + +
+
+
+ + +
+ + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + +
+ +
+
+ + +
+ + Your confirmation password is required. + + + Your confirmation password is required to be at least 4 characters. + + + Your confirmation password cannot be longer than 50 characters. + +
+
+ + +
+

+
+ If you want to + sign in, you can try the default accounts:
- Administrator (login="admin" and password="admin")
- User (login="user" and password="user").
+
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.ts new file mode 100644 index 0000000000..85244d2970 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.component.ts @@ -0,0 +1,71 @@ +import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { HttpErrorResponse } from '@angular/common/http'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; + +import { EMAIL_ALREADY_USED_TYPE, LOGIN_ALREADY_USED_TYPE } from 'app/shared'; +import { LoginModalService } from 'app/core'; +import { Register } from './register.service'; + +@Component({ + selector: 'jhi-register', + templateUrl: './register.component.html' +}) +export class RegisterComponent implements OnInit, AfterViewInit { + confirmPassword: string; + doNotMatch: string; + error: string; + errorEmailExists: string; + errorUserExists: string; + registerAccount: any; + success: boolean; + modalRef: NgbModalRef; + + constructor( + private loginModalService: LoginModalService, + private registerService: Register, + private elementRef: ElementRef, + private renderer: Renderer + ) {} + + ngOnInit() { + this.success = false; + this.registerAccount = {}; + } + + ngAfterViewInit() { + this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#login'), 'focus', []); + } + + register() { + if (this.registerAccount.password !== this.confirmPassword) { + this.doNotMatch = 'ERROR'; + } else { + this.doNotMatch = null; + this.error = null; + this.errorUserExists = null; + this.errorEmailExists = null; + this.registerAccount.langKey = 'en'; + this.registerService.save(this.registerAccount).subscribe( + () => { + this.success = true; + }, + response => this.processError(response) + ); + } + } + + openLogin() { + this.modalRef = this.loginModalService.open(); + } + + private processError(response: HttpErrorResponse) { + this.success = null; + if (response.status === 400 && response.error.type === LOGIN_ALREADY_USED_TYPE) { + this.errorUserExists = 'ERROR'; + } else if (response.status === 400 && response.error.type === EMAIL_ALREADY_USED_TYPE) { + this.errorEmailExists = 'ERROR'; + } else { + this.error = 'ERROR'; + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.route.ts new file mode 100644 index 0000000000..626cd32ff9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { RegisterComponent } from './register.component'; + +export const registerRoute: Route = { + path: 'register', + component: RegisterComponent, + data: { + authorities: [], + pageTitle: 'Registration' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.service.ts new file mode 100644 index 0000000000..dfe6f1da6a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/register/register.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class Register { + constructor(private http: HttpClient) {} + + save(account: any): Observable { + return this.http.post(SERVER_API_URL + 'api/register', account); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.html new file mode 100644 index 0000000000..bae1bb67e6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.html @@ -0,0 +1,80 @@ +
+
+
+

User settings for [{{settingsAccount.login}}]

+ +
+ Settings saved! +
+ + + +
+ +
+ + +
+ + Your first name is required. + + + Your first name is required to be at least 1 character. + + + Your first name cannot be longer than 50 characters. + +
+
+
+ + +
+ + Your last name is required. + + + Your last name is required to be at least 1 character. + + + Your last name cannot be longer than 50 characters. + +
+
+
+ + +
+ + Your email is required. + + + Your email is invalid. + + + Your email is required to be at least 5 characters. + + + Your email cannot be longer than 100 characters. + +
+
+ +
+
+
+ +
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.ts new file mode 100644 index 0000000000..92afaca793 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.component.ts @@ -0,0 +1,50 @@ +import { Component, OnInit } from '@angular/core'; + +import { AccountService } from 'app/core'; + +@Component({ + selector: 'jhi-settings', + templateUrl: './settings.component.html' +}) +export class SettingsComponent implements OnInit { + error: string; + success: string; + settingsAccount: any; + languages: any[]; + + constructor(private accountService: AccountService) {} + + ngOnInit() { + this.accountService.identity().then(account => { + this.settingsAccount = this.copyAccount(account); + }); + } + + save() { + this.accountService.save(this.settingsAccount).subscribe( + () => { + this.error = null; + this.success = 'OK'; + this.accountService.identity(true).then(account => { + this.settingsAccount = this.copyAccount(account); + }); + }, + () => { + this.success = null; + this.error = 'ERROR'; + } + ); + } + + copyAccount(account) { + return { + activated: account.activated, + email: account.email, + firstName: account.firstName, + langKey: account.langKey, + lastName: account.lastName, + login: account.login, + imageUrl: account.imageUrl + }; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.route.ts new file mode 100644 index 0000000000..3c9cf18e15 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/account/settings/settings.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from 'app/core'; +import { SettingsComponent } from './settings.component'; + +export const settingsRoute: Route = { + path: 'settings', + component: SettingsComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Settings' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.module.ts new file mode 100644 index 0000000000..4e46e0fe13 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.module.ts @@ -0,0 +1,43 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { BookstoreSharedModule } from 'app/shared'; +/* jhipster-needle-add-admin-module-import - JHipster will add admin modules imports here */ + +import { + adminState, + AuditsComponent, + UserMgmtComponent, + UserMgmtDetailComponent, + UserMgmtUpdateComponent, + UserMgmtDeleteDialogComponent, + LogsComponent, + JhiMetricsMonitoringComponent, + JhiHealthModalComponent, + JhiHealthCheckComponent, + JhiConfigurationComponent, + JhiDocsComponent +} from './'; + +@NgModule({ + imports: [ + BookstoreSharedModule, + RouterModule.forChild(adminState) + /* jhipster-needle-add-admin-module - JHipster will add admin modules here */ + ], + declarations: [ + AuditsComponent, + UserMgmtComponent, + UserMgmtDetailComponent, + UserMgmtUpdateComponent, + UserMgmtDeleteDialogComponent, + LogsComponent, + JhiConfigurationComponent, + JhiHealthCheckComponent, + JhiHealthModalComponent, + JhiDocsComponent, + JhiMetricsMonitoringComponent + ], + entryComponents: [UserMgmtDeleteDialogComponent, JhiHealthModalComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreAdminModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.route.ts new file mode 100644 index 0000000000..88c7e575f0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/admin.route.ts @@ -0,0 +1,18 @@ +import { Routes } from '@angular/router'; + +import { auditsRoute, configurationRoute, docsRoute, healthRoute, logsRoute, metricsRoute, userMgmtRoute } from './'; + +import { UserRouteAccessService } from 'app/core'; + +const ADMIN_ROUTES = [auditsRoute, configurationRoute, docsRoute, healthRoute, logsRoute, ...userMgmtRoute, metricsRoute]; + +export const adminState: Routes = [ + { + path: '', + data: { + authorities: ['ROLE_ADMIN'] + }, + canActivate: [UserRouteAccessService], + children: ADMIN_ROUTES + } +]; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit-data.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit-data.model.ts new file mode 100644 index 0000000000..a2506c4090 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit-data.model.ts @@ -0,0 +1,3 @@ +export class AuditData { + constructor(public remoteAddress: string, public sessionId: string) {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit.model.ts new file mode 100644 index 0000000000..6497fb444e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audit.model.ts @@ -0,0 +1,5 @@ +import { AuditData } from './audit-data.model'; + +export class Audit { + constructor(public data: AuditData, public principal: string, public timestamp: string, public type: string) {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.html new file mode 100644 index 0000000000..38af44044a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.html @@ -0,0 +1,52 @@ +
+

Audits

+ +
+
+

Filter by date

+
+
+ from +
+ + +
+ To +
+ +
+
+
+ +
+ + + + + + + + + + + + + + + + + +
DateUserStateExtra data
{{audit.timestamp| date:'medium'}}{{audit.principal}}{{audit.type}} + {{audit.data.message}} + Remote Address {{audit.data.remoteAddress}} +
+
+
+
+ +
+
+ +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.ts new file mode 100644 index 0000000000..21739275f2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.component.ts @@ -0,0 +1,126 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { DatePipe } from '@angular/common'; +import { ActivatedRoute, Router } from '@angular/router'; +import { JhiParseLinks, JhiAlertService } from 'ng-jhipster'; + +import { ITEMS_PER_PAGE } from 'app/shared'; +import { Audit } from './audit.model'; +import { AuditsService } from './audits.service'; + +@Component({ + selector: 'jhi-audit', + templateUrl: './audits.component.html' +}) +export class AuditsComponent implements OnInit, OnDestroy { + audits: Audit[]; + fromDate: string; + itemsPerPage: any; + links: any; + page: number; + routeData: any; + predicate: any; + previousPage: any; + reverse: boolean; + toDate: string; + totalItems: number; + + constructor( + private auditsService: AuditsService, + private alertService: JhiAlertService, + private parseLinks: JhiParseLinks, + private activatedRoute: ActivatedRoute, + private datePipe: DatePipe, + private router: Router + ) { + this.itemsPerPage = ITEMS_PER_PAGE; + this.routeData = this.activatedRoute.data.subscribe(data => { + this.page = data['pagingParams'].page; + this.previousPage = data['pagingParams'].page; + this.reverse = data['pagingParams'].ascending; + this.predicate = data['pagingParams'].predicate; + }); + } + + ngOnInit() { + this.today(); + this.previousMonth(); + this.loadAll(); + } + + ngOnDestroy() { + this.routeData.unsubscribe(); + } + + previousMonth() { + const dateFormat = 'yyyy-MM-dd'; + let fromDate: Date = new Date(); + + if (fromDate.getMonth() === 0) { + fromDate = new Date(fromDate.getFullYear() - 1, 11, fromDate.getDate()); + } else { + fromDate = new Date(fromDate.getFullYear(), fromDate.getMonth() - 1, fromDate.getDate()); + } + + this.fromDate = this.datePipe.transform(fromDate, dateFormat); + } + + today() { + const dateFormat = 'yyyy-MM-dd'; + // Today + 1 day - needed if the current day must be included + const today: Date = new Date(); + today.setDate(today.getDate() + 1); + const date = new Date(today.getFullYear(), today.getMonth(), today.getDate()); + this.toDate = this.datePipe.transform(date, dateFormat); + } + + loadAll() { + this.auditsService + .query({ + page: this.page - 1, + size: this.itemsPerPage, + sort: this.sort(), + fromDate: this.fromDate, + toDate: this.toDate + }) + .subscribe( + (res: HttpResponse) => this.onSuccess(res.body, res.headers), + (res: HttpResponse) => this.onError(res.body) + ); + } + + sort() { + const result = [this.predicate + ',' + (this.reverse ? 'asc' : 'desc')]; + if (this.predicate !== 'id') { + result.push('id'); + } + return result; + } + + loadPage(page: number) { + if (page !== this.previousPage) { + this.previousPage = page; + this.transition(); + } + } + + transition() { + this.router.navigate(['/admin/audits'], { + queryParams: { + page: this.page, + sort: this.predicate + ',' + (this.reverse ? 'asc' : 'desc') + } + }); + this.loadAll(); + } + + private onSuccess(data, headers) { + this.links = this.parseLinks.parse(headers.get('link')); + this.totalItems = headers.get('X-Total-Count'); + this.audits = data; + } + + private onError(error) { + this.alertService.error(error.error, error.message, null); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.route.ts new file mode 100644 index 0000000000..87af5c6e8c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.route.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Route } from '@angular/router'; +import { JhiPaginationUtil, JhiResolvePagingParams } from 'ng-jhipster'; + +import { AuditsComponent } from './audits.component'; + +export const auditsRoute: Route = { + path: 'audits', + component: AuditsComponent, + resolve: { + pagingParams: JhiResolvePagingParams + }, + data: { + pageTitle: 'Audits', + defaultSort: 'auditEventDate,desc' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.service.ts new file mode 100644 index 0000000000..78e8cca7e2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/audits/audits.service.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { createRequestOption } from 'app/shared'; +import { SERVER_API_URL } from 'app/app.constants'; +import { Audit } from './audit.model'; + +@Injectable({ providedIn: 'root' }) +export class AuditsService { + constructor(private http: HttpClient) {} + + query(req: any): Observable> { + const params: HttpParams = createRequestOption(req); + params.set('fromDate', req.fromDate); + params.set('toDate', req.toDate); + + const requestURL = SERVER_API_URL + 'management/audits'; + + return this.http.get(requestURL, { + params, + observe: 'response' + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.html new file mode 100644 index 0000000000..02a4a96433 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.html @@ -0,0 +1,46 @@ +
+

Configuration

+ + Filter (by prefix) +

Spring configuration

+ + + + + + + + + + + + + +
PrefixProperties
{{entry.prefix}} +
+
{{key}}
+
+ {{entry.properties[key] | json}} +
+
+
+
+

{{key}}

+ + + + + + + + + + + + + +
PropertyValue
{{item.key}} + {{item.val}} +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.ts new file mode 100644 index 0000000000..6867210c91 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit } from '@angular/core'; + +import { JhiConfigurationService } from './configuration.service'; + +@Component({ + selector: 'jhi-configuration', + templateUrl: './configuration.component.html' +}) +export class JhiConfigurationComponent implements OnInit { + allConfiguration: any = null; + configuration: any = null; + configKeys: any[]; + filter: string; + orderProp: string; + reverse: boolean; + + constructor(private configurationService: JhiConfigurationService) { + this.configKeys = []; + this.filter = ''; + this.orderProp = 'prefix'; + this.reverse = false; + } + + keys(dict): Array { + return dict === undefined ? [] : Object.keys(dict); + } + + ngOnInit() { + this.configurationService.get().subscribe(configuration => { + this.configuration = configuration; + + for (const config of configuration) { + if (config.properties !== undefined) { + this.configKeys.push(Object.keys(config.properties)); + } + } + }); + + this.configurationService.getEnv().subscribe(configuration => { + this.allConfiguration = configuration; + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.route.ts new file mode 100644 index 0000000000..f4ad9c3688 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.route.ts @@ -0,0 +1,11 @@ +import { Route } from '@angular/router'; + +import { JhiConfigurationComponent } from './configuration.component'; + +export const configurationRoute: Route = { + path: 'jhi-configuration', + component: JhiConfigurationComponent, + data: { + pageTitle: 'Configuration' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.service.ts new file mode 100644 index 0000000000..5f9dfd491c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/configuration/configuration.service.ts @@ -0,0 +1,67 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class JhiConfigurationService { + constructor(private http: HttpClient) {} + + get(): Observable { + return this.http.get(SERVER_API_URL + 'management/configprops', { observe: 'response' }).pipe( + map((res: HttpResponse) => { + const properties: any[] = []; + const propertiesObject = this.getConfigPropertiesObjects(res.body); + for (const key in propertiesObject) { + if (propertiesObject.hasOwnProperty(key)) { + properties.push(propertiesObject[key]); + } + } + + return properties.sort((propertyA, propertyB) => { + return propertyA.prefix === propertyB.prefix ? 0 : propertyA.prefix < propertyB.prefix ? -1 : 1; + }); + }) + ); + } + + getConfigPropertiesObjects(res: Object) { + // This code is for Spring Boot 2 + if (res['contexts'] !== undefined) { + for (const key in res['contexts']) { + // If the key is not bootstrap, it will be the ApplicationContext Id + // For default app, it is baseName + // For microservice, it is baseName-1 + if (!key.startsWith('bootstrap')) { + return res['contexts'][key]['beans']; + } + } + } + // by default, use the default ApplicationContext Id + return res['contexts']['Bookstore']['beans']; + } + + getEnv(): Observable { + return this.http.get(SERVER_API_URL + 'management/env', { observe: 'response' }).pipe( + map((res: HttpResponse) => { + const properties: any = {}; + const propertySources = res.body['propertySources']; + + for (const propertyObject of propertySources) { + const name = propertyObject['name']; + const detailProperties = propertyObject['properties']; + const vals: any[] = []; + for (const keyDetail in detailProperties) { + if (detailProperties.hasOwnProperty(keyDetail)) { + vals.push({ key: keyDetail, val: detailProperties[keyDetail]['value'] }); + } + } + properties[name] = vals; + } + return properties; + }) + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.html new file mode 100644 index 0000000000..30efbbb93e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.html @@ -0,0 +1,2 @@ + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.ts new file mode 100644 index 0000000000..b338e7c3a6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'jhi-docs', + templateUrl: './docs.component.html' +}) +export class JhiDocsComponent { + constructor() {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.route.ts new file mode 100644 index 0000000000..d7df51b935 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/docs/docs.route.ts @@ -0,0 +1,11 @@ +import { Route } from '@angular/router'; + +import { JhiDocsComponent } from './docs.component'; + +export const docsRoute: Route = { + path: 'docs', + component: JhiDocsComponent, + data: { + pageTitle: 'API' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.html new file mode 100644 index 0000000000..efc125e3a0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.html @@ -0,0 +1,35 @@ + + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.ts new file mode 100644 index 0000000000..28128bf321 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health-modal.component.ts @@ -0,0 +1,41 @@ +import { Component } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; + +import { JhiHealthService } from './health.service'; + +@Component({ + selector: 'jhi-health-modal', + templateUrl: './health-modal.component.html' +}) +export class JhiHealthModalComponent { + currentHealth: any; + + constructor(private healthService: JhiHealthService, public activeModal: NgbActiveModal) {} + + baseName(name) { + return this.healthService.getBaseName(name); + } + + subSystemName(name) { + return this.healthService.getSubSystemName(name); + } + + readableValue(value: number) { + if (this.currentHealth.name === 'diskSpace') { + // Should display storage space in an human readable unit + const val = value / 1073741824; + if (val > 1) { + // Value + return val.toFixed(2) + ' GB'; + } else { + return (value / 1048576).toFixed(2) + ' MB'; + } + } + + if (typeof value === 'object') { + return JSON.stringify(value); + } else { + return value.toString(); + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.html new file mode 100644 index 0000000000..b314daa0ba --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.html @@ -0,0 +1,34 @@ +
+

+ Health Checks + +

+
+ + + + + + + + + + + + + + + +
Service NameStatusDetails
{{ baseName(health.name) }} {{subSystemName(health.name)}} + + {{health.status}} + + + + + +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.ts new file mode 100644 index 0000000000..ada3ef62f4 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.component.ts @@ -0,0 +1,66 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; + +import { JhiHealthService } from './health.service'; +import { JhiHealthModalComponent } from './health-modal.component'; + +@Component({ + selector: 'jhi-health', + templateUrl: './health.component.html' +}) +export class JhiHealthCheckComponent implements OnInit { + healthData: any; + updatingHealth: boolean; + + constructor(private modalService: NgbModal, private healthService: JhiHealthService) {} + + ngOnInit() { + this.refresh(); + } + + baseName(name: string) { + return this.healthService.getBaseName(name); + } + + getBadgeClass(statusState) { + if (statusState === 'UP') { + return 'badge-success'; + } else { + return 'badge-danger'; + } + } + + refresh() { + this.updatingHealth = true; + + this.healthService.checkHealth().subscribe( + health => { + this.healthData = this.healthService.transformHealthData(health); + this.updatingHealth = false; + }, + error => { + if (error.status === 503) { + this.healthData = this.healthService.transformHealthData(error.error); + this.updatingHealth = false; + } + } + ); + } + + showHealth(health: any) { + const modalRef = this.modalService.open(JhiHealthModalComponent); + modalRef.componentInstance.currentHealth = health; + modalRef.result.then( + result => { + // Left blank intentionally, nothing to do here + }, + reason => { + // Left blank intentionally, nothing to do here + } + ); + } + + subSystemName(name: string) { + return this.healthService.getSubSystemName(name); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.route.ts new file mode 100644 index 0000000000..0b67775651 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.route.ts @@ -0,0 +1,11 @@ +import { Route } from '@angular/router'; + +import { JhiHealthCheckComponent } from './health.component'; + +export const healthRoute: Route = { + path: 'jhi-health', + component: JhiHealthCheckComponent, + data: { + pageTitle: 'Health Checks' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.service.ts new file mode 100644 index 0000000000..4c1b0e5ec8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/health/health.service.ts @@ -0,0 +1,133 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class JhiHealthService { + separator: string; + + constructor(private http: HttpClient) { + this.separator = '.'; + } + + checkHealth(): Observable { + return this.http.get(SERVER_API_URL + 'management/health'); + } + + transformHealthData(data): any { + const response = []; + this.flattenHealthData(response, null, data.details); + return response; + } + + getBaseName(name): string { + if (name) { + const split = name.split('.'); + return split[0]; + } + } + + getSubSystemName(name): string { + if (name) { + const split = name.split('.'); + split.splice(0, 1); + const remainder = split.join('.'); + return remainder ? ' - ' + remainder : ''; + } + } + + /* private methods */ + private addHealthObject(result, isLeaf, healthObject, name): any { + const healthData: any = { + name + }; + + const details = {}; + let hasDetails = false; + + for (const key in healthObject) { + if (healthObject.hasOwnProperty(key)) { + const value = healthObject[key]; + if (key === 'status' || key === 'error') { + healthData[key] = value; + } else { + if (!this.isHealthObject(value)) { + details[key] = value; + hasDetails = true; + } + } + } + } + + // Add the details + if (hasDetails) { + healthData.details = details; + } + + // Only add nodes if they provide additional information + if (isLeaf || hasDetails || healthData.error) { + result.push(healthData); + } + return healthData; + } + + private flattenHealthData(result, path, data): any { + for (const key in data) { + if (data.hasOwnProperty(key)) { + const value = data[key]; + if (this.isHealthObject(value)) { + if (this.hasSubSystem(value)) { + this.addHealthObject(result, false, value, this.getModuleName(path, key)); + this.flattenHealthData(result, this.getModuleName(path, key), value); + } else { + this.addHealthObject(result, true, value, this.getModuleName(path, key)); + } + } + } + } + return result; + } + + private getModuleName(path, name): string { + let result; + if (path && name) { + result = path + this.separator + name; + } else if (path) { + result = path; + } else if (name) { + result = name; + } else { + result = ''; + } + return result; + } + + private hasSubSystem(healthObject): boolean { + let result = false; + + for (const key in healthObject) { + if (healthObject.hasOwnProperty(key)) { + const value = healthObject[key]; + if (value && value.status) { + result = true; + } + } + } + return result; + } + + private isHealthObject(healthObject): boolean { + let result = false; + + for (const key in healthObject) { + if (healthObject.hasOwnProperty(key)) { + if (key === 'status') { + result = true; + } + } + } + return result; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/index.ts new file mode 100644 index 0000000000..7f631ffb9b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/index.ts @@ -0,0 +1,27 @@ +export * from './audits/audits.component'; +export * from './audits/audits.service'; +export * from './audits/audits.route'; +export * from './audits/audit.model'; +export * from './audits/audit-data.model'; +export * from './configuration/configuration.component'; +export * from './configuration/configuration.service'; +export * from './configuration/configuration.route'; +export * from './docs/docs.component'; +export * from './docs/docs.route'; +export * from './health/health.component'; +export * from './health/health-modal.component'; +export * from './health/health.service'; +export * from './health/health.route'; +export * from './logs/logs.component'; +export * from './logs/logs.service'; +export * from './logs/logs.route'; +export * from './logs/log.model'; +export * from './metrics/metrics.component'; +export * from './metrics/metrics.service'; +export * from './metrics/metrics.route'; +export * from './user-management/user-management-update.component'; +export * from './user-management/user-management-delete-dialog.component'; +export * from './user-management/user-management-detail.component'; +export * from './user-management/user-management.component'; +export * from './user-management/user-management.route'; +export * from './admin.route'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/log.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/log.model.ts new file mode 100644 index 0000000000..3f27b6728c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/log.model.ts @@ -0,0 +1,3 @@ +export class Log { + constructor(public name: string, public level: string) {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.html new file mode 100644 index 0000000000..cf5d6a046f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.html @@ -0,0 +1,28 @@ +
+

Logs

+ +

There are {{ loggers.length }} loggers.

+ + Filter + + + + + + + + + + + + + +
NameLevel
{{logger.name | slice:0:140}} + + + + + + +
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.ts new file mode 100644 index 0000000000..28547f9ae6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.component.ts @@ -0,0 +1,32 @@ +import { Component, OnInit } from '@angular/core'; + +import { Log } from './log.model'; +import { LogsService } from './logs.service'; + +@Component({ + selector: 'jhi-logs', + templateUrl: './logs.component.html' +}) +export class LogsComponent implements OnInit { + loggers: Log[]; + filter: string; + orderProp: string; + reverse: boolean; + + constructor(private logsService: LogsService) { + this.filter = ''; + this.orderProp = 'name'; + this.reverse = false; + } + + ngOnInit() { + this.logsService.findAll().subscribe(response => (this.loggers = response.body)); + } + + changeLevel(name: string, level: string) { + const log = new Log(name, level); + this.logsService.changeLevel(log).subscribe(() => { + this.logsService.findAll().subscribe(response => (this.loggers = response.body)); + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.route.ts new file mode 100644 index 0000000000..cfa87715d8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.route.ts @@ -0,0 +1,11 @@ +import { Route } from '@angular/router'; + +import { LogsComponent } from './logs.component'; + +export const logsRoute: Route = { + path: 'logs', + component: LogsComponent, + data: { + pageTitle: 'Logs' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.service.ts new file mode 100644 index 0000000000..71a596b0ab --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/logs/logs.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; +import { Log } from './log.model'; + +@Injectable({ providedIn: 'root' }) +export class LogsService { + constructor(private http: HttpClient) {} + + changeLevel(log: Log): Observable> { + return this.http.put(SERVER_API_URL + 'management/logs', log, { observe: 'response' }); + } + + findAll(): Observable> { + return this.http.get(SERVER_API_URL + 'management/logs', { observe: 'response' }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.html new file mode 100644 index 0000000000..75902d8fb3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.html @@ -0,0 +1,56 @@ +
+

+ Application Metrics + +

+ +

JVM Metrics

+
+ + + + + +
+ +
+

Garbage collector statistics

+ +
+ +
Updating...
+ + + + +
+ + + + + + + + + +
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.ts new file mode 100644 index 0000000000..ed508c8187 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.component.ts @@ -0,0 +1,42 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; + +import { JhiMetricsService } from './metrics.service'; + +@Component({ + selector: 'jhi-metrics', + templateUrl: './metrics.component.html' +}) +export class JhiMetricsMonitoringComponent implements OnInit { + metrics: any = {}; + threadData: any = {}; + updatingMetrics = true; + JCACHE_KEY: string; + + constructor(private modalService: NgbModal, private metricsService: JhiMetricsService) { + this.JCACHE_KEY = 'jcache.statistics'; + } + + ngOnInit() { + this.refresh(); + } + + refresh() { + this.updatingMetrics = true; + this.metricsService.getMetrics().subscribe(metrics => { + this.metrics = metrics; + this.metricsService.threadDump().subscribe(data => { + this.threadData = data.threads; + this.updatingMetrics = false; + }); + }); + } + + isObjectExisting(metrics: any, key: string) { + return metrics && metrics[key]; + } + + isObjectExistingAndNotEmpty(metrics: any, key: string) { + return this.isObjectExisting(metrics, key) && JSON.stringify(metrics[key]) !== '{}'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.route.ts new file mode 100644 index 0000000000..abc18b8254 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.route.ts @@ -0,0 +1,11 @@ +import { Route } from '@angular/router'; + +import { JhiMetricsMonitoringComponent } from './metrics.component'; + +export const metricsRoute: Route = { + path: 'jhi-metrics', + component: JhiMetricsMonitoringComponent, + data: { + pageTitle: 'Application Metrics' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.service.ts new file mode 100644 index 0000000000..15cfe3536c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/metrics/metrics.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class JhiMetricsService { + constructor(private http: HttpClient) {} + + getMetrics(): Observable { + return this.http.get(SERVER_API_URL + 'management/jhi-metrics'); + } + + threadDump(): Observable { + return this.http.get(SERVER_API_URL + 'management/threaddump'); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.html new file mode 100644 index 0000000000..adb1a908da --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.html @@ -0,0 +1,19 @@ +
+ + + +
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.ts new file mode 100644 index 0000000000..d7674f6cd9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.ts @@ -0,0 +1,29 @@ +import { Component } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { JhiEventManager } from 'ng-jhipster'; + +import { User, UserService } from 'app/core'; + +@Component({ + selector: 'jhi-user-mgmt-delete-dialog', + templateUrl: './user-management-delete-dialog.component.html' +}) +export class UserMgmtDeleteDialogComponent { + user: User; + + constructor(private userService: UserService, public activeModal: NgbActiveModal, private eventManager: JhiEventManager) {} + + clear() { + this.activeModal.dismiss('cancel'); + } + + confirmDelete(login) { + this.userService.delete(login).subscribe(response => { + this.eventManager.broadcast({ + name: 'userListModification', + content: 'Deleted a user' + }); + this.activeModal.dismiss(true); + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.html new file mode 100644 index 0000000000..051f335ded --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.html @@ -0,0 +1,47 @@ +
+
+
+

+ User [{{user.login}}] +

+
+
Login
+
+ {{user.login}} + + +
+
First Name
+
{{user.firstName}}
+
Last Name
+
{{user.lastName}}
+
Email
+
{{user.email}}
+
Created By
+
{{user.createdBy}}
+
Created Date
+
{{user.createdDate | date:'dd/MM/yy HH:mm' }}
+
Last Modified By
+
{{user.lastModifiedBy}}
+
Last Modified Date
+
{{user.lastModifiedDate | date:'dd/MM/yy HH:mm'}}
+
Profiles
+
+
    +
  • + {{authority}} +
  • +
+
+
+ +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.ts new file mode 100644 index 0000000000..0b323d89a0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-detail.component.ts @@ -0,0 +1,20 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { User } from 'app/core'; + +@Component({ + selector: 'jhi-user-mgmt-detail', + templateUrl: './user-management-detail.component.html' +}) +export class UserMgmtDetailComponent implements OnInit { + user: User; + + constructor(private route: ActivatedRoute) {} + + ngOnInit() { + this.route.data.subscribe(({ user }) => { + this.user = user.body ? user.body : user; + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.html new file mode 100644 index 0000000000..b2d04b4227 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.html @@ -0,0 +1,118 @@ +
+
+
+

+ Create or edit a User +

+
+ +
+ + +
+ +
+ + + +
+ + This field is required. + + + + This field cannot be longer than 50 characters. + + + + This field can only contain letters, digits and e-mail addresses. + +
+
+
+ + + +
+ + This field cannot be longer than 50 characters. + +
+
+
+ + + +
+ + This field cannot be longer than 50 characters. + +
+
+
+ + + +
+ + This field is required. + + + + This field cannot be longer than 100 characters. + + + + This field is required to be at least 5 characters. + + + + Your email is invalid. + +
+
+
+ +
+ +
+ + +
+
+
+ + +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.ts new file mode 100644 index 0000000000..e51e4f4a33 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management-update.component.ts @@ -0,0 +1,51 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { User, UserService } from 'app/core'; + +@Component({ + selector: 'jhi-user-mgmt-update', + templateUrl: './user-management-update.component.html' +}) +export class UserMgmtUpdateComponent implements OnInit { + user: User; + languages: any[]; + authorities: any[]; + isSaving: boolean; + + constructor(private userService: UserService, private route: ActivatedRoute, private router: Router) {} + + ngOnInit() { + this.isSaving = false; + this.route.data.subscribe(({ user }) => { + this.user = user.body ? user.body : user; + }); + this.authorities = []; + this.userService.authorities().subscribe(authorities => { + this.authorities = authorities; + }); + } + + previousState() { + window.history.back(); + } + + save() { + this.isSaving = true; + if (this.user.id !== null) { + this.userService.update(this.user).subscribe(response => this.onSaveSuccess(response), () => this.onSaveError()); + } else { + this.user.langKey = 'en'; + this.userService.create(this.user).subscribe(response => this.onSaveSuccess(response), () => this.onSaveError()); + } + } + + private onSaveSuccess(result) { + this.isSaving = false; + this.previousState(); + } + + private onSaveError() { + this.isSaving = false; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.html new file mode 100644 index 0000000000..4592998c1f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.html @@ -0,0 +1,78 @@ +
+

+ Users + +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID Login Email ProfilesCreated Date Last Modified By Last Modified Date
{{user.id}}{{user.login}}{{user.email}} + + + +
+ {{ authority }} +
+
{{user.createdDate | date:'dd/MM/yy HH:mm'}}{{user.lastModifiedBy}}{{user.lastModifiedDate | date:'dd/MM/yy HH:mm'}} +
+ + + +
+
+
+
+
+ +
+
+ +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.ts new file mode 100644 index 0000000000..439442e3b6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.component.ts @@ -0,0 +1,144 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; + +import { ActivatedRoute, Router } from '@angular/router'; +import { JhiEventManager, JhiParseLinks, JhiAlertService } from 'ng-jhipster'; + +import { ITEMS_PER_PAGE } from 'app/shared'; +import { AccountService, UserService, User } from 'app/core'; +import { UserMgmtDeleteDialogComponent } from 'app/admin'; + +@Component({ + selector: 'jhi-user-mgmt', + templateUrl: './user-management.component.html' +}) +export class UserMgmtComponent implements OnInit, OnDestroy { + currentAccount: any; + users: User[]; + error: any; + success: any; + routeData: any; + links: any; + totalItems: any; + itemsPerPage: any; + page: any; + predicate: any; + previousPage: any; + reverse: any; + + constructor( + private userService: UserService, + private alertService: JhiAlertService, + private accountService: AccountService, + private parseLinks: JhiParseLinks, + private activatedRoute: ActivatedRoute, + private router: Router, + private eventManager: JhiEventManager, + private modalService: NgbModal + ) { + this.itemsPerPage = ITEMS_PER_PAGE; + this.routeData = this.activatedRoute.data.subscribe(data => { + this.page = data['pagingParams'].page; + this.previousPage = data['pagingParams'].page; + this.reverse = data['pagingParams'].ascending; + this.predicate = data['pagingParams'].predicate; + }); + } + + ngOnInit() { + this.accountService.identity().then(account => { + this.currentAccount = account; + this.loadAll(); + this.registerChangeInUsers(); + }); + } + + ngOnDestroy() { + this.routeData.unsubscribe(); + } + + registerChangeInUsers() { + this.eventManager.subscribe('userListModification', response => this.loadAll()); + } + + setActive(user, isActivated) { + user.activated = isActivated; + + this.userService.update(user).subscribe(response => { + if (response.status === 200) { + this.error = null; + this.success = 'OK'; + this.loadAll(); + } else { + this.success = null; + this.error = 'ERROR'; + } + }); + } + + loadAll() { + this.userService + .query({ + page: this.page - 1, + size: this.itemsPerPage, + sort: this.sort() + }) + .subscribe( + (res: HttpResponse) => this.onSuccess(res.body, res.headers), + (res: HttpResponse) => this.onError(res.body) + ); + } + + trackIdentity(index, item: User) { + return item.id; + } + + sort() { + const result = [this.predicate + ',' + (this.reverse ? 'asc' : 'desc')]; + if (this.predicate !== 'id') { + result.push('id'); + } + return result; + } + + loadPage(page: number) { + if (page !== this.previousPage) { + this.previousPage = page; + this.transition(); + } + } + + transition() { + this.router.navigate(['/admin/user-management'], { + queryParams: { + page: this.page, + sort: this.predicate + ',' + (this.reverse ? 'asc' : 'desc') + } + }); + this.loadAll(); + } + + deleteUser(user: User) { + const modalRef = this.modalService.open(UserMgmtDeleteDialogComponent, { size: 'lg', backdrop: 'static' }); + modalRef.componentInstance.user = user; + modalRef.result.then( + result => { + // Left blank intentionally, nothing to do here + }, + reason => { + // Left blank intentionally, nothing to do here + } + ); + } + + private onSuccess(data, headers) { + this.links = this.parseLinks.parse(headers.get('link')); + this.totalItems = headers.get('X-Total-Count'); + this.users = data; + } + + private onError(error) { + this.alertService.error(error.error, error.message, null); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.route.ts new file mode 100644 index 0000000000..bf1115516f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/admin/user-management/user-management.route.ts @@ -0,0 +1,68 @@ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Routes, CanActivate } from '@angular/router'; +import { JhiPaginationUtil, JhiResolvePagingParams } from 'ng-jhipster'; + +import { AccountService, User, UserService } from 'app/core'; +import { UserMgmtComponent } from './user-management.component'; +import { UserMgmtDetailComponent } from './user-management-detail.component'; +import { UserMgmtUpdateComponent } from './user-management-update.component'; + +@Injectable({ providedIn: 'root' }) +export class UserResolve implements CanActivate { + constructor(private accountService: AccountService) {} + + canActivate() { + return this.accountService.identity().then(account => this.accountService.hasAnyAuthority(['ROLE_ADMIN'])); + } +} + +@Injectable({ providedIn: 'root' }) +export class UserMgmtResolve implements Resolve { + constructor(private service: UserService) {} + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + const id = route.params['login'] ? route.params['login'] : null; + if (id) { + return this.service.find(id); + } + return new User(); + } +} + +export const userMgmtRoute: Routes = [ + { + path: 'user-management', + component: UserMgmtComponent, + resolve: { + pagingParams: JhiResolvePagingParams + }, + data: { + pageTitle: 'Users', + defaultSort: 'id,asc' + } + }, + { + path: 'user-management/:login/view', + component: UserMgmtDetailComponent, + resolve: { + user: UserMgmtResolve + }, + data: { + pageTitle: 'Users' + } + }, + { + path: 'user-management/new', + component: UserMgmtUpdateComponent, + resolve: { + user: UserMgmtResolve + } + }, + { + path: 'user-management/:login/edit', + component: UserMgmtUpdateComponent, + resolve: { + user: UserMgmtResolve + } + } +]; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/app-routing.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/app-routing.module.ts new file mode 100644 index 0000000000..c40d4df774 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/app-routing.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { errorRoute, navbarRoute } from './layouts'; +import { DEBUG_INFO_ENABLED } from 'app/app.constants'; + +const LAYOUT_ROUTES = [navbarRoute, ...errorRoute]; + +@NgModule({ + imports: [ + RouterModule.forRoot( + [ + { + path: 'admin', + loadChildren: './admin/admin.module#BookstoreAdminModule' + }, + ...LAYOUT_ROUTES + ], + { useHash: true, enableTracing: DEBUG_INFO_ENABLED } + ) + ], + exports: [RouterModule] +}) +export class BookstoreAppRoutingModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/app.constants.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.constants.ts new file mode 100644 index 0000000000..9760a49a91 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.constants.ts @@ -0,0 +1,8 @@ +// These constants are injected via webpack environment variables. +// You can add more variables in webpack.common.js or in profile specific webpack..js files. +// If you change the values in the webpack config files, you need to re run webpack to update the application + +export const VERSION = process.env.VERSION; +export const DEBUG_INFO_ENABLED: boolean = !!process.env.DEBUG_INFO_ENABLED; +export const SERVER_API_URL = process.env.SERVER_API_URL; +export const BUILD_TIMESTAMP = process.env.BUILD_TIMESTAMP; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/app.main.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.main.ts new file mode 100644 index 0000000000..7695bb8571 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.main.ts @@ -0,0 +1,14 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { ProdConfig } from './blocks/config/prod.config'; +import { BookstoreAppModule } from './app.module'; + +ProdConfig(); + +if (module['hot']) { + module['hot'].accept(); +} + +platformBrowserDynamic() + .bootstrapModule(BookstoreAppModule, { preserveWhitespaces: true }) + .then(success => console.log(`Application started`)) + .catch(err => console.error(err)); diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/app.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.module.ts new file mode 100644 index 0000000000..5fb96ed8c5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/app.module.ts @@ -0,0 +1,70 @@ +import './vendor.ts'; + +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { NgbDatepickerConfig } from '@ng-bootstrap/ng-bootstrap'; +import { Ng2Webstorage } from 'ngx-webstorage'; +import { NgJhipsterModule } from 'ng-jhipster'; + +import { AuthInterceptor } from './blocks/interceptor/auth.interceptor'; +import { AuthExpiredInterceptor } from './blocks/interceptor/auth-expired.interceptor'; +import { ErrorHandlerInterceptor } from './blocks/interceptor/errorhandler.interceptor'; +import { NotificationInterceptor } from './blocks/interceptor/notification.interceptor'; +import { BookstoreSharedModule } from 'app/shared'; +import { BookstoreCoreModule } from 'app/core'; +import { BookstoreAppRoutingModule } from './app-routing.module'; +import { BookstoreHomeModule } from './home/home.module'; +import { BookstoreAccountModule } from './account/account.module'; +import { BookstoreEntityModule } from './entities/entity.module'; +import * as moment from 'moment'; +// jhipster-needle-angular-add-module-import JHipster will add new module here +import { JhiMainComponent, NavbarComponent, FooterComponent, PageRibbonComponent, ErrorComponent } from './layouts'; + +@NgModule({ + imports: [ + BrowserModule, + Ng2Webstorage.forRoot({ prefix: 'jhi', separator: '-' }), + NgJhipsterModule.forRoot({ + // set below to true to make alerts look like toast + alertAsToast: false, + alertTimeout: 5000 + }), + BookstoreSharedModule.forRoot(), + BookstoreCoreModule, + BookstoreHomeModule, + BookstoreAccountModule, + // jhipster-needle-angular-add-module JHipster will add new module here + BookstoreEntityModule, + BookstoreAppRoutingModule + ], + declarations: [JhiMainComponent, NavbarComponent, ErrorComponent, PageRibbonComponent, FooterComponent], + providers: [ + { + provide: HTTP_INTERCEPTORS, + useClass: AuthInterceptor, + multi: true + }, + { + provide: HTTP_INTERCEPTORS, + useClass: AuthExpiredInterceptor, + multi: true + }, + { + provide: HTTP_INTERCEPTORS, + useClass: ErrorHandlerInterceptor, + multi: true + }, + { + provide: HTTP_INTERCEPTORS, + useClass: NotificationInterceptor, + multi: true + } + ], + bootstrap: [JhiMainComponent] +}) +export class BookstoreAppModule { + constructor(private dpConfig: NgbDatepickerConfig) { + this.dpConfig.minDate = { year: moment().year() - 100, month: 1, day: 1 }; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/prod.config.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/prod.config.ts new file mode 100644 index 0000000000..c6221c1eaf --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/prod.config.ts @@ -0,0 +1,9 @@ +import { enableProdMode } from '@angular/core'; +import { DEBUG_INFO_ENABLED } from 'app/app.constants'; + +export function ProdConfig() { + // disable debug data on prod profile to improve performance + if (!DEBUG_INFO_ENABLED) { + enableProdMode(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/uib-pagination.config.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/uib-pagination.config.ts new file mode 100644 index 0000000000..0c2ea94808 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/config/uib-pagination.config.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { NgbPaginationConfig } from '@ng-bootstrap/ng-bootstrap'; +import { ITEMS_PER_PAGE } from 'app/shared'; + +@Injectable({ providedIn: 'root' }) +export class PaginationConfig { + // tslint:disable-next-line: no-unused-variable + constructor(private config: NgbPaginationConfig) { + config.boundaryLinks = true; + config.maxSize = 5; + config.pageSize = ITEMS_PER_PAGE; + config.size = 'sm'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.ts new file mode 100644 index 0000000000..bc1b70cfef --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; +import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; +import { LoginService } from 'app/core/login/login.service'; + +@Injectable() +export class AuthExpiredInterceptor implements HttpInterceptor { + constructor(private loginService: LoginService) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request).pipe( + tap( + (event: HttpEvent) => {}, + (err: any) => { + if (err instanceof HttpErrorResponse) { + if (err.status === 401) { + this.loginService.logout(); + } + } + } + ) + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth.interceptor.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth.interceptor.ts new file mode 100644 index 0000000000..23cdeaf66b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/auth.interceptor.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; +import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable() +export class AuthInterceptor implements HttpInterceptor { + constructor(private localStorage: LocalStorageService, private sessionStorage: SessionStorageService) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + if (!request || !request.url || (/^http/.test(request.url) && !(SERVER_API_URL && request.url.startsWith(SERVER_API_URL)))) { + return next.handle(request); + } + + const token = this.localStorage.retrieve('authenticationToken') || this.sessionStorage.retrieve('authenticationToken'); + if (!!token) { + request = request.clone({ + setHeaders: { + Authorization: 'Bearer ' + token + } + }); + } + return next.handle(request); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.ts new file mode 100644 index 0000000000..e464f66cd3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; +import { JhiEventManager } from 'ng-jhipster'; +import { HttpInterceptor, HttpRequest, HttpErrorResponse, HttpHandler, HttpEvent } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; + +@Injectable() +export class ErrorHandlerInterceptor implements HttpInterceptor { + constructor(private eventManager: JhiEventManager) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request).pipe( + tap( + (event: HttpEvent) => {}, + (err: any) => { + if (err instanceof HttpErrorResponse) { + if (!(err.status === 401 && (err.message === '' || (err.url && err.url.includes('/api/account'))))) { + this.eventManager.broadcast({ name: 'bookstoreApp.httpError', content: err }); + } + } + } + ) + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/notification.interceptor.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/notification.interceptor.ts new file mode 100644 index 0000000000..34af81d482 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/blocks/interceptor/notification.interceptor.ts @@ -0,0 +1,34 @@ +import { JhiAlertService } from 'ng-jhipster'; +import { HttpInterceptor, HttpRequest, HttpResponse, HttpHandler, HttpEvent } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; + +@Injectable() +export class NotificationInterceptor implements HttpInterceptor { + constructor(private alertService: JhiAlertService) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request).pipe( + tap( + (event: HttpEvent) => { + if (event instanceof HttpResponse) { + const arr = event.headers.keys(); + let alert = null; + arr.forEach(entry => { + if (entry.toLowerCase().endsWith('app-alert')) { + alert = event.headers.get(entry); + } + }); + if (alert) { + if (typeof alert === 'string') { + this.alertService.success(alert, null, null); + } + } + } + }, + (err: any) => {} + ) + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/account.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/account.service.ts new file mode 100644 index 0000000000..a6548f6dd9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/account.service.ts @@ -0,0 +1,108 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable, Subject } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; +import { Account } from 'app/core/user/account.model'; + +@Injectable({ providedIn: 'root' }) +export class AccountService { + private userIdentity: any; + private authenticated = false; + private authenticationState = new Subject(); + + constructor(private http: HttpClient) {} + + fetch(): Observable> { + return this.http.get(SERVER_API_URL + 'api/account', { observe: 'response' }); + } + + save(account: any): Observable> { + return this.http.post(SERVER_API_URL + 'api/account', account, { observe: 'response' }); + } + + authenticate(identity) { + this.userIdentity = identity; + this.authenticated = identity !== null; + this.authenticationState.next(this.userIdentity); + } + + hasAnyAuthority(authorities: string[]): boolean { + if (!this.authenticated || !this.userIdentity || !this.userIdentity.authorities) { + return false; + } + + for (let i = 0; i < authorities.length; i++) { + if (this.userIdentity.authorities.includes(authorities[i])) { + return true; + } + } + + return false; + } + + hasAuthority(authority: string): Promise { + if (!this.authenticated) { + return Promise.resolve(false); + } + + return this.identity().then( + id => { + return Promise.resolve(id.authorities && id.authorities.includes(authority)); + }, + () => { + return Promise.resolve(false); + } + ); + } + + identity(force?: boolean): Promise { + if (force) { + this.userIdentity = undefined; + } + + // check and see if we have retrieved the userIdentity data from the server. + // if we have, reuse it by immediately resolving + if (this.userIdentity) { + return Promise.resolve(this.userIdentity); + } + + // retrieve the userIdentity data from the server, update the identity object, and then resolve. + return this.fetch() + .toPromise() + .then(response => { + const account = response.body; + if (account) { + this.userIdentity = account; + this.authenticated = true; + } else { + this.userIdentity = null; + this.authenticated = false; + } + this.authenticationState.next(this.userIdentity); + return this.userIdentity; + }) + .catch(err => { + this.userIdentity = null; + this.authenticated = false; + this.authenticationState.next(this.userIdentity); + return null; + }); + } + + isAuthenticated(): boolean { + return this.authenticated; + } + + isIdentityResolved(): boolean { + return this.userIdentity !== undefined; + } + + getAuthenticationState(): Observable { + return this.authenticationState.asObservable(); + } + + getImageUrl(): string { + return this.isIdentityResolved() ? this.userIdentity.imageUrl : null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/auth-jwt.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/auth-jwt.service.ts new file mode 100644 index 0000000000..5ad53e3dfe --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/auth-jwt.service.ts @@ -0,0 +1,59 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; + +import { SERVER_API_URL } from 'app/app.constants'; + +@Injectable({ providedIn: 'root' }) +export class AuthServerProvider { + constructor(private http: HttpClient, private $localStorage: LocalStorageService, private $sessionStorage: SessionStorageService) {} + + getToken() { + return this.$localStorage.retrieve('authenticationToken') || this.$sessionStorage.retrieve('authenticationToken'); + } + + login(credentials): Observable { + const data = { + username: credentials.username, + password: credentials.password, + rememberMe: credentials.rememberMe + }; + return this.http.post(SERVER_API_URL + 'api/authenticate', data, { observe: 'response' }).pipe(map(authenticateSuccess.bind(this))); + + function authenticateSuccess(resp) { + const bearerToken = resp.headers.get('Authorization'); + if (bearerToken && bearerToken.slice(0, 7) === 'Bearer ') { + const jwt = bearerToken.slice(7, bearerToken.length); + this.storeAuthenticationToken(jwt, credentials.rememberMe); + return jwt; + } + } + } + + loginWithToken(jwt, rememberMe) { + if (jwt) { + this.storeAuthenticationToken(jwt, rememberMe); + return Promise.resolve(jwt); + } else { + return Promise.reject('auth-jwt-service Promise reject'); // Put appropriate error message here + } + } + + storeAuthenticationToken(jwt, rememberMe) { + if (rememberMe) { + this.$localStorage.store('authenticationToken', jwt); + } else { + this.$sessionStorage.store('authenticationToken', jwt); + } + } + + logout(): Observable { + return new Observable(observer => { + this.$localStorage.clear('authenticationToken'); + this.$sessionStorage.clear('authenticationToken'); + observer.complete(); + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/csrf.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/csrf.service.ts new file mode 100644 index 0000000000..01fdccb02a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/csrf.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@angular/core'; +import { CookieService } from 'ngx-cookie'; + +@Injectable({ providedIn: 'root' }) +export class CSRFService { + constructor(private cookieService: CookieService) {} + + getCSRF(name = 'XSRF-TOKEN') { + return this.cookieService.get(name); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/state-storage.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/state-storage.service.ts new file mode 100644 index 0000000000..0e5befbfc3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/state-storage.service.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@angular/core'; +import { SessionStorageService } from 'ngx-webstorage'; + +@Injectable({ providedIn: 'root' }) +export class StateStorageService { + constructor(private $sessionStorage: SessionStorageService) {} + + getPreviousState() { + return this.$sessionStorage.retrieve('previousState'); + } + + resetPreviousState() { + this.$sessionStorage.clear('previousState'); + } + + storePreviousState(previousStateName, previousStateParams) { + const previousState = { name: previousStateName, params: previousStateParams }; + this.$sessionStorage.store('previousState', previousState); + } + + getDestinationState() { + return this.$sessionStorage.retrieve('destinationState'); + } + + storeUrl(url: string) { + this.$sessionStorage.store('previousUrl', url); + } + + getUrl() { + return this.$sessionStorage.retrieve('previousUrl'); + } + + storeDestinationState(destinationState, destinationStateParams, fromState) { + const destinationInfo = { + destination: { + name: destinationState.name, + data: destinationState.data + }, + params: destinationStateParams, + from: { + name: fromState.name + } + }; + this.$sessionStorage.store('destinationState', destinationInfo); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/user-route-access-service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/user-route-access-service.ts new file mode 100644 index 0000000000..a55b0bc035 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/auth/user-route-access-service.ts @@ -0,0 +1,52 @@ +import { Injectable, isDevMode } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; + +import { AccountService } from '../'; +import { LoginModalService } from '../login/login-modal.service'; +import { StateStorageService } from './state-storage.service'; + +@Injectable({ providedIn: 'root' }) +export class UserRouteAccessService implements CanActivate { + constructor( + private router: Router, + private loginModalService: LoginModalService, + private accountService: AccountService, + private stateStorageService: StateStorageService + ) {} + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Promise { + const authorities = route.data['authorities']; + // We need to call the checkLogin / and so the accountService.identity() function, to ensure, + // that the client has a principal too, if they already logged in by the server. + // This could happen on a page refresh. + return this.checkLogin(authorities, state.url); + } + + checkLogin(authorities: string[], url: string): Promise { + return this.accountService.identity().then(account => { + if (!authorities || authorities.length === 0) { + return true; + } + + if (account) { + const hasAnyAuthority = this.accountService.hasAnyAuthority(authorities); + if (hasAnyAuthority) { + return true; + } + if (isDevMode()) { + console.error('User has not any of required authorities: ', authorities); + } + return false; + } + + this.stateStorageService.storeUrl(url); + this.router.navigate(['accessdenied']).then(() => { + // only show the login dialog, if the user hasn't logged in yet + if (!account) { + this.loginModalService.open(); + } + }); + return false; + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/core.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/core.module.ts new file mode 100644 index 0000000000..7569b8f59e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/core.module.ts @@ -0,0 +1,24 @@ +import { NgModule, LOCALE_ID } from '@angular/core'; +import { DatePipe, registerLocaleData } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { Title } from '@angular/platform-browser'; +import locale from '@angular/common/locales/en'; + +@NgModule({ + imports: [HttpClientModule], + exports: [], + declarations: [], + providers: [ + Title, + { + provide: LOCALE_ID, + useValue: 'en' + }, + DatePipe + ] +}) +export class BookstoreCoreModule { + constructor() { + registerLocaleData(locale); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/index.ts new file mode 100644 index 0000000000..38827443a5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/index.ts @@ -0,0 +1,11 @@ +export * from './auth/csrf.service'; +export * from './auth/state-storage.service'; +export * from './auth/account.service'; +export * from './auth/auth-jwt.service'; +export * from './user/account.model'; +export * from './user/user.model'; +export * from './auth/user-route-access-service'; +export * from './login/login-modal.service'; +export * from './login/login.service'; +export * from './user/user.service'; +export * from './core.module'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login-modal.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login-modal.service.ts new file mode 100644 index 0000000000..a0002aa56b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login-modal.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; + +import { JhiLoginModalComponent } from 'app/shared/login/login.component'; + +@Injectable({ providedIn: 'root' }) +export class LoginModalService { + private isOpen = false; + constructor(private modalService: NgbModal) {} + + open(): NgbModalRef { + if (this.isOpen) { + return; + } + this.isOpen = true; + const modalRef = this.modalService.open(JhiLoginModalComponent); + modalRef.result.then( + result => { + this.isOpen = false; + }, + reason => { + this.isOpen = false; + } + ); + return modalRef; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login.service.ts new file mode 100644 index 0000000000..e91508ff44 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/login/login.service.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; + +import { AccountService } from 'app/core/auth/account.service'; +import { AuthServerProvider } from 'app/core/auth/auth-jwt.service'; + +@Injectable({ providedIn: 'root' }) +export class LoginService { + constructor(private accountService: AccountService, private authServerProvider: AuthServerProvider) {} + + login(credentials, callback?) { + const cb = callback || function() {}; + + return new Promise((resolve, reject) => { + this.authServerProvider.login(credentials).subscribe( + data => { + this.accountService.identity(true).then(account => { + resolve(data); + }); + return cb(); + }, + err => { + this.logout(); + reject(err); + return cb(err); + } + ); + }); + } + + loginWithToken(jwt, rememberMe) { + return this.authServerProvider.loginWithToken(jwt, rememberMe); + } + + logout() { + this.authServerProvider.logout().subscribe(); + this.accountService.authenticate(null); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/account.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/account.model.ts new file mode 100644 index 0000000000..35679657e3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/account.model.ts @@ -0,0 +1,12 @@ +export class Account { + constructor( + public activated: boolean, + public authorities: string[], + public email: string, + public firstName: string, + public langKey: string, + public lastName: string, + public login: string, + public imageUrl: string + ) {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.model.ts new file mode 100644 index 0000000000..e82da11ac5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.model.ts @@ -0,0 +1,47 @@ +export interface IUser { + id?: any; + login?: string; + firstName?: string; + lastName?: string; + email?: string; + activated?: boolean; + langKey?: string; + authorities?: any[]; + createdBy?: string; + createdDate?: Date; + lastModifiedBy?: string; + lastModifiedDate?: Date; + password?: string; +} + +export class User implements IUser { + constructor( + public id?: any, + public login?: string, + public firstName?: string, + public lastName?: string, + public email?: string, + public activated?: boolean, + public langKey?: string, + public authorities?: any[], + public createdBy?: string, + public createdDate?: Date, + public lastModifiedBy?: string, + public lastModifiedDate?: Date, + public password?: string + ) { + this.id = id ? id : null; + this.login = login ? login : null; + this.firstName = firstName ? firstName : null; + this.lastName = lastName ? lastName : null; + this.email = email ? email : null; + this.activated = activated ? activated : false; + this.langKey = langKey ? langKey : null; + this.authorities = authorities ? authorities : null; + this.createdBy = createdBy ? createdBy : null; + this.createdDate = createdDate ? createdDate : null; + this.lastModifiedBy = lastModifiedBy ? lastModifiedBy : null; + this.lastModifiedDate = lastModifiedDate ? lastModifiedDate : null; + this.password = password ? password : null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.service.ts new file mode 100644 index 0000000000..5c8065bedd --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/core/user/user.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { SERVER_API_URL } from 'app/app.constants'; +import { createRequestOption } from 'app/shared/util/request-util'; +import { IUser } from './user.model'; + +@Injectable({ providedIn: 'root' }) +export class UserService { + public resourceUrl = SERVER_API_URL + 'api/users'; + + constructor(private http: HttpClient) {} + + create(user: IUser): Observable> { + return this.http.post(this.resourceUrl, user, { observe: 'response' }); + } + + update(user: IUser): Observable> { + return this.http.put(this.resourceUrl, user, { observe: 'response' }); + } + + find(login: string): Observable> { + return this.http.get(`${this.resourceUrl}/${login}`, { observe: 'response' }); + } + + query(req?: any): Observable> { + const options = createRequestOption(req); + return this.http.get(this.resourceUrl, { params: options, observe: 'response' }); + } + + delete(login: string): Observable> { + return this.http.delete(`${this.resourceUrl}/${login}`, { observe: 'response' }); + } + + authorities(): Observable { + return this.http.get(SERVER_API_URL + 'api/users/authorities'); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.html new file mode 100644 index 0000000000..be3647e9df --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.html @@ -0,0 +1,19 @@ +
+ + + +
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.ts new file mode 100644 index 0000000000..7992a5d26d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-delete-dialog.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { JhiEventManager } from 'ng-jhipster'; + +import { IBook } from 'app/shared/model/book.model'; +import { BookService } from './book.service'; + +@Component({ + selector: 'jhi-book-delete-dialog', + templateUrl: './book-delete-dialog.component.html' +}) +export class BookDeleteDialogComponent { + book: IBook; + + constructor(protected bookService: BookService, public activeModal: NgbActiveModal, protected eventManager: JhiEventManager) {} + + clear() { + this.activeModal.dismiss('cancel'); + } + + confirmDelete(id: number) { + this.bookService.delete(id).subscribe(response => { + this.eventManager.broadcast({ + name: 'bookListModification', + content: 'Deleted an book' + }); + this.activeModal.dismiss(true); + }); + } +} + +@Component({ + selector: 'jhi-book-delete-popup', + template: '' +}) +export class BookDeletePopupComponent implements OnInit, OnDestroy { + protected ngbModalRef: NgbModalRef; + + constructor(protected activatedRoute: ActivatedRoute, protected router: Router, protected modalService: NgbModal) {} + + ngOnInit() { + this.activatedRoute.data.subscribe(({ book }) => { + setTimeout(() => { + this.ngbModalRef = this.modalService.open(BookDeleteDialogComponent as Component, { size: 'lg', backdrop: 'static' }); + this.ngbModalRef.componentInstance.book = book; + this.ngbModalRef.result.then( + result => { + this.router.navigate(['/book', { outlets: { popup: null } }]); + this.ngbModalRef = null; + }, + reason => { + this.router.navigate(['/book', { outlets: { popup: null } }]); + this.ngbModalRef = null; + } + ); + }, 0); + }); + } + + ngOnDestroy() { + this.ngbModalRef = null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.html new file mode 100644 index 0000000000..4a3c20e841 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.html @@ -0,0 +1,49 @@ +
+
+
+

Book {{book.id}}

+
+ +
+
Title
+
+ {{book.title}} +
+
Author
+
+ {{book.author}} +
+
Published
+
+ {{book.published}} +
+
Quantity
+
+ {{book.quantity}} +
+
Price
+
+ {{book.price}} +
+
+ + + + + + +
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.ts new file mode 100644 index 0000000000..6b84c0ba73 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-detail.component.ts @@ -0,0 +1,36 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { IBook } from 'app/shared/model/book.model'; +import { BookService } from 'app/entities/book/book.service'; +import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; + +@Component({ + selector: 'jhi-book-detail', + templateUrl: './book-detail.component.html' +}) +export class BookDetailComponent implements OnInit { + book: IBook; + + constructor(protected activatedRoute: ActivatedRoute, protected bookService: BookService) {} + + ngOnInit() { + this.activatedRoute.data.subscribe(({ book }) => { + this.book = book; + }); + } + + previousState() { + window.history.back(); + } + + purchase(id: number) { + console.log('Purchasing book ' + id); + this.bookService.purchase(id).subscribe( + (res: HttpResponse) => { + this.book = res.body; + }, + (res: HttpErrorResponse) => console.log(res.message) + ); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.html new file mode 100644 index 0000000000..3b41c6e1e0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.html @@ -0,0 +1,100 @@ +
+
+
+

Create or edit a Book

+
+ +
+ + +
+
+ + +
+ + This field is required. + +
+
+
+ + +
+ + This field is required. + +
+
+
+ +
+ + + + +
+
+ + This field is required. + +
+
+
+ + +
+ + This field is required. + + + This field should be at least 0. + + + This field should be a number. + +
+
+
+ + +
+ + This field is required. + + + This field should be at least 0. + + + This field should be a number. + +
+
+ +
+
+ + +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.ts new file mode 100644 index 0000000000..67f46a67c2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book-update.component.ts @@ -0,0 +1,53 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; +import * as moment from 'moment'; +import { IBook } from 'app/shared/model/book.model'; +import { BookService } from './book.service'; + +@Component({ + selector: 'jhi-book-update', + templateUrl: './book-update.component.html' +}) +export class BookUpdateComponent implements OnInit { + book: IBook; + isSaving: boolean; + publishedDp: any; + + constructor(protected bookService: BookService, protected activatedRoute: ActivatedRoute) {} + + ngOnInit() { + this.isSaving = false; + this.activatedRoute.data.subscribe(({ book }) => { + this.book = book; + }); + } + + previousState() { + window.history.back(); + } + + save() { + this.isSaving = true; + if (this.book.id !== undefined) { + this.subscribeToSaveResponse(this.bookService.update(this.book)); + } else { + this.subscribeToSaveResponse(this.bookService.create(this.book)); + } + } + + protected subscribeToSaveResponse(result: Observable>) { + result.subscribe((res: HttpResponse) => this.onSaveSuccess(), (res: HttpErrorResponse) => this.onSaveError()); + } + + protected onSaveSuccess() { + this.isSaving = false; + this.previousState(); + } + + protected onSaveError() { + this.isSaving = false; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.html new file mode 100644 index 0000000000..74ad02a8e3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.html @@ -0,0 +1,62 @@ +
+

+ Books + +

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
IDTitleAuthorPublishedQuantityPrice
{{book.id}}{{book.title}}{{book.author}}{{book.published | date:'mediumDate'}}{{book.quantity}}{{book.price}} +
+ + + +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.ts new file mode 100644 index 0000000000..91a71c2f5c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; +import { Subscription } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; +import { JhiEventManager, JhiAlertService } from 'ng-jhipster'; + +import { IBook } from 'app/shared/model/book.model'; +import { AccountService } from 'app/core'; +import { BookService } from './book.service'; + +@Component({ + selector: 'jhi-book', + templateUrl: './book.component.html' +}) +export class BookComponent implements OnInit, OnDestroy { + books: IBook[]; + currentAccount: any; + eventSubscriber: Subscription; + + constructor( + protected bookService: BookService, + protected jhiAlertService: JhiAlertService, + protected eventManager: JhiEventManager, + protected accountService: AccountService + ) {} + + loadAll() { + this.bookService + .query() + .pipe( + filter((res: HttpResponse) => res.ok), + map((res: HttpResponse) => res.body) + ) + .subscribe( + (res: IBook[]) => { + this.books = res; + }, + (res: HttpErrorResponse) => this.onError(res.message) + ); + } + + ngOnInit() { + this.loadAll(); + this.accountService.identity().then(account => { + this.currentAccount = account; + }); + this.registerChangeInBooks(); + } + + ngOnDestroy() { + this.eventManager.destroy(this.eventSubscriber); + } + + trackId(index: number, item: IBook) { + return item.id; + } + + registerChangeInBooks() { + this.eventSubscriber = this.eventManager.subscribe('bookListModification', response => this.loadAll()); + } + + protected onError(errorMessage: string) { + this.jhiAlertService.error(errorMessage, null, null); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.module.ts new file mode 100644 index 0000000000..fe221a0eb9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.module.ts @@ -0,0 +1,23 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { BookstoreSharedModule } from 'app/shared'; +import { + BookComponent, + BookDetailComponent, + BookUpdateComponent, + BookDeletePopupComponent, + BookDeleteDialogComponent, + bookRoute, + bookPopupRoute +} from './'; + +const ENTITY_STATES = [...bookRoute, ...bookPopupRoute]; + +@NgModule({ + imports: [BookstoreSharedModule, RouterModule.forChild(ENTITY_STATES)], + declarations: [BookComponent, BookDetailComponent, BookUpdateComponent, BookDeleteDialogComponent, BookDeletePopupComponent], + entryComponents: [BookComponent, BookUpdateComponent, BookDeleteDialogComponent, BookDeletePopupComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreBookModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.route.ts new file mode 100644 index 0000000000..154fa89a5c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.route.ts @@ -0,0 +1,93 @@ +import { Injectable } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Routes } from '@angular/router'; +import { UserRouteAccessService } from 'app/core'; +import { Observable, of } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; +import { Book } from 'app/shared/model/book.model'; +import { BookService } from './book.service'; +import { BookComponent } from './book.component'; +import { BookDetailComponent } from './book-detail.component'; +import { BookUpdateComponent } from './book-update.component'; +import { BookDeletePopupComponent } from './book-delete-dialog.component'; +import { IBook } from 'app/shared/model/book.model'; + +@Injectable({ providedIn: 'root' }) +export class BookResolve implements Resolve { + constructor(private service: BookService) {} + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + const id = route.params['id'] ? route.params['id'] : null; + if (id) { + return this.service.find(id).pipe( + filter((response: HttpResponse) => response.ok), + map((book: HttpResponse) => book.body) + ); + } + return of(new Book()); + } +} + +export const bookRoute: Routes = [ + { + path: '', + component: BookComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Books' + }, + canActivate: [UserRouteAccessService] + }, + { + path: ':id/view', + component: BookDetailComponent, + resolve: { + book: BookResolve + }, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Books' + }, + canActivate: [UserRouteAccessService] + }, + { + path: 'new', + component: BookUpdateComponent, + resolve: { + book: BookResolve + }, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Books' + }, + canActivate: [UserRouteAccessService] + }, + { + path: ':id/edit', + component: BookUpdateComponent, + resolve: { + book: BookResolve + }, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Books' + }, + canActivate: [UserRouteAccessService] + } +]; + +export const bookPopupRoute: Routes = [ + { + path: ':id/delete', + component: BookDeletePopupComponent, + resolve: { + book: BookResolve + }, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'Books' + }, + canActivate: [UserRouteAccessService], + outlet: 'popup' + } +]; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.service.ts new file mode 100644 index 0000000000..bff511f7e6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/book.service.ts @@ -0,0 +1,81 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import * as moment from 'moment'; +import { DATE_FORMAT } from 'app/shared/constants/input.constants'; +import { map } from 'rxjs/operators'; + +import { SERVER_API_URL } from 'app/app.constants'; +import { createRequestOption } from 'app/shared'; +import { IBook } from 'app/shared/model/book.model'; + +type EntityResponseType = HttpResponse; +type EntityArrayResponseType = HttpResponse; + +@Injectable({ providedIn: 'root' }) +export class BookService { + public resourceUrl = SERVER_API_URL + 'api/books'; + + constructor(protected http: HttpClient) {} + + create(book: IBook): Observable { + const copy = this.convertDateFromClient(book); + return this.http + .post(this.resourceUrl, copy, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + update(book: IBook): Observable { + const copy = this.convertDateFromClient(book); + return this.http + .put(this.resourceUrl, copy, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + find(id: number): Observable { + return this.http + .get(`${this.resourceUrl}/${id}`, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + purchase(id: number): Observable { + console.log('Calling /api/books/purchase/ ' + id); + return this.http + .get(`${this.resourceUrl}/purchase/${id}`, { observe: 'response' }) + .pipe(map((res: EntityResponseType) => this.convertDateFromServer(res))); + } + + query(req?: any): Observable { + const options = createRequestOption(req); + return this.http + .get(this.resourceUrl, { params: options, observe: 'response' }) + .pipe(map((res: EntityArrayResponseType) => this.convertDateArrayFromServer(res))); + } + + delete(id: number): Observable> { + return this.http.delete(`${this.resourceUrl}/${id}`, { observe: 'response' }); + } + + protected convertDateFromClient(book: IBook): IBook { + const copy: IBook = Object.assign({}, book, { + published: book.published != null && book.published.isValid() ? book.published.format(DATE_FORMAT) : null + }); + return copy; + } + + protected convertDateFromServer(res: EntityResponseType): EntityResponseType { + if (res.body) { + res.body.published = res.body.published != null ? moment(res.body.published) : null; + } + return res; + } + + protected convertDateArrayFromServer(res: EntityArrayResponseType): EntityArrayResponseType { + if (res.body) { + res.body.forEach((book: IBook) => { + book.published = book.published != null ? moment(book.published) : null; + }); + } + return res; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/index.ts new file mode 100644 index 0000000000..603cf68f9f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/book/index.ts @@ -0,0 +1,6 @@ +export * from './book.service'; +export * from './book-update.component'; +export * from './book-delete-dialog.component'; +export * from './book-detail.component'; +export * from './book.component'; +export * from './book.route'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/entity.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/entity.module.ts new file mode 100644 index 0000000000..fba1f55ef7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/entities/entity.module.ts @@ -0,0 +1,19 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +@NgModule({ + imports: [ + RouterModule.forChild([ + { + path: 'book', + loadChildren: './book/book.module#BookstoreBookModule' + } + /* jhipster-needle-add-entity-route - JHipster will add entity modules routes here */ + ]) + ], + declarations: [], + entryComponents: [], + providers: [], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreEntityModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.html new file mode 100644 index 0000000000..0c595b9d74 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.html @@ -0,0 +1,41 @@ +
+
+ +
+
+

Welcome, Java Hipster!

+

This is your homepage

+ +
+
+ You are logged in as user "{{account.login}}". +
+ +
+ If you want to + sign in, you can try the default accounts:
- Administrator (login="admin" and password="admin")
- User (login="user" and password="user").
+
+
+ You don't have an account yet?  + Register a new account +
+
+ +

+ If you have any question on JHipster: +

+ + + +

+ If you like JHipster, don't forget to give us a star on GitHub! +

+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.ts new file mode 100644 index 0000000000..f1410c2cf5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.component.ts @@ -0,0 +1,44 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { JhiEventManager } from 'ng-jhipster'; + +import { LoginModalService, AccountService, Account } from 'app/core'; + +@Component({ + selector: 'jhi-home', + templateUrl: './home.component.html', + styleUrls: ['home.scss'] +}) +export class HomeComponent implements OnInit { + account: Account; + modalRef: NgbModalRef; + + constructor( + private accountService: AccountService, + private loginModalService: LoginModalService, + private eventManager: JhiEventManager + ) {} + + ngOnInit() { + this.accountService.identity().then((account: Account) => { + this.account = account; + }); + this.registerAuthenticationSuccess(); + } + + registerAuthenticationSuccess() { + this.eventManager.subscribe('authenticationSuccess', message => { + this.accountService.identity().then(account => { + this.account = account; + }); + }); + } + + isAuthenticated() { + return this.accountService.isAuthenticated(); + } + + login() { + this.modalRef = this.loginModalService.open(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.module.ts new file mode 100644 index 0000000000..c1004a6dd9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.module.ts @@ -0,0 +1,12 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { BookstoreSharedModule } from 'app/shared'; +import { HOME_ROUTE, HomeComponent } from './'; + +@NgModule({ + imports: [BookstoreSharedModule, RouterModule.forChild([HOME_ROUTE])], + declarations: [HomeComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreHomeModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.route.ts new file mode 100644 index 0000000000..a59993f8f0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { HomeComponent } from './'; + +export const HOME_ROUTE: Route = { + path: '', + component: HomeComponent, + data: { + authorities: [], + pageTitle: 'Welcome, Java Hipster!' + } +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.scss b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.scss new file mode 100644 index 0000000000..7fe48ff5fa --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/home.scss @@ -0,0 +1,23 @@ +/* ========================================================================== +Main page styles +========================================================================== */ + +.hipster { + display: inline-block; + width: 347px; + height: 497px; + background: url('../../content/images/jhipster_family_member_0.svg') no-repeat center top; + background-size: contain; +} + +/* wait autoprefixer update to allow simple generation of high pixel density media query */ +@media only screen and (-webkit-min-device-pixel-ratio: 2), + only screen and (-moz-min-device-pixel-ratio: 2), + only screen and (-o-min-device-pixel-ratio: 2/1), + only screen and (min-resolution: 192dpi), + only screen and (min-resolution: 2dppx) { + .hipster { + background: url('../../content/images/jhipster_family_member_0.svg') no-repeat center top; + background-size: contain; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/home/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/index.ts new file mode 100644 index 0000000000..d76285b277 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/home/index.ts @@ -0,0 +1,3 @@ +export * from './home.component'; +export * from './home.route'; +export * from './home.module'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.html new file mode 100644 index 0000000000..b79392173e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.html @@ -0,0 +1,19 @@ +
+
+
+ +
+
+

Error Page!

+ +
+
{{errorMessage}} +
+
+
You are not authorized to access this page. +
+
The page asked was not found. +
+
+
+
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.ts new file mode 100644 index 0000000000..faa9658161 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.component.ts @@ -0,0 +1,28 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + selector: 'jhi-error', + templateUrl: './error.component.html' +}) +export class ErrorComponent implements OnInit { + errorMessage: string; + error403: boolean; + error404: boolean; + + constructor(private route: ActivatedRoute) {} + + ngOnInit() { + this.route.data.subscribe(routeData => { + if (routeData.error403) { + this.error403 = routeData.error403; + } + if (routeData.error404) { + this.error404 = routeData.error404; + } + if (routeData.errorMessage) { + this.errorMessage = routeData.errorMessage; + } + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.route.ts new file mode 100644 index 0000000000..85ab257ca9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/error/error.route.ts @@ -0,0 +1,36 @@ +import { Routes } from '@angular/router'; + +import { ErrorComponent } from './error.component'; + +export const errorRoute: Routes = [ + { + path: 'error', + component: ErrorComponent, + data: { + authorities: [], + pageTitle: 'Bookstore' + } + }, + { + path: 'accessdenied', + component: ErrorComponent, + data: { + authorities: [], + pageTitle: 'Bookstore', + error403: true + } + }, + { + path: '404', + component: ErrorComponent, + data: { + authorities: [], + pageTitle: 'Bookstore', + error404: true + } + }, + { + path: '**', + redirectTo: '/404' + } +]; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.html new file mode 100644 index 0000000000..b3ba632e02 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.html @@ -0,0 +1,3 @@ + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.ts new file mode 100644 index 0000000000..37da8bca75 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/footer/footer.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'jhi-footer', + templateUrl: './footer.component.html' +}) +export class FooterComponent {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/index.ts new file mode 100644 index 0000000000..8cbf6368d7 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/index.ts @@ -0,0 +1,9 @@ +export * from './error/error.component'; +export * from './error/error.route'; +export * from './main/main.component'; +export * from './footer/footer.component'; +export * from './navbar/navbar.component'; +export * from './navbar/navbar.route'; +export * from './profiles/page-ribbon.component'; +export * from './profiles/profile.service'; +export * from './profiles/profile-info.model'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.html new file mode 100644 index 0000000000..5bcd12ab0b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.html @@ -0,0 +1,11 @@ + +
+ +
+
+
+ + +
+ +
diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.ts new file mode 100644 index 0000000000..e1f2c8134e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/main/main.component.ts @@ -0,0 +1,31 @@ +import { Component, OnInit } from '@angular/core'; +import { Router, ActivatedRouteSnapshot, NavigationEnd, NavigationError } from '@angular/router'; + +import { Title } from '@angular/platform-browser'; + +@Component({ + selector: 'jhi-main', + templateUrl: './main.component.html' +}) +export class JhiMainComponent implements OnInit { + constructor(private titleService: Title, private router: Router) {} + + private getPageTitle(routeSnapshot: ActivatedRouteSnapshot) { + let title: string = routeSnapshot.data && routeSnapshot.data['pageTitle'] ? routeSnapshot.data['pageTitle'] : 'bookstoreApp'; + if (routeSnapshot.firstChild) { + title = this.getPageTitle(routeSnapshot.firstChild) || title; + } + return title; + } + + ngOnInit() { + this.router.events.subscribe(event => { + if (event instanceof NavigationEnd) { + this.titleService.setTitle(this.getPageTitle(this.router.routerState.snapshot.root)); + } + if (event instanceof NavigationError && event.error.status === 404) { + this.router.navigate(['/404']); + } + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.html new file mode 100644 index 0000000000..e58d234c22 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.html @@ -0,0 +1,145 @@ + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.ts new file mode 100644 index 0000000000..6e00d7a1cb --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; + +import { VERSION } from 'app/app.constants'; +import { AccountService, LoginModalService, LoginService } from 'app/core'; +import { ProfileService } from 'app/layouts/profiles/profile.service'; + +@Component({ + selector: 'jhi-navbar', + templateUrl: './navbar.component.html', + styleUrls: ['navbar.scss'] +}) +export class NavbarComponent implements OnInit { + inProduction: boolean; + isNavbarCollapsed: boolean; + languages: any[]; + swaggerEnabled: boolean; + modalRef: NgbModalRef; + version: string; + + constructor( + private loginService: LoginService, + private accountService: AccountService, + private loginModalService: LoginModalService, + private profileService: ProfileService, + private router: Router + ) { + this.version = VERSION ? 'v' + VERSION : ''; + this.isNavbarCollapsed = true; + } + + ngOnInit() { + this.profileService.getProfileInfo().then(profileInfo => { + this.inProduction = profileInfo.inProduction; + this.swaggerEnabled = profileInfo.swaggerEnabled; + }); + } + + collapseNavbar() { + this.isNavbarCollapsed = true; + } + + isAuthenticated() { + return this.accountService.isAuthenticated(); + } + + login() { + this.modalRef = this.loginModalService.open(); + } + + logout() { + this.collapseNavbar(); + this.loginService.logout(); + this.router.navigate(['']); + } + + toggleNavbar() { + this.isNavbarCollapsed = !this.isNavbarCollapsed; + } + + getImageUrl() { + return this.isAuthenticated() ? this.accountService.getImageUrl() : null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.route.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.route.ts new file mode 100644 index 0000000000..317d99604b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.route.ts @@ -0,0 +1,9 @@ +import { Route } from '@angular/router'; + +import { NavbarComponent } from './navbar.component'; + +export const navbarRoute: Route = { + path: '', + component: NavbarComponent, + outlet: 'navbar' +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.scss b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.scss new file mode 100644 index 0000000000..9a5f929293 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/navbar/navbar.scss @@ -0,0 +1,53 @@ +@import '~bootstrap/scss/functions'; +@import '~bootstrap/scss/variables'; + +/* ========================================================================== +Navbar +========================================================================== */ + +.navbar-version { + font-size: 0.65em; + color: $navbar-dark-color; +} + +.profile-image { + height: 1.75em; + width: 1.75em; +} + +.navbar { + padding: 0.2rem 1rem; + .dropdown-item.active, + .dropdown-item.active:focus, + .dropdown-item.active:hover { + background-color: $dark; + } + + ul.navbar-nav { + .nav-item { + margin-left: 0.5em; + } + } + + a.nav-link { + font-weight: 400; + } + + .navbar-toggler { + &:hover { + color: $navbar-dark-hover-color; + } + } +} + +/* ========================================================================== +Logo styles +========================================================================== */ +.logo-img { + height: 45px; + width: 45px; + display: inline-block; + vertical-align: middle; + background: url('../../../content/images/logo-jhipster.png') no-repeat center center; + background-size: contain; +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts new file mode 100644 index 0000000000..00fe76075d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts @@ -0,0 +1,26 @@ +import { Component, OnInit } from '@angular/core'; +import { ProfileService } from './profile.service'; +import { ProfileInfo } from './profile-info.model'; + +@Component({ + selector: 'jhi-page-ribbon', + template: ` + + `, + styleUrls: ['page-ribbon.scss'] +}) +export class PageRibbonComponent implements OnInit { + profileInfo: ProfileInfo; + ribbonEnv: string; + + constructor(private profileService: ProfileService) {} + + ngOnInit() { + this.profileService.getProfileInfo().then(profileInfo => { + this.profileInfo = profileInfo; + this.ribbonEnv = profileInfo.ribbonEnv; + }); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.scss b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.scss new file mode 100644 index 0000000000..90125b70cb --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/page-ribbon.scss @@ -0,0 +1,31 @@ +/* ========================================================================== +Developement Ribbon +========================================================================== */ +.ribbon { + background-color: rgba(170, 0, 0, 0.5); + left: -3.5em; + -moz-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + -o-transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + overflow: hidden; + position: absolute; + top: 40px; + white-space: nowrap; + width: 15em; + z-index: 9999; + pointer-events: none; + opacity: 0.75; + a { + color: #fff; + display: block; + font-weight: 400; + margin: 1px 0; + padding: 10px 50px; + text-align: center; + text-decoration: none; + text-shadow: 0 0 5px #444; + pointer-events: none; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile-info.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile-info.model.ts new file mode 100644 index 0000000000..f1adc52c7b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile-info.model.ts @@ -0,0 +1,6 @@ +export class ProfileInfo { + activeProfiles: string[]; + ribbonEnv: string; + inProduction: boolean; + swaggerEnabled: boolean; +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile.service.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile.service.ts new file mode 100644 index 0000000000..d07fad7e7f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/layouts/profiles/profile.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; + +import { SERVER_API_URL } from 'app/app.constants'; +import { ProfileInfo } from './profile-info.model'; +import { map } from 'rxjs/operators'; + +@Injectable({ providedIn: 'root' }) +export class ProfileService { + private infoUrl = SERVER_API_URL + 'management/info'; + private profileInfo: Promise; + + constructor(private http: HttpClient) {} + + getProfileInfo(): Promise { + if (!this.profileInfo) { + this.profileInfo = this.http + .get(this.infoUrl, { observe: 'response' }) + .pipe( + map((res: HttpResponse) => { + const data = res.body; + const pi = new ProfileInfo(); + pi.activeProfiles = data['activeProfiles']; + const displayRibbonOnProfiles = data['display-ribbon-on-profiles'].split(','); + if (pi.activeProfiles) { + const ribbonProfiles = displayRibbonOnProfiles.filter(profile => pi.activeProfiles.includes(profile)); + if (ribbonProfiles.length !== 0) { + pi.ribbonEnv = ribbonProfiles[0]; + } + pi.inProduction = pi.activeProfiles.includes('prod'); + pi.swaggerEnabled = pi.activeProfiles.includes('swagger'); + } + return pi; + }) + ) + .toPromise(); + } + return this.profileInfo; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/polyfills.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/polyfills.ts new file mode 100644 index 0000000000..cf38f3221b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/polyfills.ts @@ -0,0 +1,70 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +import 'core-js/es6/symbol'; +import 'core-js/es6/object'; +import 'core-js/es6/function'; +import 'core-js/es6/parse-int'; +import 'core-js/es6/parse-float'; +import 'core-js/es6/number'; +import 'core-js/es6/math'; +import 'core-js/es6/string'; +import 'core-js/es6/date'; +import 'core-js/es6/array'; +import 'core-js/es7/array'; +import 'core-js/es6/regexp'; +import 'core-js/es6/map'; +import 'core-js/es6/weak-map'; +import 'core-js/es6/set'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** Evergreen browsers require these. **/ +import 'core-js/es6/reflect'; +import 'core-js/es7/reflect'; + +/** + * Required to support Web Animations `@angular/animation`. + * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/*************************************************************************************************** + * Zone JS is required by Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ + +/** + * Date, currency, decimal and percent pipes. + * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 + */ +// import 'intl'; // Run `npm install --save intl`. +/** + * Need to import at least one locale-data with intl. + */ +// import 'intl/locale-data/jsonp/en'; + +require('../manifest.webapp'); diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert-error.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert-error.component.ts new file mode 100644 index 0000000000..892e2d828c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert-error.component.ts @@ -0,0 +1,110 @@ +import { Component, OnDestroy } from '@angular/core'; +import { JhiEventManager, JhiAlert, JhiAlertService } from 'ng-jhipster'; +import { Subscription } from 'rxjs'; + +@Component({ + selector: 'jhi-alert-error', + template: ` + + ` +}) +export class JhiAlertErrorComponent implements OnDestroy { + alerts: any[]; + cleanHttpErrorListener: Subscription; + /* tslint:disable */ + constructor(private alertService: JhiAlertService, private eventManager: JhiEventManager) { + /* tslint:enable */ + this.alerts = []; + + this.cleanHttpErrorListener = eventManager.subscribe('bookstoreApp.httpError', response => { + let i; + const httpErrorResponse = response.content; + switch (httpErrorResponse.status) { + // connection refused, server not reachable + case 0: + this.addErrorAlert('Server not reachable', 'error.server.not.reachable'); + break; + + case 400: + const arr = httpErrorResponse.headers.keys(); + let errorHeader = null; + let entityKey = null; + arr.forEach(entry => { + if (entry.toLowerCase().endsWith('app-error')) { + errorHeader = httpErrorResponse.headers.get(entry); + } else if (entry.toLowerCase().endsWith('app-params')) { + entityKey = httpErrorResponse.headers.get(entry); + } + }); + if (errorHeader) { + const entityName = entityKey; + this.addErrorAlert(errorHeader, errorHeader, { entityName }); + } else if (httpErrorResponse.error !== '' && httpErrorResponse.error.fieldErrors) { + const fieldErrors = httpErrorResponse.error.fieldErrors; + for (i = 0; i < fieldErrors.length; i++) { + const fieldError = fieldErrors[i]; + if (['Min', 'Max', 'DecimalMin', 'DecimalMax'].includes(fieldError.message)) { + fieldError.message = 'Size'; + } + // convert 'something[14].other[4].id' to 'something[].other[].id' so translations can be written to it + const convertedField = fieldError.field.replace(/\[\d*\]/g, '[]'); + const fieldName = convertedField.charAt(0).toUpperCase() + convertedField.slice(1); + this.addErrorAlert('Error on field "' + fieldName + '"', 'error.' + fieldError.message, { fieldName }); + } + } else if (httpErrorResponse.error !== '' && httpErrorResponse.error.message) { + this.addErrorAlert( + httpErrorResponse.error.message, + httpErrorResponse.error.message, + httpErrorResponse.error.params + ); + } else { + this.addErrorAlert(httpErrorResponse.error); + } + break; + + case 404: + this.addErrorAlert('Not found', 'error.url.not.found'); + break; + + default: + if (httpErrorResponse.error !== '' && httpErrorResponse.error.message) { + this.addErrorAlert(httpErrorResponse.error.message); + } else { + this.addErrorAlert(httpErrorResponse.error); + } + } + }); + } + + setClasses(alert) { + return { + toast: !!alert.toast, + [alert.position]: true + }; + } + + ngOnDestroy() { + if (this.cleanHttpErrorListener !== undefined && this.cleanHttpErrorListener !== null) { + this.eventManager.destroy(this.cleanHttpErrorListener); + this.alerts = []; + } + } + + addErrorAlert(message, key?, data?) { + const newAlert: JhiAlert = { + type: 'danger', + msg: message, + timeout: 5000, + toast: this.alertService.isToast(), + scoped: true + }; + + this.alerts.push(this.alertService.addAlert(newAlert, this.alerts)); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert.component.ts new file mode 100644 index 0000000000..a77c3e72c5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/alert/alert.component.ts @@ -0,0 +1,35 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { JhiAlertService } from 'ng-jhipster'; + +@Component({ + selector: 'jhi-alert', + template: ` + + ` +}) +export class JhiAlertComponent implements OnInit, OnDestroy { + alerts: any[]; + + constructor(private alertService: JhiAlertService) {} + + ngOnInit() { + this.alerts = this.alertService.get(); + } + + setClasses(alert) { + return { + toast: !!alert.toast, + [alert.position]: true + }; + } + + ngOnDestroy() { + this.alerts = []; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/auth/has-any-authority.directive.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/auth/has-any-authority.directive.ts new file mode 100644 index 0000000000..0f8cefb28e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/auth/has-any-authority.directive.ts @@ -0,0 +1,42 @@ +import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core'; +import { AccountService } from 'app/core/auth/account.service'; + +/** + * @whatItDoes Conditionally includes an HTML element if current user has any + * of the authorities passed as the `expression`. + * + * @howToUse + * ``` + * ... + * + * ... + * ``` + */ +@Directive({ + selector: '[jhiHasAnyAuthority]' +}) +export class HasAnyAuthorityDirective { + private authorities: string[]; + + constructor( + private accountService: AccountService, + private templateRef: TemplateRef, + private viewContainerRef: ViewContainerRef + ) {} + + @Input() + set jhiHasAnyAuthority(value: string | string[]) { + this.authorities = typeof value === 'string' ? [value] : value; + this.updateView(); + // Get notified each time authentication state changes. + this.accountService.getAuthenticationState().subscribe(identity => this.updateView()); + } + + private updateView(): void { + const hasAnyAuthority = this.accountService.hasAnyAuthority(this.authorities); + this.viewContainerRef.clear(); + if (hasAnyAuthority) { + this.viewContainerRef.createEmbeddedView(this.templateRef); + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/error.constants.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/error.constants.ts new file mode 100644 index 0000000000..2ebea94220 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/error.constants.ts @@ -0,0 +1,4 @@ +export const PROBLEM_BASE_URL = 'https://www.jhipster.tech/problem'; +export const EMAIL_ALREADY_USED_TYPE = PROBLEM_BASE_URL + '/email-already-used'; +export const LOGIN_ALREADY_USED_TYPE = PROBLEM_BASE_URL + '/login-already-used'; +export const EMAIL_NOT_FOUND_TYPE = PROBLEM_BASE_URL + '/email-not-found'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/input.constants.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/input.constants.ts new file mode 100644 index 0000000000..1e3978a9b3 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/input.constants.ts @@ -0,0 +1,2 @@ +export const DATE_FORMAT = 'YYYY-MM-DD'; +export const DATE_TIME_FORMAT = 'YYYY-MM-DDTHH:mm'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/pagination.constants.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/pagination.constants.ts new file mode 100644 index 0000000000..a148d4579b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/constants/pagination.constants.ts @@ -0,0 +1 @@ +export const ITEMS_PER_PAGE = 20; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/index.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/index.ts new file mode 100644 index 0000000000..92a8ccef73 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/index.ts @@ -0,0 +1,12 @@ +export * from './constants/error.constants'; +export * from './constants/pagination.constants'; +export * from './constants/input.constants'; +export * from './alert/alert.component'; +export * from './alert/alert-error.component'; +export * from './auth/has-any-authority.directive'; +export * from './login/login.component'; +export * from './util/request-util'; +export * from './shared-libs.module'; +export * from './shared-common.module'; +export * from './shared.module'; +export * from './util/datepicker-adapter'; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.html b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.html new file mode 100644 index 0000000000..60d593bd4b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.html @@ -0,0 +1,43 @@ + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.ts new file mode 100644 index 0000000000..46711a0619 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/login/login.component.ts @@ -0,0 +1,87 @@ +import { Component, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Router } from '@angular/router'; +import { JhiEventManager } from 'ng-jhipster'; + +import { LoginService } from 'app/core/login/login.service'; +import { StateStorageService } from 'app/core/auth/state-storage.service'; + +@Component({ + selector: 'jhi-login-modal', + templateUrl: './login.component.html' +}) +export class JhiLoginModalComponent implements AfterViewInit { + authenticationError: boolean; + password: string; + rememberMe: boolean; + username: string; + credentials: any; + + constructor( + private eventManager: JhiEventManager, + private loginService: LoginService, + private stateStorageService: StateStorageService, + private elementRef: ElementRef, + private renderer: Renderer, + private router: Router, + public activeModal: NgbActiveModal + ) { + this.credentials = {}; + } + + ngAfterViewInit() { + setTimeout(() => this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#username'), 'focus', []), 0); + } + + cancel() { + this.credentials = { + username: null, + password: null, + rememberMe: true + }; + this.authenticationError = false; + this.activeModal.dismiss('cancel'); + } + + login() { + this.loginService + .login({ + username: this.username, + password: this.password, + rememberMe: this.rememberMe + }) + .then(() => { + this.authenticationError = false; + this.activeModal.dismiss('login success'); + if (this.router.url === '/register' || /^\/activate\//.test(this.router.url) || /^\/reset\//.test(this.router.url)) { + this.router.navigate(['']); + } + + this.eventManager.broadcast({ + name: 'authenticationSuccess', + content: 'Sending Authentication Success' + }); + + // previousState was set in the authExpiredInterceptor before being redirected to login modal. + // since login is successful, go to stored previousState and clear previousState + const redirect = this.stateStorageService.getUrl(); + if (redirect) { + this.stateStorageService.storeUrl(null); + this.router.navigate([redirect]); + } + }) + .catch(() => { + this.authenticationError = true; + }); + } + + register() { + this.activeModal.dismiss('to state register'); + this.router.navigate(['/register']); + } + + requestResetPassword() { + this.activeModal.dismiss('to state requestReset'); + this.router.navigate(['/reset', 'request']); + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/model/book.model.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/model/book.model.ts new file mode 100644 index 0000000000..ee943a4127 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/model/book.model.ts @@ -0,0 +1,21 @@ +import { Moment } from 'moment'; + +export interface IBook { + id?: number; + title?: string; + author?: string; + published?: Moment; + quantity?: number; + price?: number; +} + +export class Book implements IBook { + constructor( + public id?: number, + public title?: string, + public author?: string, + public published?: Moment, + public quantity?: number, + public price?: number + ) {} +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-common.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-common.module.ts new file mode 100644 index 0000000000..c6e52d67c5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-common.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; + +import { BookstoreSharedLibsModule, JhiAlertComponent, JhiAlertErrorComponent } from './'; + +@NgModule({ + imports: [BookstoreSharedLibsModule], + declarations: [JhiAlertComponent, JhiAlertErrorComponent], + exports: [BookstoreSharedLibsModule, JhiAlertComponent, JhiAlertErrorComponent] +}) +export class BookstoreSharedCommonModule {} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-libs.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-libs.module.ts new file mode 100644 index 0000000000..79ac658edb --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared-libs.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { CommonModule } from '@angular/common'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgJhipsterModule } from 'ng-jhipster'; +import { InfiniteScrollModule } from 'ngx-infinite-scroll'; +import { CookieModule } from 'ngx-cookie'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; + +@NgModule({ + imports: [NgbModule.forRoot(), InfiniteScrollModule, CookieModule.forRoot(), FontAwesomeModule], + exports: [FormsModule, CommonModule, NgbModule, NgJhipsterModule, InfiniteScrollModule, FontAwesomeModule] +}) +export class BookstoreSharedLibsModule { + static forRoot() { + return { + ngModule: BookstoreSharedLibsModule + }; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared.module.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared.module.ts new file mode 100644 index 0000000000..695b166793 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/shared.module.ts @@ -0,0 +1,21 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'; + +import { NgbDateMomentAdapter } from './util/datepicker-adapter'; +import { BookstoreSharedLibsModule, BookstoreSharedCommonModule, JhiLoginModalComponent, HasAnyAuthorityDirective } from './'; + +@NgModule({ + imports: [BookstoreSharedLibsModule, BookstoreSharedCommonModule], + declarations: [JhiLoginModalComponent, HasAnyAuthorityDirective], + providers: [{ provide: NgbDateAdapter, useClass: NgbDateMomentAdapter }], + entryComponents: [JhiLoginModalComponent], + exports: [BookstoreSharedCommonModule, JhiLoginModalComponent, HasAnyAuthorityDirective], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BookstoreSharedModule { + static forRoot() { + return { + ngModule: BookstoreSharedModule + }; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/datepicker-adapter.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/datepicker-adapter.ts new file mode 100644 index 0000000000..524a38c834 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/datepicker-adapter.ts @@ -0,0 +1,21 @@ +/** + * Angular bootstrap Date adapter + */ +import { Injectable } from '@angular/core'; +import { NgbDateAdapter, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap'; +import { Moment } from 'moment'; +import * as moment from 'moment'; + +@Injectable() +export class NgbDateMomentAdapter extends NgbDateAdapter { + fromModel(date: Moment): NgbDateStruct { + if (date != null && moment.isMoment(date) && date.isValid()) { + return { year: date.year(), month: date.month() + 1, day: date.date() }; + } + return null; + } + + toModel(date: NgbDateStruct): Moment { + return date ? moment(date.year + '-' + date.month + '-' + date.day, 'YYYY-MM-DD') : null; + } +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/request-util.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/request-util.ts new file mode 100644 index 0000000000..6579c3cb2a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/shared/util/request-util.ts @@ -0,0 +1,18 @@ +import { HttpParams } from '@angular/common/http'; + +export const createRequestOption = (req?: any): HttpParams => { + let options: HttpParams = new HttpParams(); + if (req) { + Object.keys(req).forEach(key => { + if (key !== 'sort') { + options = options.set(key, req[key]); + } + }); + if (req.sort) { + req.sort.forEach(val => { + options = options.append('sort', val); + }); + } + } + return options; +}; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/app/vendor.ts b/jhipster-5/bookstore-monolith/src/main/webapp/app/vendor.ts new file mode 100644 index 0000000000..e8923d5c66 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/app/vendor.ts @@ -0,0 +1,81 @@ +/* after changing this file run 'npm run webpack:build' */ +/* tslint:disable */ +import '../content/scss/vendor.scss'; + +// Imports all fontawesome core and solid icons + +import { library } from '@fortawesome/fontawesome-svg-core'; +import { + faUser, + faSort, + faSortUp, + faSortDown, + faSync, + faEye, + faBan, + faTimes, + faArrowLeft, + faSave, + faPlus, + faPencilAlt, + faBars, + faThList, + faUserPlus, + faRoad, + faTachometerAlt, + faHeart, + faList, + faBell, + faBook, + faHdd, + faFlag, + faWrench, + faClock, + faCloud, + faSignOutAlt, + faSignInAlt, + faCalendarAlt, + faSearch, + faTrashAlt, + faAsterisk, + faTasks, + faHome +} from '@fortawesome/free-solid-svg-icons'; + +// Adds the SVG icon to the library so you can use it in your page +library.add(faUser); +library.add(faSort); +library.add(faSortUp); +library.add(faSortDown); +library.add(faSync); +library.add(faEye); +library.add(faBan); +library.add(faTimes); +library.add(faArrowLeft); +library.add(faSave); +library.add(faPlus); +library.add(faPencilAlt); +library.add(faBars); +library.add(faHome); +library.add(faThList); +library.add(faUserPlus); +library.add(faRoad); +library.add(faTachometerAlt); +library.add(faHeart); +library.add(faList); +library.add(faBell); +library.add(faTasks); +library.add(faBook); +library.add(faHdd); +library.add(faFlag); +library.add(faWrench); +library.add(faClock); +library.add(faCloud); +library.add(faSignOutAlt); +library.add(faSignInAlt); +library.add(faCalendarAlt); +library.add(faSearch); +library.add(faTrashAlt); +library.add(faAsterisk); + +// jhipster-needle-add-element-to-vendor - JHipster will add new menu items here diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/css/loading.css b/jhipster-5/bookstore-monolith/src/main/webapp/content/css/loading.css new file mode 100644 index 0000000000..a1e24615b4 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/css/loading.css @@ -0,0 +1,152 @@ +@keyframes lds-pacman-1 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 50% { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + } + 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} +@-webkit-keyframes lds-pacman-1 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 50% { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + } + 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} +@keyframes lds-pacman-2 { + 0% { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + } + 50% { + -webkit-transform: rotate(225deg); + transform: rotate(225deg); + } + 100% { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + } +} +@-webkit-keyframes lds-pacman-2 { + 0% { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + } + 50% { + -webkit-transform: rotate(225deg); + transform: rotate(225deg); + } + 100% { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + } +} +@keyframes lds-pacman-3 { + 0% { + -webkit-transform: translate(190px, 0); + transform: translate(190px, 0); + opacity: 0; + } + 20% { + opacity: 1; + } + 100% { + -webkit-transform: translate(70px, 0); + transform: translate(70px, 0); + opacity: 1; + } +} +@-webkit-keyframes lds-pacman-3 { + 0% { + -webkit-transform: translate(190px, 0); + transform: translate(190px, 0); + opacity: 0; + } + 20% { + opacity: 1; + } + 100% { + -webkit-transform: translate(70px, 0); + transform: translate(70px, 0); + opacity: 1; + } +} + +.app-loading { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + top: 10em; +} +.app-loading p { + display: block; + font-size: 1.17em; + margin-inline-start: 0px; + margin-inline-end: 0px; + font-weight: normal; +} + +.app-loading .lds-pacman { + position: relative; + margin: auto; + width: 200px !important; + height: 200px !important; + -webkit-transform: translate(-100px, -100px) scale(1) translate(100px, 100px); + transform: translate(-100px, -100px) scale(1) translate(100px, 100px); +} +.app-loading .lds-pacman > div:nth-child(2) div { + position: absolute; + top: 40px; + left: 40px; + width: 120px; + height: 60px; + border-radius: 120px 120px 0 0; + background: #bbcedd; + -webkit-animation: lds-pacman-1 1s linear infinite; + animation: lds-pacman-1 1s linear infinite; + -webkit-transform-origin: 60px 60px; + transform-origin: 60px 60px; +} +.app-loading .lds-pacman > div:nth-child(2) div:nth-child(2) { + -webkit-animation: lds-pacman-2 1s linear infinite; + animation: lds-pacman-2 1s linear infinite; +} +.app-loading .lds-pacman > div:nth-child(1) div { + position: absolute; + top: 97px; + left: -8px; + width: 24px; + height: 10px; + background-image: url('../images/logo-jhipster.png'); + background-size: contain; + -webkit-animation: lds-pacman-3 1s linear infinite; + animation: lds-pacman-3 1.5s linear infinite; +} +.app-loading .lds-pacman > div:nth-child(1) div:nth-child(1) { + -webkit-animation-delay: -0.67s; + animation-delay: -1s; +} +.app-loading .lds-pacman > div:nth-child(1) div:nth-child(2) { + -webkit-animation-delay: -0.33s; + animation-delay: -0.5s; +} +.app-loading .lds-pacman > div:nth-child(1) div:nth-child(3) { + -webkit-animation-delay: 0s; + animation-delay: 0s; +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0.svg b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0.svg new file mode 100755 index 0000000000..1f9ab52790 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-192.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-192.png new file mode 100644 index 0000000000..8133068921 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-192.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-256.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-256.png new file mode 100644 index 0000000000..b4739ec3e4 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-256.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-384.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-384.png new file mode 100644 index 0000000000..0280f27e8b Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-384.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-512.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-512.png new file mode 100644 index 0000000000..326141b927 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_0_head-512.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1.svg b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1.svg new file mode 100755 index 0000000000..7a118f3077 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1.svg @@ -0,0 +1,9387 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-192.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-192.png new file mode 100644 index 0000000000..dd2643c15d Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-192.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-256.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-256.png new file mode 100644 index 0000000000..2c5352683a Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-256.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-384.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-384.png new file mode 100644 index 0000000000..f930681c12 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-384.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-512.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-512.png new file mode 100644 index 0000000000..9110dc8fe4 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_1_head-512.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2.svg b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2.svg new file mode 100755 index 0000000000..1747933833 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2.svg @@ -0,0 +1,841 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-192.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-192.png new file mode 100644 index 0000000000..2699ab4473 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-192.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-256.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-256.png new file mode 100644 index 0000000000..3a5903e19e Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-256.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-384.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-384.png new file mode 100644 index 0000000000..da964fcb2e Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-384.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-512.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-512.png new file mode 100644 index 0000000000..6337f5effb Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_2_head-512.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3.svg b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3.svg new file mode 100755 index 0000000000..6b9e056662 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3.svg @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-192.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-192.png new file mode 100644 index 0000000000..35b91257fc Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-192.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-256.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-256.png new file mode 100644 index 0000000000..098fd8fb05 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-256.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-384.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-384.png new file mode 100644 index 0000000000..b770045754 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-384.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-512.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-512.png new file mode 100644 index 0000000000..58b28b9c48 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/jhipster_family_member_3_head-512.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/images/logo-jhipster.png b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/logo-jhipster.png new file mode 100755 index 0000000000..5d31c2f84d Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/content/images/logo-jhipster.png differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/_bootstrap-variables.scss b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/_bootstrap-variables.scss new file mode 100644 index 0000000000..be0f226497 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/_bootstrap-variables.scss @@ -0,0 +1,42 @@ +/* +* Bootstrap overrides https://getbootstrap.com/docs/4.0/getting-started/theming/ +* All values defined in bootstrap source +* https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variables.scss can be overwritten here +* Make sure not to add !default to values here +*/ + +// Colors: +// Grayscale and brand colors for use across Bootstrap. + +$primary: #3e8acc; +$success: #28a745; +$info: #17a2b8; +$warning: #ffc107; +$danger: #dc3545; + +// Options: +// Quickly modify global styling by enabling or disabling optional features. +$enable-rounded: true; +$enable-shadows: false; +$enable-gradients: false; +$enable-transitions: true; +$enable-hover-media-query: false; +$enable-grid-classes: true; +$enable-print-styles: true; + +// Components: +// Define common padding and border radius sizes and more. + +$border-radius: 0.15rem; +$border-radius-lg: 0.125rem; +$border-radius-sm: 0.1rem; + +// Body: +// Settings for the `` element. + +$body-bg: #e4e5e6; + +// Typography: +// Font, line-height, and color for body text, headings, and more. + +$font-size-base: 1rem; diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/global.scss b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/global.scss new file mode 100644 index 0000000000..cfbb9bf5b8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/global.scss @@ -0,0 +1,226 @@ +@import 'bootstrap-variables'; + +/* ============================================================== +Bootstrap tweaks +===============================================================*/ + +body, +h1, +h2, +h3, +h4 { + font-weight: 300; +} + +a { + color: #533f03; + font-weight: bold; +} + +a:hover { + color: #533f03; + font-weight: bold; + /* make sure browsers use the pointer cursor for anchors, even with no href */ + cursor: pointer; +} + +/* ========================================================================== +Browser Upgrade Prompt +========================================================================== */ +.browserupgrade { + margin: 0.2em 0; + background: #ccc; + color: #000; + padding: 0.2em 0; +} + +/* ========================================================================== +Generic styles +========================================================================== */ + +/* Error highlight on input fields */ +.ng-valid[required], +.ng-valid.required { + border-left: 5px solid green; +} + +.ng-invalid:not(form) { + border-left: 5px solid red; +} + +/* other generic styles */ + +.jh-card { + padding: 1.5%; + margin-top: 20px; + border: none; +} + +.error { + color: white; + background-color: red; +} + +.pad { + padding: 10px; +} + +.w-40 { + width: 40% !important; +} + +.w-60 { + width: 60% !important; +} + +.break { + white-space: normal; + word-break: break-all; +} + +.readonly { + background-color: #eee; + opacity: 1; +} + +.footer { + border-top: 1px solid rgba(0, 0, 0, 0.125); +} + +.hand, +[jhisortby] { + cursor: pointer; +} + +/* ========================================================================== +Custom alerts for notification +========================================================================== */ +.alerts { + .alert { + text-overflow: ellipsis; + pre { + background: none; + border: none; + font: inherit; + color: inherit; + padding: 0; + margin: 0; + } + .popover pre { + font-size: 10px; + } + } + .toast { + position: fixed; + width: 100%; + &.left { + left: 5px; + } + &.right { + right: 5px; + } + &.top { + top: 55px; + } + &.bottom { + bottom: 55px; + } + } +} + +@media screen and (min-width: 480px) { + .alerts .toast { + width: 50%; + } +} + +/* ========================================================================== +entity tables helpers +========================================================================== */ + +/* Remove Bootstrap padding from the element +http://stackoverflow.com/questions/19562903/remove-padding-from-columns-in-bootstrap-3 */ +@mixin no-padding($side) { + @if $side == 'all' { + .no-padding { + padding: 0 !important; + } + } @else { + .no-padding-#{$side} { + padding-#{$side}: 0 !important; + } + } +} +@include no-padding('left'); +@include no-padding('right'); +@include no-padding('top'); +@include no-padding('bottom'); +@include no-padding('all'); + +/* bootstrap 3 input-group 100% width +http://stackoverflow.com/questions/23436430/bootstrap-3-input-group-100-width */ +.width-min { + width: 1% !important; +} + +/* Makes toolbar not wrap on smaller screens +http://www.sketchingwithcss.com/samplechapter/cheatsheet.html#right */ +.flex-btn-group-container { + display: -webkit-flex; + display: flex; + -webkit-flex-direction: row; + flex-direction: row; + -webkit-justify-content: flex-end; + justify-content: flex-end; +} + +/* ========================================================================== +entity detail page css +========================================================================== */ +.row.jh-entity-details > { + dd { + margin-bottom: 15px; + } +} + +@media screen and (min-width: 768px) { + .row.jh-entity-details > { + dt { + margin-bottom: 15px; + } + dd { + border-bottom: 1px solid #eee; + padding-left: 180px; + margin-left: 0; + } + } +} + +/* ========================================================================== +ui bootstrap tweaks +========================================================================== */ +.nav, +.pagination, +.carousel, +.panel-title a { + cursor: pointer; +} + +.datetime-picker-dropdown > li.date-picker-menu div > table .btn-default, +.uib-datepicker-popup > li > div.uib-datepicker > table .btn-default { + border: 0; +} + +.datetime-picker-dropdown > li.date-picker-menu div > table:focus, +.uib-datepicker-popup > li > div.uib-datepicker > table:focus { + outline: none; +} + +.thread-dump-modal-lock { + max-width: 450px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* jhipster-needle-scss-add-main JHipster will add new css style */ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/vendor.scss b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/vendor.scss new file mode 100644 index 0000000000..12a8f54b83 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/content/scss/vendor.scss @@ -0,0 +1,12 @@ +/* after changing this file run 'npm run webpack:build' */ + +/*************************** +put Sass variables here: +eg $input-color: red; +****************************/ +// Override Boostrap variables +@import 'bootstrap-variables'; +// Import Bootstrap source files from node_modules +@import '~bootstrap/scss/bootstrap'; + +/* jhipster-needle-scss-add-vendor JHipster will add new css style */ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/favicon.ico b/jhipster-5/bookstore-monolith/src/main/webapp/favicon.ico new file mode 100755 index 0000000000..4179874f53 Binary files /dev/null and b/jhipster-5/bookstore-monolith/src/main/webapp/favicon.ico differ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/index.html b/jhipster-5/bookstore-monolith/src/main/webapp/index.html new file mode 100644 index 0000000000..a2fd4df265 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/index.html @@ -0,0 +1,108 @@ + + + + + + + Bookstore + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+ +
+
+ + + + + + diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/manifest.webapp b/jhipster-5/bookstore-monolith/src/main/webapp/manifest.webapp new file mode 100644 index 0000000000..42b606ea1d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/manifest.webapp @@ -0,0 +1,31 @@ +{ + "name": "Bookstore", + "short_name": "Bookstore", + "icons": [ + { + "src": "./content/images/jhipster_family_member_0_head-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "./content/images/jhipster_family_member_0_head-256.png", + "sizes": "256x256", + "type": "image/png" + }, + { + "src": "./content/images/jhipster_family_member_0_head-384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "./content/images/jhipster_family_member_0_head-512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#000000", + "background_color": "#e0e0e0", + "start_url": "/index.html", + "display": "standalone", + "orientation": "portrait" +} diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/robots.txt b/jhipster-5/bookstore-monolith/src/main/webapp/robots.txt new file mode 100644 index 0000000000..7cda27477d --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/robots.txt @@ -0,0 +1,11 @@ +# robotstxt.org/ + +User-agent: * +Disallow: /api/account +Disallow: /api/account/change-password +Disallow: /api/account/sessions +Disallow: /api/audits/ +Disallow: /api/logs/ +Disallow: /api/users/ +Disallow: /management/ +Disallow: /v2/api-docs/ diff --git a/jhipster-5/bookstore-monolith/src/main/webapp/swagger-ui/index.html b/jhipster-5/bookstore-monolith/src/main/webapp/swagger-ui/index.html new file mode 100644 index 0000000000..416eacef70 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/main/webapp/swagger-ui/index.html @@ -0,0 +1,166 @@ + + + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+
+ + diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTest.java new file mode 100644 index 0000000000..670042d2df --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTest.java @@ -0,0 +1,189 @@ +package com.baeldung.jhipster5.config; + +import io.github.jhipster.config.JHipsterConstants; +import io.github.jhipster.config.JHipsterProperties; +import io.github.jhipster.web.filter.CachingHttpHeadersFilter; +import io.undertow.Undertow; +import io.undertow.Undertow.Builder; +import io.undertow.UndertowOptions; +import org.apache.commons.io.FilenameUtils; + +import org.h2.server.web.WebServlet; +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.mock.web.MockServletContext; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.xnio.OptionMap; + +import javax.servlet.*; +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Unit tests for the WebConfigurer class. + * + * @see WebConfigurer + */ +public class WebConfigurerTest { + + private WebConfigurer webConfigurer; + + private MockServletContext servletContext; + + private MockEnvironment env; + + private JHipsterProperties props; + + @Before + public void setup() { + servletContext = spy(new MockServletContext()); + doReturn(mock(FilterRegistration.Dynamic.class)) + .when(servletContext).addFilter(anyString(), any(Filter.class)); + doReturn(mock(ServletRegistration.Dynamic.class)) + .when(servletContext).addServlet(anyString(), any(Servlet.class)); + + env = new MockEnvironment(); + props = new JHipsterProperties(); + + webConfigurer = new WebConfigurer(env, props); + } + + @Test + public void testStartUpProdServletContext() throws ServletException { + env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION); + webConfigurer.onStartup(servletContext); + + verify(servletContext).addFilter(eq("cachingHttpHeadersFilter"), any(CachingHttpHeadersFilter.class)); + verify(servletContext, never()).addServlet(eq("H2Console"), any(WebServlet.class)); + } + + @Test + public void testStartUpDevServletContext() throws ServletException { + env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT); + webConfigurer.onStartup(servletContext); + + verify(servletContext, never()).addFilter(eq("cachingHttpHeadersFilter"), any(CachingHttpHeadersFilter.class)); + verify(servletContext).addServlet(eq("H2Console"), any(WebServlet.class)); + } + + @Test + public void testCustomizeServletContainer() { + env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION); + UndertowServletWebServerFactory container = new UndertowServletWebServerFactory(); + webConfigurer.customize(container); + assertThat(container.getMimeMappings().get("abs")).isEqualTo("audio/x-mpeg"); + assertThat(container.getMimeMappings().get("html")).isEqualTo("text/html;charset=utf-8"); + assertThat(container.getMimeMappings().get("json")).isEqualTo("text/html;charset=utf-8"); + if (container.getDocumentRoot() != null) { + assertThat(container.getDocumentRoot().getPath()).isEqualTo(FilenameUtils.separatorsToSystem("target/www")); + } + + Builder builder = Undertow.builder(); + container.getBuilderCustomizers().forEach(c -> c.customize(builder)); + OptionMap.Builder serverOptions = (OptionMap.Builder) ReflectionTestUtils.getField(builder, "serverOptions"); + assertThat(serverOptions.getMap().get(UndertowOptions.ENABLE_HTTP2)).isNull(); + } + + @Test + public void testUndertowHttp2Enabled() { + props.getHttp().setVersion(JHipsterProperties.Http.Version.V_2_0); + UndertowServletWebServerFactory container = new UndertowServletWebServerFactory(); + webConfigurer.customize(container); + Builder builder = Undertow.builder(); + container.getBuilderCustomizers().forEach(c -> c.customize(builder)); + OptionMap.Builder serverOptions = (OptionMap.Builder) ReflectionTestUtils.getField(builder, "serverOptions"); + assertThat(serverOptions.getMap().get(UndertowOptions.ENABLE_HTTP2)).isTrue(); + } + + @Test + public void testCorsFilterOnApiPath() throws Exception { + props.getCors().setAllowedOrigins(Collections.singletonList("*")); + props.getCors().setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); + props.getCors().setAllowedHeaders(Collections.singletonList("*")); + props.getCors().setMaxAge(1800L); + props.getCors().setAllowCredentials(true); + + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()) + .addFilters(webConfigurer.corsFilter()) + .build(); + + mockMvc.perform( + options("/api/test-cors") + .header(HttpHeaders.ORIGIN, "other.domain.com") + .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "POST")) + .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "other.domain.com")) + .andExpect(header().string(HttpHeaders.VARY, "Origin")) + .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,PUT,DELETE")) + .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true")) + .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "1800")); + + mockMvc.perform( + get("/api/test-cors") + .header(HttpHeaders.ORIGIN, "other.domain.com")) + .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "other.domain.com")); + } + + @Test + public void testCorsFilterOnOtherPath() throws Exception { + props.getCors().setAllowedOrigins(Collections.singletonList("*")); + props.getCors().setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); + props.getCors().setAllowedHeaders(Collections.singletonList("*")); + props.getCors().setMaxAge(1800L); + props.getCors().setAllowCredentials(true); + + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()) + .addFilters(webConfigurer.corsFilter()) + .build(); + + mockMvc.perform( + get("/test/test-cors") + .header(HttpHeaders.ORIGIN, "other.domain.com")) + .andExpect(status().isOk()) + .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); + } + + @Test + public void testCorsFilterDeactivated() throws Exception { + props.getCors().setAllowedOrigins(null); + + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()) + .addFilters(webConfigurer.corsFilter()) + .build(); + + mockMvc.perform( + get("/api/test-cors") + .header(HttpHeaders.ORIGIN, "other.domain.com")) + .andExpect(status().isOk()) + .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); + } + + @Test + public void testCorsFilterDeactivated2() throws Exception { + props.getCors().setAllowedOrigins(new ArrayList<>()); + + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()) + .addFilters(webConfigurer.corsFilter()) + .build(); + + mockMvc.perform( + get("/api/test-cors") + .header(HttpHeaders.ORIGIN, "other.domain.com")) + .andExpect(status().isOk()) + .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTestController.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTestController.java new file mode 100644 index 0000000000..c19b28ea16 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/WebConfigurerTestController.java @@ -0,0 +1,16 @@ +package com.baeldung.jhipster5.config; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class WebConfigurerTestController { + + @GetMapping("/api/test-cors") + public void testCorsOnApiPath() { + } + + @GetMapping("/test/test-cors") + public void testCorsOnOtherPath() { + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/timezone/HibernateTimeZoneTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/timezone/HibernateTimeZoneTest.java new file mode 100644 index 0000000000..9027606e67 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/config/timezone/HibernateTimeZoneTest.java @@ -0,0 +1,176 @@ +package com.baeldung.jhipster5.config.timezone; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.repository.timezone.DateTimeWrapper; +import com.baeldung.jhipster5.repository.timezone.DateTimeWrapperRepository; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.time.*; +import java.time.format.DateTimeFormatter; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for the UTC Hibernate configuration. + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class HibernateTimeZoneTest { + + @Autowired + private DateTimeWrapperRepository dateTimeWrapperRepository; + @Autowired + private JdbcTemplate jdbcTemplate; + + private DateTimeWrapper dateTimeWrapper; + private DateTimeFormatter dateTimeFormatter; + private DateTimeFormatter timeFormatter; + private DateTimeFormatter dateFormatter; + + @Before + public void setup() { + dateTimeWrapper = new DateTimeWrapper(); + dateTimeWrapper.setInstant(Instant.parse("2014-11-12T05:50:00.0Z")); + dateTimeWrapper.setLocalDateTime(LocalDateTime.parse("2014-11-12T07:50:00.0")); + dateTimeWrapper.setOffsetDateTime(OffsetDateTime.parse("2011-12-14T08:30:00.0Z")); + dateTimeWrapper.setZonedDateTime(ZonedDateTime.parse("2011-12-14T08:30:00.0Z")); + dateTimeWrapper.setLocalTime(LocalTime.parse("14:30:00")); + dateTimeWrapper.setOffsetTime(OffsetTime.parse("14:30:00+02:00")); + dateTimeWrapper.setLocalDate(LocalDate.parse("2016-09-10")); + + dateTimeFormatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss.S") + .withZone(ZoneId.of("UTC")); + + timeFormatter = DateTimeFormatter + .ofPattern("HH:mm:ss") + .withZone(ZoneId.of("UTC")); + + dateFormatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd"); + } + + @Test + @Transactional + public void storeInstantWithUtcConfigShouldBeStoredOnGMTTimeZone() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("instant", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeFormatter.format(dateTimeWrapper.getInstant()); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeLocalDateTimeWithUtcConfigShouldBeStoredOnGMTTimeZone() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("local_date_time", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getLocalDateTime() + .atZone(ZoneId.systemDefault()) + .format(dateTimeFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeOffsetDateTimeWithUtcConfigShouldBeStoredOnGMTTimeZone() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("offset_date_time", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getOffsetDateTime() + .format(dateTimeFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeZoneDateTimeWithUtcConfigShouldBeStoredOnGMTTimeZone() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("zoned_date_time", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getZonedDateTime() + .format(dateTimeFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeLocalTimeWithUtcConfigShouldBeStoredOnGMTTimeZoneAccordingToHis1stJan1970Value() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("local_time", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getLocalTime() + .atDate(LocalDate.of(1970, Month.JANUARY, 1)) + .atZone(ZoneId.systemDefault()) + .format(timeFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeOffsetTimeWithUtcConfigShouldBeStoredOnGMTTimeZoneAccordingToHis1stJan1970Value() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("offset_time", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getOffsetTime() + .toLocalTime() + .atDate(LocalDate.of(1970, Month.JANUARY, 1)) + .atZone(ZoneId.systemDefault()) + .format(timeFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + @Test + @Transactional + public void storeLocalDateWithUtcConfigShouldBeStoredWithoutTransformation() { + dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); + + String request = generateSqlRequest("local_date", dateTimeWrapper.getId()); + SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); + String expectedValue = dateTimeWrapper + .getLocalDate() + .format(dateFormatter); + + assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); + } + + private String generateSqlRequest(String fieldName, long id) { + return format("SELECT %s FROM jhi_date_time_wrapper where id=%d", fieldName, id); + } + + private void assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(SqlRowSet sqlRowSet, String expectedValue) { + while (sqlRowSet.next()) { + String dbValue = sqlRowSet.getString(1); + + assertThat(dbValue).isNotNull(); + assertThat(dbValue).isEqualTo(expectedValue); + } + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/CustomAuditEventRepositoryIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/CustomAuditEventRepositoryIntTest.java new file mode 100644 index 0000000000..eaf5c07504 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/CustomAuditEventRepositoryIntTest.java @@ -0,0 +1,165 @@ +package com.baeldung.jhipster5.repository; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.config.audit.AuditEventConverter; +import com.baeldung.jhipster5.domain.PersistentAuditEvent; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpSession; +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static com.baeldung.jhipster5.repository.CustomAuditEventRepository.EVENT_DATA_COLUMN_MAX_LENGTH; + +/** + * Test class for the CustomAuditEventRepository class. + * + * @see CustomAuditEventRepository + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +@Transactional +public class CustomAuditEventRepositoryIntTest { + + @Autowired + private PersistenceAuditEventRepository persistenceAuditEventRepository; + + @Autowired + private AuditEventConverter auditEventConverter; + + private CustomAuditEventRepository customAuditEventRepository; + + private PersistentAuditEvent testUserEvent; + + private PersistentAuditEvent testOtherUserEvent; + + private PersistentAuditEvent testOldUserEvent; + + @Before + public void setup() { + customAuditEventRepository = new CustomAuditEventRepository(persistenceAuditEventRepository, auditEventConverter); + persistenceAuditEventRepository.deleteAll(); + Instant oneHourAgo = Instant.now().minusSeconds(3600); + + testUserEvent = new PersistentAuditEvent(); + testUserEvent.setPrincipal("test-user"); + testUserEvent.setAuditEventType("test-type"); + testUserEvent.setAuditEventDate(oneHourAgo); + Map data = new HashMap<>(); + data.put("test-key", "test-value"); + testUserEvent.setData(data); + + testOldUserEvent = new PersistentAuditEvent(); + testOldUserEvent.setPrincipal("test-user"); + testOldUserEvent.setAuditEventType("test-type"); + testOldUserEvent.setAuditEventDate(oneHourAgo.minusSeconds(10000)); + + testOtherUserEvent = new PersistentAuditEvent(); + testOtherUserEvent.setPrincipal("other-test-user"); + testOtherUserEvent.setAuditEventType("test-type"); + testOtherUserEvent.setAuditEventDate(oneHourAgo); + } + + @Test + public void addAuditEvent() { + Map data = new HashMap<>(); + data.put("test-key", "test-value"); + AuditEvent event = new AuditEvent("test-user", "test-type", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(1); + PersistentAuditEvent persistentAuditEvent = persistentAuditEvents.get(0); + assertThat(persistentAuditEvent.getPrincipal()).isEqualTo(event.getPrincipal()); + assertThat(persistentAuditEvent.getAuditEventType()).isEqualTo(event.getType()); + assertThat(persistentAuditEvent.getData()).containsKey("test-key"); + assertThat(persistentAuditEvent.getData().get("test-key")).isEqualTo("test-value"); + assertThat(persistentAuditEvent.getAuditEventDate()).isEqualTo(event.getTimestamp()); + } + + @Test + public void addAuditEventTruncateLargeData() { + Map data = new HashMap<>(); + StringBuilder largeData = new StringBuilder(); + for (int i = 0; i < EVENT_DATA_COLUMN_MAX_LENGTH + 10; i++) { + largeData.append("a"); + } + data.put("test-key", largeData); + AuditEvent event = new AuditEvent("test-user", "test-type", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(1); + PersistentAuditEvent persistentAuditEvent = persistentAuditEvents.get(0); + assertThat(persistentAuditEvent.getPrincipal()).isEqualTo(event.getPrincipal()); + assertThat(persistentAuditEvent.getAuditEventType()).isEqualTo(event.getType()); + assertThat(persistentAuditEvent.getData()).containsKey("test-key"); + String actualData = persistentAuditEvent.getData().get("test-key"); + assertThat(actualData.length()).isEqualTo(EVENT_DATA_COLUMN_MAX_LENGTH); + assertThat(actualData).isSubstringOf(largeData); + assertThat(persistentAuditEvent.getAuditEventDate()).isEqualTo(event.getTimestamp()); + } + + @Test + public void testAddEventWithWebAuthenticationDetails() { + HttpSession session = new MockHttpSession(null, "test-session-id"); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setSession(session); + request.setRemoteAddr("1.2.3.4"); + WebAuthenticationDetails details = new WebAuthenticationDetails(request); + Map data = new HashMap<>(); + data.put("test-key", details); + AuditEvent event = new AuditEvent("test-user", "test-type", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(1); + PersistentAuditEvent persistentAuditEvent = persistentAuditEvents.get(0); + assertThat(persistentAuditEvent.getData().get("remoteAddress")).isEqualTo("1.2.3.4"); + assertThat(persistentAuditEvent.getData().get("sessionId")).isEqualTo("test-session-id"); + } + + @Test + public void testAddEventWithNullData() { + Map data = new HashMap<>(); + data.put("test-key", null); + AuditEvent event = new AuditEvent("test-user", "test-type", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(1); + PersistentAuditEvent persistentAuditEvent = persistentAuditEvents.get(0); + assertThat(persistentAuditEvent.getData().get("test-key")).isEqualTo("null"); + } + + @Test + public void addAuditEventWithAnonymousUser() { + Map data = new HashMap<>(); + data.put("test-key", "test-value"); + AuditEvent event = new AuditEvent(Constants.ANONYMOUS_USER, "test-type", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(0); + } + + @Test + public void addAuditEventWithAuthorizationFailureType() { + Map data = new HashMap<>(); + data.put("test-key", "test-value"); + AuditEvent event = new AuditEvent("test-user", "AUTHORIZATION_FAILURE", data); + customAuditEventRepository.add(event); + List persistentAuditEvents = persistenceAuditEventRepository.findAll(); + assertThat(persistentAuditEvents).hasSize(0); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapper.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapper.java new file mode 100644 index 0000000000..473a8e782e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapper.java @@ -0,0 +1,131 @@ +package com.baeldung.jhipster5.repository.timezone; + +import javax.persistence.*; +import java.io.Serializable; +import java.time.*; +import java.util.Objects; + +@Entity +@Table(name = "jhi_date_time_wrapper") +public class DateTimeWrapper implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "instant") + private Instant instant; + + @Column(name = "local_date_time") + private LocalDateTime localDateTime; + + @Column(name = "offset_date_time") + private OffsetDateTime offsetDateTime; + + @Column(name = "zoned_date_time") + private ZonedDateTime zonedDateTime; + + @Column(name = "local_time") + private LocalTime localTime; + + @Column(name = "offset_time") + private OffsetTime offsetTime; + + @Column(name = "local_date") + private LocalDate localDate; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Instant getInstant() { + return instant; + } + + public void setInstant(Instant instant) { + this.instant = instant; + } + + public LocalDateTime getLocalDateTime() { + return localDateTime; + } + + public void setLocalDateTime(LocalDateTime localDateTime) { + this.localDateTime = localDateTime; + } + + public OffsetDateTime getOffsetDateTime() { + return offsetDateTime; + } + + public void setOffsetDateTime(OffsetDateTime offsetDateTime) { + this.offsetDateTime = offsetDateTime; + } + + public ZonedDateTime getZonedDateTime() { + return zonedDateTime; + } + + public void setZonedDateTime(ZonedDateTime zonedDateTime) { + this.zonedDateTime = zonedDateTime; + } + + public LocalTime getLocalTime() { + return localTime; + } + + public void setLocalTime(LocalTime localTime) { + this.localTime = localTime; + } + + public OffsetTime getOffsetTime() { + return offsetTime; + } + + public void setOffsetTime(OffsetTime offsetTime) { + this.offsetTime = offsetTime; + } + + public LocalDate getLocalDate() { + return localDate; + } + + public void setLocalDate(LocalDate localDate) { + this.localDate = localDate; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DateTimeWrapper dateTimeWrapper = (DateTimeWrapper) o; + return !(dateTimeWrapper.getId() == null || getId() == null) && Objects.equals(getId(), dateTimeWrapper.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getId()); + } + + @Override + public String toString() { + return "TimeZoneTest{" + + "id=" + id + + ", instant=" + instant + + ", localDateTime=" + localDateTime + + ", offsetDateTime=" + offsetDateTime + + ", zonedDateTime=" + zonedDateTime + + '}'; + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapperRepository.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapperRepository.java new file mode 100644 index 0000000000..9c3831879f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/repository/timezone/DateTimeWrapperRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.jhipster5.repository.timezone; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * Spring Data JPA repository for the DateTimeWrapper entity. + */ +@Repository +public interface DateTimeWrapperRepository extends JpaRepository { + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/DomainUserDetailsServiceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/DomainUserDetailsServiceIntTest.java new file mode 100644 index 0000000000..f11252de2b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/DomainUserDetailsServiceIntTest.java @@ -0,0 +1,127 @@ +package com.baeldung.jhipster5.security; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Locale; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test class for DomainUserDetailsService. + * + * @see DomainUserDetailsService + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +@Transactional +public class DomainUserDetailsServiceIntTest { + + private static final String USER_ONE_LOGIN = "test-user-one"; + private static final String USER_ONE_EMAIL = "test-user-one@localhost"; + private static final String USER_TWO_LOGIN = "test-user-two"; + private static final String USER_TWO_EMAIL = "test-user-two@localhost"; + private static final String USER_THREE_LOGIN = "test-user-three"; + private static final String USER_THREE_EMAIL = "test-user-three@localhost"; + + @Autowired + private UserRepository userRepository; + + @Autowired + private UserDetailsService domainUserDetailsService; + + private User userOne; + private User userTwo; + private User userThree; + + @Before + public void init() { + userOne = new User(); + userOne.setLogin(USER_ONE_LOGIN); + userOne.setPassword(RandomStringUtils.random(60)); + userOne.setActivated(true); + userOne.setEmail(USER_ONE_EMAIL); + userOne.setFirstName("userOne"); + userOne.setLastName("doe"); + userOne.setLangKey("en"); + userRepository.save(userOne); + + userTwo = new User(); + userTwo.setLogin(USER_TWO_LOGIN); + userTwo.setPassword(RandomStringUtils.random(60)); + userTwo.setActivated(true); + userTwo.setEmail(USER_TWO_EMAIL); + userTwo.setFirstName("userTwo"); + userTwo.setLastName("doe"); + userTwo.setLangKey("en"); + userRepository.save(userTwo); + + userThree = new User(); + userThree.setLogin(USER_THREE_LOGIN); + userThree.setPassword(RandomStringUtils.random(60)); + userThree.setActivated(false); + userThree.setEmail(USER_THREE_EMAIL); + userThree.setFirstName("userThree"); + userThree.setLastName("doe"); + userThree.setLangKey("en"); + userRepository.save(userThree); + } + + @Test + @Transactional + public void assertThatUserCanBeFoundByLogin() { + UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_LOGIN); + assertThat(userDetails).isNotNull(); + assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN); + } + + @Test + @Transactional + public void assertThatUserCanBeFoundByLoginIgnoreCase() { + UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_LOGIN.toUpperCase(Locale.ENGLISH)); + assertThat(userDetails).isNotNull(); + assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN); + } + + @Test + @Transactional + public void assertThatUserCanBeFoundByEmail() { + UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_TWO_EMAIL); + assertThat(userDetails).isNotNull(); + assertThat(userDetails.getUsername()).isEqualTo(USER_TWO_LOGIN); + } + + @Test(expected = UsernameNotFoundException.class) + @Transactional + public void assertThatUserCanNotBeFoundByEmailIgnoreCase() { + domainUserDetailsService.loadUserByUsername(USER_TWO_EMAIL.toUpperCase(Locale.ENGLISH)); + } + + @Test + @Transactional + public void assertThatEmailIsPrioritizedOverLogin() { + UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_EMAIL); + assertThat(userDetails).isNotNull(); + assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN); + } + + @Test(expected = UserNotActivatedException.class) + @Transactional + public void assertThatUserNotActivatedExceptionIsThrownForNotActivatedUsers() { + domainUserDetailsService.loadUserByUsername(USER_THREE_LOGIN); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/SecurityUtilsUnitTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/SecurityUtilsUnitTest.java new file mode 100644 index 0000000000..b2736badd6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/SecurityUtilsUnitTest.java @@ -0,0 +1,73 @@ +package com.baeldung.jhipster5.security; + +import org.junit.Test; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test class for the SecurityUtils utility class. + * + * @see SecurityUtils + */ +public class SecurityUtilsUnitTest { + + @Test + public void testgetCurrentUserLogin() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin")); + SecurityContextHolder.setContext(securityContext); + Optional login = SecurityUtils.getCurrentUserLogin(); + assertThat(login).contains("admin"); + } + + @Test + public void testgetCurrentUserJWT() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "token")); + SecurityContextHolder.setContext(securityContext); + Optional jwt = SecurityUtils.getCurrentUserJWT(); + assertThat(jwt).contains("token"); + } + + @Test + public void testIsAuthenticated() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin")); + SecurityContextHolder.setContext(securityContext); + boolean isAuthenticated = SecurityUtils.isAuthenticated(); + assertThat(isAuthenticated).isTrue(); + } + + @Test + public void testAnonymousIsNotAuthenticated() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities)); + SecurityContextHolder.setContext(securityContext); + boolean isAuthenticated = SecurityUtils.isAuthenticated(); + assertThat(isAuthenticated).isFalse(); + } + + @Test + public void testIsCurrentUserInRole() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER)); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("user", "user", authorities)); + SecurityContextHolder.setContext(securityContext); + + assertThat(SecurityUtils.isCurrentUserInRole(AuthoritiesConstants.USER)).isTrue(); + assertThat(SecurityUtils.isCurrentUserInRole(AuthoritiesConstants.ADMIN)).isFalse(); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/JWTFilterTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/JWTFilterTest.java new file mode 100644 index 0000000000..b3de21819b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/JWTFilterTest.java @@ -0,0 +1,115 @@ +package com.baeldung.jhipster5.security.jwt; + +import com.baeldung.jhipster5.security.AuthoritiesConstants; +import io.github.jhipster.config.JHipsterProperties; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.HttpStatus; +import org.springframework.mock.web.MockFilterChain; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JWTFilterTest { + + private TokenProvider tokenProvider; + + private JWTFilter jwtFilter; + + @Before + public void setup() { + JHipsterProperties jHipsterProperties = new JHipsterProperties(); + tokenProvider = new TokenProvider(jHipsterProperties); + ReflectionTestUtils.setField(tokenProvider, "key", + Keys.hmacShaKeyFor(Decoders.BASE64 + .decode("fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8"))); + + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", 60000); + jwtFilter = new JWTFilter(tokenProvider); + SecurityContextHolder.getContext().setAuthentication(null); + } + + @Test + public void testJWTFilter() throws Exception { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + "test-user", + "test-password", + Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.USER)) + ); + String jwt = tokenProvider.createToken(authentication, false); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication().getName()).isEqualTo("test-user"); + assertThat(SecurityContextHolder.getContext().getAuthentication().getCredentials().toString()).isEqualTo(jwt); + } + + @Test + public void testJWTFilterInvalidToken() throws Exception { + String jwt = "wrong_jwt"; + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + + @Test + public void testJWTFilterMissingAuthorization() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + + @Test + public void testJWTFilterMissingToken() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer "); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + + @Test + public void testJWTFilterWrongScheme() throws Exception { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + "test-user", + "test-password", + Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.USER)) + ); + String jwt = tokenProvider.createToken(authentication, false); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Basic " + jwt); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/TokenProviderTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/TokenProviderTest.java new file mode 100644 index 0000000000..11fcfddbf9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/security/jwt/TokenProviderTest.java @@ -0,0 +1,111 @@ +package com.baeldung.jhipster5.security.jwt; + +import com.baeldung.jhipster5.security.AuthoritiesConstants; + +import java.security.Key; +import java.util.*; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.test.util.ReflectionTestUtils; + +import io.github.jhipster.config.JHipsterProperties; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TokenProviderTest { + + private final long ONE_MINUTE = 60000; + private Key key; + private JHipsterProperties jHipsterProperties; + private TokenProvider tokenProvider; + + @Before + public void setup() { + jHipsterProperties = Mockito.mock(JHipsterProperties.class); + tokenProvider = new TokenProvider(jHipsterProperties); + key = Keys.hmacShaKeyFor(Decoders.BASE64 + .decode("fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8")); + + ReflectionTestUtils.setField(tokenProvider, "key", key); + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", ONE_MINUTE); + } + + @Test + public void testReturnFalseWhenJWThasInvalidSignature() { + boolean isTokenValid = tokenProvider.validateToken(createTokenWithDifferentSignature()); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisMalformed() { + Authentication authentication = createAuthentication(); + String token = tokenProvider.createToken(authentication, false); + String invalidToken = token.substring(1); + boolean isTokenValid = tokenProvider.validateToken(invalidToken); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisExpired() { + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", -ONE_MINUTE); + + Authentication authentication = createAuthentication(); + String token = tokenProvider.createToken(authentication, false); + + boolean isTokenValid = tokenProvider.validateToken(token); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisUnsupported() { + String unsupportedToken = createUnsupportedToken(); + + boolean isTokenValid = tokenProvider.validateToken(unsupportedToken); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisInvalid() { + boolean isTokenValid = tokenProvider.validateToken(""); + + assertThat(isTokenValid).isEqualTo(false); + } + + private Authentication createAuthentication() { + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); + return new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities); + } + + private String createUnsupportedToken() { + return Jwts.builder() + .setPayload("payload") + .signWith(key, SignatureAlgorithm.HS512) + .compact(); + } + + private String createTokenWithDifferentSignature() { + Key otherKey = Keys.hmacShaKeyFor(Decoders.BASE64 + .decode("Xfd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8")); + + return Jwts.builder() + .setSubject("anonymous") + .signWith(otherKey, SignatureAlgorithm.HS512) + .setExpiration(new Date(new Date().getTime() + ONE_MINUTE)) + .compact(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/MailServiceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/MailServiceIntTest.java new file mode 100644 index 0000000000..4bde3276f5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/MailServiceIntTest.java @@ -0,0 +1,187 @@ +package com.baeldung.jhipster5.service; +import com.baeldung.jhipster5.config.Constants; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.domain.User; +import io.github.jhipster.config.JHipsterProperties; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.MessageSource; +import org.springframework.mail.MailSendException; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.test.context.junit4.SpringRunner; +import org.thymeleaf.spring5.SpringTemplateEngine; + +import javax.mail.Multipart; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import java.io.ByteArrayOutputStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class MailServiceIntTest { + + @Autowired + private JHipsterProperties jHipsterProperties; + + @Autowired + private MessageSource messageSource; + + @Autowired + private SpringTemplateEngine templateEngine; + + @Spy + private JavaMailSenderImpl javaMailSender; + + @Captor + private ArgumentCaptor messageCaptor; + + private MailService mailService; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + doNothing().when(javaMailSender).send(any(MimeMessage.class)); + mailService = new MailService(jHipsterProperties, javaMailSender, messageSource, templateEngine); + } + + @Test + public void testSendEmail() throws Exception { + mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, false); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getSubject()).isEqualTo("testSubject"); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo("john.doe@example.com"); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent()).isInstanceOf(String.class); + assertThat(message.getContent().toString()).isEqualTo("testContent"); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/plain; charset=UTF-8"); + } + + @Test + public void testSendHtmlEmail() throws Exception { + mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, true); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getSubject()).isEqualTo("testSubject"); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo("john.doe@example.com"); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent()).isInstanceOf(String.class); + assertThat(message.getContent().toString()).isEqualTo("testContent"); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testSendMultipartEmail() throws Exception { + mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", true, false); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + MimeMultipart mp = (MimeMultipart) message.getContent(); + MimeBodyPart part = (MimeBodyPart) ((MimeMultipart) mp.getBodyPart(0).getContent()).getBodyPart(0); + ByteArrayOutputStream aos = new ByteArrayOutputStream(); + part.writeTo(aos); + assertThat(message.getSubject()).isEqualTo("testSubject"); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo("john.doe@example.com"); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent()).isInstanceOf(Multipart.class); + assertThat(aos.toString()).isEqualTo("\r\ntestContent"); + assertThat(part.getDataHandler().getContentType()).isEqualTo("text/plain; charset=UTF-8"); + } + + @Test + public void testSendMultipartHtmlEmail() throws Exception { + mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", true, true); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + MimeMultipart mp = (MimeMultipart) message.getContent(); + MimeBodyPart part = (MimeBodyPart) ((MimeMultipart) mp.getBodyPart(0).getContent()).getBodyPart(0); + ByteArrayOutputStream aos = new ByteArrayOutputStream(); + part.writeTo(aos); + assertThat(message.getSubject()).isEqualTo("testSubject"); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo("john.doe@example.com"); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent()).isInstanceOf(Multipart.class); + assertThat(aos.toString()).isEqualTo("\r\ntestContent"); + assertThat(part.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testSendEmailFromTemplate() throws Exception { + User user = new User(); + user.setLogin("john"); + user.setEmail("john.doe@example.com"); + user.setLangKey("en"); + mailService.sendEmailFromTemplate(user, "mail/testEmail", "email.test.title"); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getSubject()).isEqualTo("test title"); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo(user.getEmail()); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent().toString()).isEqualToNormalizingNewlines("test title, http://127.0.0.1:8080, john\n"); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testSendActivationEmail() throws Exception { + User user = new User(); + user.setLangKey(Constants.DEFAULT_LANGUAGE); + user.setLogin("john"); + user.setEmail("john.doe@example.com"); + mailService.sendActivationEmail(user); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo(user.getEmail()); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent().toString()).isNotEmpty(); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testCreationEmail() throws Exception { + User user = new User(); + user.setLangKey(Constants.DEFAULT_LANGUAGE); + user.setLogin("john"); + user.setEmail("john.doe@example.com"); + mailService.sendCreationEmail(user); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo(user.getEmail()); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent().toString()).isNotEmpty(); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testSendPasswordResetMail() throws Exception { + User user = new User(); + user.setLangKey(Constants.DEFAULT_LANGUAGE); + user.setLogin("john"); + user.setEmail("john.doe@example.com"); + mailService.sendPasswordResetMail(user); + verify(javaMailSender).send(messageCaptor.capture()); + MimeMessage message = messageCaptor.getValue(); + assertThat(message.getAllRecipients()[0].toString()).isEqualTo(user.getEmail()); + assertThat(message.getFrom()[0].toString()).isEqualTo("test@localhost"); + assertThat(message.getContent().toString()).isNotEmpty(); + assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void testSendEmailWithException() throws Exception { + doThrow(MailSendException.class).when(javaMailSender).send(any(MimeMessage.class)); + mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, false); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/UserServiceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/UserServiceIntTest.java new file mode 100644 index 0000000000..81034c2793 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/UserServiceIntTest.java @@ -0,0 +1,192 @@ +package com.baeldung.jhipster5.service; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.service.util.RandomUtil; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.auditing.AuditingHandler; +import org.springframework.data.auditing.DateTimeProvider; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +/** + * Test class for the UserResource REST controller. + * + * @see UserService + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +@Transactional +public class UserServiceIntTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private UserService userService; + + @Autowired + private AuditingHandler auditingHandler; + + @Mock + DateTimeProvider dateTimeProvider; + + private User user; + + @Before + public void init() { + user = new User(); + user.setLogin("johndoe"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setEmail("johndoe@localhost"); + user.setFirstName("john"); + user.setLastName("doe"); + user.setImageUrl("http://placehold.it/50x50"); + user.setLangKey("en"); + + when(dateTimeProvider.getNow()).thenReturn(Optional.of(LocalDateTime.now())); + auditingHandler.setDateTimeProvider(dateTimeProvider); + } + + @Test + @Transactional + public void assertThatUserMustExistToResetPassword() { + userRepository.saveAndFlush(user); + Optional maybeUser = userService.requestPasswordReset("invalid.login@localhost"); + assertThat(maybeUser).isNotPresent(); + + maybeUser = userService.requestPasswordReset(user.getEmail()); + assertThat(maybeUser).isPresent(); + assertThat(maybeUser.orElse(null).getEmail()).isEqualTo(user.getEmail()); + assertThat(maybeUser.orElse(null).getResetDate()).isNotNull(); + assertThat(maybeUser.orElse(null).getResetKey()).isNotNull(); + } + + @Test + @Transactional + public void assertThatOnlyActivatedUserCanRequestPasswordReset() { + user.setActivated(false); + userRepository.saveAndFlush(user); + + Optional maybeUser = userService.requestPasswordReset(user.getLogin()); + assertThat(maybeUser).isNotPresent(); + userRepository.delete(user); + } + + @Test + @Transactional + public void assertThatResetKeyMustNotBeOlderThan24Hours() { + Instant daysAgo = Instant.now().minus(25, ChronoUnit.HOURS); + String resetKey = RandomUtil.generateResetKey(); + user.setActivated(true); + user.setResetDate(daysAgo); + user.setResetKey(resetKey); + userRepository.saveAndFlush(user); + + Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); + assertThat(maybeUser).isNotPresent(); + userRepository.delete(user); + } + + @Test + @Transactional + public void assertThatResetKeyMustBeValid() { + Instant daysAgo = Instant.now().minus(25, ChronoUnit.HOURS); + user.setActivated(true); + user.setResetDate(daysAgo); + user.setResetKey("1234"); + userRepository.saveAndFlush(user); + + Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); + assertThat(maybeUser).isNotPresent(); + userRepository.delete(user); + } + + @Test + @Transactional + public void assertThatUserCanResetPassword() { + String oldPassword = user.getPassword(); + Instant daysAgo = Instant.now().minus(2, ChronoUnit.HOURS); + String resetKey = RandomUtil.generateResetKey(); + user.setActivated(true); + user.setResetDate(daysAgo); + user.setResetKey(resetKey); + userRepository.saveAndFlush(user); + + Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); + assertThat(maybeUser).isPresent(); + assertThat(maybeUser.orElse(null).getResetDate()).isNull(); + assertThat(maybeUser.orElse(null).getResetKey()).isNull(); + assertThat(maybeUser.orElse(null).getPassword()).isNotEqualTo(oldPassword); + + userRepository.delete(user); + } + + @Test + @Transactional + public void testFindNotActivatedUsersByCreationDateBefore() { + Instant now = Instant.now(); + when(dateTimeProvider.getNow()).thenReturn(Optional.of(now.minus(4, ChronoUnit.DAYS))); + user.setActivated(false); + User dbUser = userRepository.saveAndFlush(user); + dbUser.setCreatedDate(now.minus(4, ChronoUnit.DAYS)); + userRepository.saveAndFlush(user); + List users = userRepository.findAllByActivatedIsFalseAndCreatedDateBefore(now.minus(3, ChronoUnit.DAYS)); + assertThat(users).isNotEmpty(); + userService.removeNotActivatedUsers(); + users = userRepository.findAllByActivatedIsFalseAndCreatedDateBefore(now.minus(3, ChronoUnit.DAYS)); + assertThat(users).isEmpty(); + } + + @Test + @Transactional + public void assertThatAnonymousUserIsNotGet() { + user.setLogin(Constants.ANONYMOUS_USER); + if (!userRepository.findOneByLogin(Constants.ANONYMOUS_USER).isPresent()) { + userRepository.saveAndFlush(user); + } + final PageRequest pageable = PageRequest.of(0, (int) userRepository.count()); + final Page allManagedUsers = userService.getAllManagedUsers(pageable); + assertThat(allManagedUsers.getContent().stream() + .noneMatch(user -> Constants.ANONYMOUS_USER.equals(user.getLogin()))) + .isTrue(); + } + + + @Test + @Transactional + public void testRemoveNotActivatedUsers() { + // custom "now" for audit to use as creation date + when(dateTimeProvider.getNow()).thenReturn(Optional.of(Instant.now().minus(30, ChronoUnit.DAYS))); + + user.setActivated(false); + userRepository.saveAndFlush(user); + + assertThat(userRepository.findOneByLogin("johndoe")).isPresent(); + userService.removeNotActivatedUsers(); + assertThat(userRepository.findOneByLogin("johndoe")).isNotPresent(); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperTest.java new file mode 100644 index 0000000000..3d66fa5813 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperTest.java @@ -0,0 +1,150 @@ +package com.baeldung.jhipster5.service.mapper; + + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.service.dto.UserDTO; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test class for the UserMapper. + * + * @see UserMapper + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class UserMapperTest { + + private static final String DEFAULT_LOGIN = "johndoe"; + + @Autowired + private UserMapper userMapper; + + private User user; + private UserDTO userDto; + + private static final Long DEFAULT_ID = 1L; + + @Before + public void init() { + user = new User(); + user.setLogin(DEFAULT_LOGIN); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setEmail("johndoe@localhost"); + user.setFirstName("john"); + user.setLastName("doe"); + user.setImageUrl("image_url"); + user.setLangKey("en"); + + userDto = new UserDTO(user); + } + + @Test + public void usersToUserDTOsShouldMapOnlyNonNullUsers(){ + List users = new ArrayList<>(); + users.add(user); + users.add(null); + + List userDTOS = userMapper.usersToUserDTOs(users); + + assertThat(userDTOS).isNotEmpty(); + assertThat(userDTOS).size().isEqualTo(1); + } + + @Test + public void userDTOsToUsersShouldMapOnlyNonNullUsers(){ + List usersDto = new ArrayList<>(); + usersDto.add(userDto); + usersDto.add(null); + + List users = userMapper.userDTOsToUsers(usersDto); + + assertThat(users).isNotEmpty(); + assertThat(users).size().isEqualTo(1); + } + + @Test + public void userDTOsToUsersWithAuthoritiesStringShouldMapToUsersWithAuthoritiesDomain(){ + Set authoritiesAsString = new HashSet<>(); + authoritiesAsString.add("ADMIN"); + userDto.setAuthorities(authoritiesAsString); + + List usersDto = new ArrayList<>(); + usersDto.add(userDto); + + List users = userMapper.userDTOsToUsers(usersDto); + + assertThat(users).isNotEmpty(); + assertThat(users).size().isEqualTo(1); + assertThat(users.get(0).getAuthorities()).isNotNull(); + assertThat(users.get(0).getAuthorities()).isNotEmpty(); + assertThat(users.get(0).getAuthorities().iterator().next().getName()).isEqualTo("ADMIN"); + } + + @Test + public void userDTOsToUsersMapWithNullAuthoritiesStringShouldReturnUserWithEmptyAuthorities(){ + userDto.setAuthorities(null); + + List usersDto = new ArrayList<>(); + usersDto.add(userDto); + + List users = userMapper.userDTOsToUsers(usersDto); + + assertThat(users).isNotEmpty(); + assertThat(users).size().isEqualTo(1); + assertThat(users.get(0).getAuthorities()).isNotNull(); + assertThat(users.get(0).getAuthorities()).isEmpty(); + } + + @Test + public void userDTOToUserMapWithAuthoritiesStringShouldReturnUserWithAuthorities(){ + Set authoritiesAsString = new HashSet<>(); + authoritiesAsString.add("ADMIN"); + userDto.setAuthorities(authoritiesAsString); + + userDto.setAuthorities(authoritiesAsString); + + User user = userMapper.userDTOToUser(userDto); + + assertThat(user).isNotNull(); + assertThat(user.getAuthorities()).isNotNull(); + assertThat(user.getAuthorities()).isNotEmpty(); + assertThat(user.getAuthorities().iterator().next().getName()).isEqualTo("ADMIN"); + } + + @Test + public void userDTOToUserMapWithNullAuthoritiesStringShouldReturnUserWithEmptyAuthorities(){ + userDto.setAuthorities(null); + + User user = userMapper.userDTOToUser(userDto); + + assertThat(user).isNotNull(); + assertThat(user.getAuthorities()).isNotNull(); + assertThat(user.getAuthorities()).isEmpty(); + } + + @Test + public void userDTOToUserMapWithNullUserShouldReturnNull(){ + assertThat(userMapper.userDTOToUser(null)).isNull(); + } + + @Test + public void testUserFromId() { + assertThat(userMapper.userFromId(DEFAULT_ID).getId()).isEqualTo(DEFAULT_ID); + assertThat(userMapper.userFromId(null)).isNull(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AccountResourceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AccountResourceIntTest.java new file mode 100644 index 0000000000..6db284a87f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AccountResourceIntTest.java @@ -0,0 +1,818 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.config.Constants; +import com.baeldung.jhipster5.domain.Authority; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.AuthorityRepository; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.AuthoritiesConstants; +import com.baeldung.jhipster5.service.MailService; +import com.baeldung.jhipster5.service.UserService; +import com.baeldung.jhipster5.service.dto.PasswordChangeDTO; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.web.rest.errors.ExceptionTranslator; +import com.baeldung.jhipster5.web.rest.vm.KeyAndPasswordVM; +import com.baeldung.jhipster5.web.rest.vm.ManagedUserVM; +import org.apache.commons.lang3.RandomStringUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the AccountResource REST controller. + * + * @see AccountResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class AccountResourceIntTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private AuthorityRepository authorityRepository; + + @Autowired + private UserService userService; + + @Autowired + private PasswordEncoder passwordEncoder; + + @Autowired + private HttpMessageConverter[] httpMessageConverters; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Mock + private UserService mockUserService; + + @Mock + private MailService mockMailService; + + private MockMvc restMvc; + + private MockMvc restUserMockMvc; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + doNothing().when(mockMailService).sendActivationEmail(any()); + AccountResource accountResource = + new AccountResource(userRepository, userService, mockMailService); + + AccountResource accountUserMockResource = + new AccountResource(userRepository, mockUserService, mockMailService); + this.restMvc = MockMvcBuilders.standaloneSetup(accountResource) + .setMessageConverters(httpMessageConverters) + .setControllerAdvice(exceptionTranslator) + .build(); + this.restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource) + .setControllerAdvice(exceptionTranslator) + .build(); + } + + @Test + public void testNonAuthenticatedUser() throws Exception { + restUserMockMvc.perform(get("/api/authenticate") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string("")); + } + + @Test + public void testAuthenticatedUser() throws Exception { + restUserMockMvc.perform(get("/api/authenticate") + .with(request -> { + request.setRemoteUser("test"); + return request; + }) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string("test")); + } + + @Test + public void testGetExistingAccount() throws Exception { + Set authorities = new HashSet<>(); + Authority authority = new Authority(); + authority.setName(AuthoritiesConstants.ADMIN); + authorities.add(authority); + + User user = new User(); + user.setLogin("test"); + user.setFirstName("john"); + user.setLastName("doe"); + user.setEmail("john.doe@jhipster.com"); + user.setImageUrl("http://placehold.it/50x50"); + user.setLangKey("en"); + user.setAuthorities(authorities); + when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.of(user)); + + restUserMockMvc.perform(get("/api/account") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.login").value("test")) + .andExpect(jsonPath("$.firstName").value("john")) + .andExpect(jsonPath("$.lastName").value("doe")) + .andExpect(jsonPath("$.email").value("john.doe@jhipster.com")) + .andExpect(jsonPath("$.imageUrl").value("http://placehold.it/50x50")) + .andExpect(jsonPath("$.langKey").value("en")) + .andExpect(jsonPath("$.authorities").value(AuthoritiesConstants.ADMIN)); + } + + @Test + public void testGetUnknownAccount() throws Exception { + when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.empty()); + + restUserMockMvc.perform(get("/api/account") + .accept(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(status().isInternalServerError()); + } + + @Test + @Transactional + public void testRegisterValid() throws Exception { + ManagedUserVM validUser = new ManagedUserVM(); + validUser.setLogin("test-register-valid"); + validUser.setPassword("password"); + validUser.setFirstName("Alice"); + validUser.setLastName("Test"); + validUser.setEmail("test-register-valid@example.com"); + validUser.setImageUrl("http://placehold.it/50x50"); + validUser.setLangKey(Constants.DEFAULT_LANGUAGE); + validUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + assertThat(userRepository.findOneByLogin("test-register-valid").isPresent()).isFalse(); + + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(validUser))) + .andExpect(status().isCreated()); + + assertThat(userRepository.findOneByLogin("test-register-valid").isPresent()).isTrue(); + } + + @Test + @Transactional + public void testRegisterInvalidLogin() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM(); + invalidUser.setLogin("funky-log!n");// <-- invalid + invalidUser.setPassword("password"); + invalidUser.setFirstName("Funky"); + invalidUser.setLastName("One"); + invalidUser.setEmail("funky@example.com"); + invalidUser.setActivated(true); + invalidUser.setImageUrl("http://placehold.it/50x50"); + invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); + invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByEmailIgnoreCase("funky@example.com"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterInvalidEmail() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM(); + invalidUser.setLogin("bob"); + invalidUser.setPassword("password"); + invalidUser.setFirstName("Bob"); + invalidUser.setLastName("Green"); + invalidUser.setEmail("invalid");// <-- invalid + invalidUser.setActivated(true); + invalidUser.setImageUrl("http://placehold.it/50x50"); + invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); + invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByLogin("bob"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterInvalidPassword() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM(); + invalidUser.setLogin("bob"); + invalidUser.setPassword("123");// password with only 3 digits + invalidUser.setFirstName("Bob"); + invalidUser.setLastName("Green"); + invalidUser.setEmail("bob@example.com"); + invalidUser.setActivated(true); + invalidUser.setImageUrl("http://placehold.it/50x50"); + invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); + invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByLogin("bob"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterNullPassword() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM(); + invalidUser.setLogin("bob"); + invalidUser.setPassword(null);// invalid null password + invalidUser.setFirstName("Bob"); + invalidUser.setLastName("Green"); + invalidUser.setEmail("bob@example.com"); + invalidUser.setActivated(true); + invalidUser.setImageUrl("http://placehold.it/50x50"); + invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); + invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByLogin("bob"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterDuplicateLogin() throws Exception { + // First registration + ManagedUserVM firstUser = new ManagedUserVM(); + firstUser.setLogin("alice"); + firstUser.setPassword("password"); + firstUser.setFirstName("Alice"); + firstUser.setLastName("Something"); + firstUser.setEmail("alice@example.com"); + firstUser.setImageUrl("http://placehold.it/50x50"); + firstUser.setLangKey(Constants.DEFAULT_LANGUAGE); + firstUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + // Duplicate login, different email + ManagedUserVM secondUser = new ManagedUserVM(); + secondUser.setLogin(firstUser.getLogin()); + secondUser.setPassword(firstUser.getPassword()); + secondUser.setFirstName(firstUser.getFirstName()); + secondUser.setLastName(firstUser.getLastName()); + secondUser.setEmail("alice2@example.com"); + secondUser.setImageUrl(firstUser.getImageUrl()); + secondUser.setLangKey(firstUser.getLangKey()); + secondUser.setCreatedBy(firstUser.getCreatedBy()); + secondUser.setCreatedDate(firstUser.getCreatedDate()); + secondUser.setLastModifiedBy(firstUser.getLastModifiedBy()); + secondUser.setLastModifiedDate(firstUser.getLastModifiedDate()); + secondUser.setAuthorities(new HashSet<>(firstUser.getAuthorities())); + + // First user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(firstUser))) + .andExpect(status().isCreated()); + + // Second (non activated) user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(secondUser))) + .andExpect(status().isCreated()); + + Optional testUser = userRepository.findOneByEmailIgnoreCase("alice2@example.com"); + assertThat(testUser.isPresent()).isTrue(); + testUser.get().setActivated(true); + userRepository.save(testUser.get()); + + // Second (already activated) user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(secondUser))) + .andExpect(status().is4xxClientError()); + } + + @Test + @Transactional + public void testRegisterDuplicateEmail() throws Exception { + // First user + ManagedUserVM firstUser = new ManagedUserVM(); + firstUser.setLogin("test-register-duplicate-email"); + firstUser.setPassword("password"); + firstUser.setFirstName("Alice"); + firstUser.setLastName("Test"); + firstUser.setEmail("test-register-duplicate-email@example.com"); + firstUser.setImageUrl("http://placehold.it/50x50"); + firstUser.setLangKey(Constants.DEFAULT_LANGUAGE); + firstUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + // Register first user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(firstUser))) + .andExpect(status().isCreated()); + + Optional testUser1 = userRepository.findOneByLogin("test-register-duplicate-email"); + assertThat(testUser1.isPresent()).isTrue(); + + // Duplicate email, different login + ManagedUserVM secondUser = new ManagedUserVM(); + secondUser.setLogin("test-register-duplicate-email-2"); + secondUser.setPassword(firstUser.getPassword()); + secondUser.setFirstName(firstUser.getFirstName()); + secondUser.setLastName(firstUser.getLastName()); + secondUser.setEmail(firstUser.getEmail()); + secondUser.setImageUrl(firstUser.getImageUrl()); + secondUser.setLangKey(firstUser.getLangKey()); + secondUser.setAuthorities(new HashSet<>(firstUser.getAuthorities())); + + // Register second (non activated) user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(secondUser))) + .andExpect(status().isCreated()); + + Optional testUser2 = userRepository.findOneByLogin("test-register-duplicate-email"); + assertThat(testUser2.isPresent()).isFalse(); + + Optional testUser3 = userRepository.findOneByLogin("test-register-duplicate-email-2"); + assertThat(testUser3.isPresent()).isTrue(); + + // Duplicate email - with uppercase email address + ManagedUserVM userWithUpperCaseEmail = new ManagedUserVM(); + userWithUpperCaseEmail.setId(firstUser.getId()); + userWithUpperCaseEmail.setLogin("test-register-duplicate-email-3"); + userWithUpperCaseEmail.setPassword(firstUser.getPassword()); + userWithUpperCaseEmail.setFirstName(firstUser.getFirstName()); + userWithUpperCaseEmail.setLastName(firstUser.getLastName()); + userWithUpperCaseEmail.setEmail("TEST-register-duplicate-email@example.com"); + userWithUpperCaseEmail.setImageUrl(firstUser.getImageUrl()); + userWithUpperCaseEmail.setLangKey(firstUser.getLangKey()); + userWithUpperCaseEmail.setAuthorities(new HashSet<>(firstUser.getAuthorities())); + + // Register third (not activated) user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(userWithUpperCaseEmail))) + .andExpect(status().isCreated()); + + Optional testUser4 = userRepository.findOneByLogin("test-register-duplicate-email-3"); + assertThat(testUser4.isPresent()).isTrue(); + assertThat(testUser4.get().getEmail()).isEqualTo("test-register-duplicate-email@example.com"); + + testUser4.get().setActivated(true); + userService.updateUser((new UserDTO(testUser4.get()))); + + // Register 4th (already activated) user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(secondUser))) + .andExpect(status().is4xxClientError()); + } + + @Test + @Transactional + public void testRegisterAdminIsIgnored() throws Exception { + ManagedUserVM validUser = new ManagedUserVM(); + validUser.setLogin("badguy"); + validUser.setPassword("password"); + validUser.setFirstName("Bad"); + validUser.setLastName("Guy"); + validUser.setEmail("badguy@example.com"); + validUser.setActivated(true); + validUser.setImageUrl("http://placehold.it/50x50"); + validUser.setLangKey(Constants.DEFAULT_LANGUAGE); + validUser.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); + + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(validUser))) + .andExpect(status().isCreated()); + + Optional userDup = userRepository.findOneByLogin("badguy"); + assertThat(userDup.isPresent()).isTrue(); + assertThat(userDup.get().getAuthorities()).hasSize(1) + .containsExactly(authorityRepository.findById(AuthoritiesConstants.USER).get()); + } + + @Test + @Transactional + public void testActivateAccount() throws Exception { + final String activationKey = "some activation key"; + User user = new User(); + user.setLogin("activate-account"); + user.setEmail("activate-account@example.com"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(false); + user.setActivationKey(activationKey); + + userRepository.saveAndFlush(user); + + restMvc.perform(get("/api/activate?key={activationKey}", activationKey)) + .andExpect(status().isOk()); + + user = userRepository.findOneByLogin(user.getLogin()).orElse(null); + assertThat(user.getActivated()).isTrue(); + } + + @Test + @Transactional + public void testActivateAccountWithWrongKey() throws Exception { + restMvc.perform(get("/api/activate?key=wrongActivationKey")) + .andExpect(status().isInternalServerError()); + } + + @Test + @Transactional + @WithMockUser("save-account") + public void testSaveAccount() throws Exception { + User user = new User(); + user.setLogin("save-account"); + user.setEmail("save-account@example.com"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + + userRepository.saveAndFlush(user); + + UserDTO userDTO = new UserDTO(); + userDTO.setLogin("not-used"); + userDTO.setFirstName("firstname"); + userDTO.setLastName("lastname"); + userDTO.setEmail("save-account@example.com"); + userDTO.setActivated(false); + userDTO.setImageUrl("http://placehold.it/50x50"); + userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); + userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); + + restMvc.perform( + post("/api/account") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(userDTO))) + .andExpect(status().isOk()); + + User updatedUser = userRepository.findOneByLogin(user.getLogin()).orElse(null); + assertThat(updatedUser.getFirstName()).isEqualTo(userDTO.getFirstName()); + assertThat(updatedUser.getLastName()).isEqualTo(userDTO.getLastName()); + assertThat(updatedUser.getEmail()).isEqualTo(userDTO.getEmail()); + assertThat(updatedUser.getLangKey()).isEqualTo(userDTO.getLangKey()); + assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); + assertThat(updatedUser.getImageUrl()).isEqualTo(userDTO.getImageUrl()); + assertThat(updatedUser.getActivated()).isEqualTo(true); + assertThat(updatedUser.getAuthorities()).isEmpty(); + } + + @Test + @Transactional + @WithMockUser("save-invalid-email") + public void testSaveInvalidEmail() throws Exception { + User user = new User(); + user.setLogin("save-invalid-email"); + user.setEmail("save-invalid-email@example.com"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + + userRepository.saveAndFlush(user); + + UserDTO userDTO = new UserDTO(); + userDTO.setLogin("not-used"); + userDTO.setFirstName("firstname"); + userDTO.setLastName("lastname"); + userDTO.setEmail("invalid email"); + userDTO.setActivated(false); + userDTO.setImageUrl("http://placehold.it/50x50"); + userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); + userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); + + restMvc.perform( + post("/api/account") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(userDTO))) + .andExpect(status().isBadRequest()); + + assertThat(userRepository.findOneByEmailIgnoreCase("invalid email")).isNotPresent(); + } + + @Test + @Transactional + @WithMockUser("save-existing-email") + public void testSaveExistingEmail() throws Exception { + User user = new User(); + user.setLogin("save-existing-email"); + user.setEmail("save-existing-email@example.com"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + + userRepository.saveAndFlush(user); + + User anotherUser = new User(); + anotherUser.setLogin("save-existing-email2"); + anotherUser.setEmail("save-existing-email2@example.com"); + anotherUser.setPassword(RandomStringUtils.random(60)); + anotherUser.setActivated(true); + + userRepository.saveAndFlush(anotherUser); + + UserDTO userDTO = new UserDTO(); + userDTO.setLogin("not-used"); + userDTO.setFirstName("firstname"); + userDTO.setLastName("lastname"); + userDTO.setEmail("save-existing-email2@example.com"); + userDTO.setActivated(false); + userDTO.setImageUrl("http://placehold.it/50x50"); + userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); + userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); + + restMvc.perform( + post("/api/account") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(userDTO))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin("save-existing-email").orElse(null); + assertThat(updatedUser.getEmail()).isEqualTo("save-existing-email@example.com"); + } + + @Test + @Transactional + @WithMockUser("save-existing-email-and-login") + public void testSaveExistingEmailAndLogin() throws Exception { + User user = new User(); + user.setLogin("save-existing-email-and-login"); + user.setEmail("save-existing-email-and-login@example.com"); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + + userRepository.saveAndFlush(user); + + UserDTO userDTO = new UserDTO(); + userDTO.setLogin("not-used"); + userDTO.setFirstName("firstname"); + userDTO.setLastName("lastname"); + userDTO.setEmail("save-existing-email-and-login@example.com"); + userDTO.setActivated(false); + userDTO.setImageUrl("http://placehold.it/50x50"); + userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); + userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); + + restMvc.perform( + post("/api/account") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(userDTO))) + .andExpect(status().isOk()); + + User updatedUser = userRepository.findOneByLogin("save-existing-email-and-login").orElse(null); + assertThat(updatedUser.getEmail()).isEqualTo("save-existing-email-and-login@example.com"); + } + + @Test + @Transactional + @WithMockUser("change-password-wrong-existing-password") + public void testChangePasswordWrongExistingPassword() throws Exception { + User user = new User(); + String currentPassword = RandomStringUtils.random(60); + user.setPassword(passwordEncoder.encode(currentPassword)); + user.setLogin("change-password-wrong-existing-password"); + user.setEmail("change-password-wrong-existing-password@example.com"); + userRepository.saveAndFlush(user); + + restMvc.perform(post("/api/account/change-password") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO("1"+currentPassword, "new password")))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin("change-password-wrong-existing-password").orElse(null); + assertThat(passwordEncoder.matches("new password", updatedUser.getPassword())).isFalse(); + assertThat(passwordEncoder.matches(currentPassword, updatedUser.getPassword())).isTrue(); + } + + @Test + @Transactional + @WithMockUser("change-password") + public void testChangePassword() throws Exception { + User user = new User(); + String currentPassword = RandomStringUtils.random(60); + user.setPassword(passwordEncoder.encode(currentPassword)); + user.setLogin("change-password"); + user.setEmail("change-password@example.com"); + userRepository.saveAndFlush(user); + + restMvc.perform(post("/api/account/change-password") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, "new password")))) + .andExpect(status().isOk()); + + User updatedUser = userRepository.findOneByLogin("change-password").orElse(null); + assertThat(passwordEncoder.matches("new password", updatedUser.getPassword())).isTrue(); + } + + @Test + @Transactional + @WithMockUser("change-password-too-small") + public void testChangePasswordTooSmall() throws Exception { + User user = new User(); + String currentPassword = RandomStringUtils.random(60); + user.setPassword(passwordEncoder.encode(currentPassword)); + user.setLogin("change-password-too-small"); + user.setEmail("change-password-too-small@example.com"); + userRepository.saveAndFlush(user); + + String newPassword = RandomStringUtils.random(ManagedUserVM.PASSWORD_MIN_LENGTH - 1); + + restMvc.perform(post("/api/account/change-password") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, newPassword)))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin("change-password-too-small").orElse(null); + assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); + } + + @Test + @Transactional + @WithMockUser("change-password-too-long") + public void testChangePasswordTooLong() throws Exception { + User user = new User(); + String currentPassword = RandomStringUtils.random(60); + user.setPassword(passwordEncoder.encode(currentPassword)); + user.setLogin("change-password-too-long"); + user.setEmail("change-password-too-long@example.com"); + userRepository.saveAndFlush(user); + + String newPassword = RandomStringUtils.random(ManagedUserVM.PASSWORD_MAX_LENGTH + 1); + + restMvc.perform(post("/api/account/change-password") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, newPassword)))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin("change-password-too-long").orElse(null); + assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); + } + + @Test + @Transactional + @WithMockUser("change-password-empty") + public void testChangePasswordEmpty() throws Exception { + User user = new User(); + String currentPassword = RandomStringUtils.random(60); + user.setPassword(passwordEncoder.encode(currentPassword)); + user.setLogin("change-password-empty"); + user.setEmail("change-password-empty@example.com"); + userRepository.saveAndFlush(user); + + restMvc.perform(post("/api/account/change-password") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, "")))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin("change-password-empty").orElse(null); + assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); + } + + @Test + @Transactional + public void testRequestPasswordReset() throws Exception { + User user = new User(); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setLogin("password-reset"); + user.setEmail("password-reset@example.com"); + userRepository.saveAndFlush(user); + + restMvc.perform(post("/api/account/reset-password/init") + .content("password-reset@example.com")) + .andExpect(status().isOk()); + } + + @Test + @Transactional + public void testRequestPasswordResetUpperCaseEmail() throws Exception { + User user = new User(); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setLogin("password-reset"); + user.setEmail("password-reset@example.com"); + userRepository.saveAndFlush(user); + + restMvc.perform(post("/api/account/reset-password/init") + .content("password-reset@EXAMPLE.COM")) + .andExpect(status().isOk()); + } + + @Test + public void testRequestPasswordResetWrongEmail() throws Exception { + restMvc.perform( + post("/api/account/reset-password/init") + .content("password-reset-wrong-email@example.com")) + .andExpect(status().isBadRequest()); + } + + @Test + @Transactional + public void testFinishPasswordReset() throws Exception { + User user = new User(); + user.setPassword(RandomStringUtils.random(60)); + user.setLogin("finish-password-reset"); + user.setEmail("finish-password-reset@example.com"); + user.setResetDate(Instant.now().plusSeconds(60)); + user.setResetKey("reset key"); + userRepository.saveAndFlush(user); + + KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM(); + keyAndPassword.setKey(user.getResetKey()); + keyAndPassword.setNewPassword("new password"); + + restMvc.perform( + post("/api/account/reset-password/finish") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(keyAndPassword))) + .andExpect(status().isOk()); + + User updatedUser = userRepository.findOneByLogin(user.getLogin()).orElse(null); + assertThat(passwordEncoder.matches(keyAndPassword.getNewPassword(), updatedUser.getPassword())).isTrue(); + } + + @Test + @Transactional + public void testFinishPasswordResetTooSmall() throws Exception { + User user = new User(); + user.setPassword(RandomStringUtils.random(60)); + user.setLogin("finish-password-reset-too-small"); + user.setEmail("finish-password-reset-too-small@example.com"); + user.setResetDate(Instant.now().plusSeconds(60)); + user.setResetKey("reset key too small"); + userRepository.saveAndFlush(user); + + KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM(); + keyAndPassword.setKey(user.getResetKey()); + keyAndPassword.setNewPassword("foo"); + + restMvc.perform( + post("/api/account/reset-password/finish") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(keyAndPassword))) + .andExpect(status().isBadRequest()); + + User updatedUser = userRepository.findOneByLogin(user.getLogin()).orElse(null); + assertThat(passwordEncoder.matches(keyAndPassword.getNewPassword(), updatedUser.getPassword())).isFalse(); + } + + + @Test + @Transactional + public void testFinishPasswordResetWrongKey() throws Exception { + KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM(); + keyAndPassword.setKey("wrong reset key"); + keyAndPassword.setNewPassword("new password"); + + restMvc.perform( + post("/api/account/reset-password/finish") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(keyAndPassword))) + .andExpect(status().isInternalServerError()); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AuditResourceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AuditResourceIntTest.java new file mode 100644 index 0000000000..c3b91ab390 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/AuditResourceIntTest.java @@ -0,0 +1,162 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.config.audit.AuditEventConverter; +import com.baeldung.jhipster5.domain.PersistentAuditEvent; +import com.baeldung.jhipster5.repository.PersistenceAuditEventRepository; +import com.baeldung.jhipster5.service.AuditEventService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.format.support.FormattingConversionService; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the AuditResource REST controller. + * + * @see AuditResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +@Transactional +public class AuditResourceIntTest { + + private static final String SAMPLE_PRINCIPAL = "SAMPLE_PRINCIPAL"; + private static final String SAMPLE_TYPE = "SAMPLE_TYPE"; + private static final Instant SAMPLE_TIMESTAMP = Instant.parse("2015-08-04T10:11:30Z"); + private static final long SECONDS_PER_DAY = 60 * 60 * 24; + + @Autowired + private PersistenceAuditEventRepository auditEventRepository; + + @Autowired + private AuditEventConverter auditEventConverter; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + @Autowired + private FormattingConversionService formattingConversionService; + + @Autowired + private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + + private PersistentAuditEvent auditEvent; + + private MockMvc restAuditMockMvc; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + AuditEventService auditEventService = + new AuditEventService(auditEventRepository, auditEventConverter); + AuditResource auditResource = new AuditResource(auditEventService); + this.restAuditMockMvc = MockMvcBuilders.standaloneSetup(auditResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setConversionService(formattingConversionService) + .setMessageConverters(jacksonMessageConverter).build(); + } + + @Before + public void initTest() { + auditEventRepository.deleteAll(); + auditEvent = new PersistentAuditEvent(); + auditEvent.setAuditEventType(SAMPLE_TYPE); + auditEvent.setPrincipal(SAMPLE_PRINCIPAL); + auditEvent.setAuditEventDate(SAMPLE_TIMESTAMP); + } + + @Test + public void getAllAudits() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Get all the audits + restAuditMockMvc.perform(get("/management/audits")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].principal").value(hasItem(SAMPLE_PRINCIPAL))); + } + + @Test + public void getAudit() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Get the audit + restAuditMockMvc.perform(get("/management/audits/{id}", auditEvent.getId())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.principal").value(SAMPLE_PRINCIPAL)); + } + + @Test + public void getAuditsByDate() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Generate dates for selecting audits by date, making sure the period will contain the audit + String fromDate = SAMPLE_TIMESTAMP.minusSeconds(SECONDS_PER_DAY).toString().substring(0, 10); + String toDate = SAMPLE_TIMESTAMP.plusSeconds(SECONDS_PER_DAY).toString().substring(0, 10); + + // Get the audit + restAuditMockMvc.perform(get("/management/audits?fromDate="+fromDate+"&toDate="+toDate)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].principal").value(hasItem(SAMPLE_PRINCIPAL))); + } + + @Test + public void getNonExistingAuditsByDate() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Generate dates for selecting audits by date, making sure the period will not contain the sample audit + String fromDate = SAMPLE_TIMESTAMP.minusSeconds(2*SECONDS_PER_DAY).toString().substring(0, 10); + String toDate = SAMPLE_TIMESTAMP.minusSeconds(SECONDS_PER_DAY).toString().substring(0, 10); + + // Query audits but expect no results + restAuditMockMvc.perform(get("/management/audits?fromDate=" + fromDate + "&toDate=" + toDate)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(header().string("X-Total-Count", "0")); + } + + @Test + public void getNonExistingAudit() throws Exception { + // Get the audit + restAuditMockMvc.perform(get("/management/audits/{id}", Long.MAX_VALUE)) + .andExpect(status().isNotFound()); + } + + @Test + @Transactional + public void testPersistentAuditEventEquals() throws Exception { + TestUtil.equalsVerifier(PersistentAuditEvent.class); + PersistentAuditEvent auditEvent1 = new PersistentAuditEvent(); + auditEvent1.setId(1L); + PersistentAuditEvent auditEvent2 = new PersistentAuditEvent(); + auditEvent2.setId(auditEvent1.getId()); + assertThat(auditEvent1).isEqualTo(auditEvent2); + auditEvent2.setId(2L); + assertThat(auditEvent1).isNotEqualTo(auditEvent2); + auditEvent1.setId(null); + assertThat(auditEvent1).isNotEqualTo(auditEvent2); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/BookResourceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/BookResourceIntTest.java new file mode 100644 index 0000000000..ef8f27ceea --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/BookResourceIntTest.java @@ -0,0 +1,416 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; + +import com.baeldung.jhipster5.domain.Book; +import com.baeldung.jhipster5.repository.BookRepository; +import com.baeldung.jhipster5.service.BookService; +import com.baeldung.jhipster5.service.dto.BookDTO; +import com.baeldung.jhipster5.service.mapper.BookMapper; +import com.baeldung.jhipster5.web.rest.errors.ExceptionTranslator; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.Validator; + +import javax.persistence.EntityManager; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.List; + + +import static com.baeldung.jhipster5.web.rest.TestUtil.createFormattingConversionService; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the BookResource REST controller. + * + * @see BookResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class BookResourceIntTest { + + private static final String DEFAULT_TITLE = "AAAAAAAAAA"; + private static final String UPDATED_TITLE = "BBBBBBBBBB"; + + private static final String DEFAULT_AUTHOR = "AAAAAAAAAA"; + private static final String UPDATED_AUTHOR = "BBBBBBBBBB"; + + private static final LocalDate DEFAULT_PUBLISHED = LocalDate.ofEpochDay(0L); + private static final LocalDate UPDATED_PUBLISHED = LocalDate.now(ZoneId.systemDefault()); + + private static final Integer DEFAULT_QUANTITY = 0; + private static final Integer UPDATED_QUANTITY = 1; + + private static final Double DEFAULT_PRICE = 0D; + private static final Double UPDATED_PRICE = 1D; + + @Autowired + private BookRepository bookRepository; + + @Autowired + private BookMapper bookMapper; + + @Autowired + private BookService bookService; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + @Autowired + private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Autowired + private EntityManager em; + + @Autowired + private Validator validator; + + private MockMvc restBookMockMvc; + + private Book book; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + final BookResource bookResource = new BookResource(bookService); + this.restBookMockMvc = MockMvcBuilders.standaloneSetup(bookResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setConversionService(createFormattingConversionService()) + .setMessageConverters(jacksonMessageConverter) + .setValidator(validator).build(); + } + + /** + * Create an entity for this test. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + public static Book createEntity(EntityManager em) { + Book book = new Book() + .title(DEFAULT_TITLE) + .author(DEFAULT_AUTHOR) + .published(DEFAULT_PUBLISHED) + .quantity(DEFAULT_QUANTITY) + .price(DEFAULT_PRICE); + return book; + } + + @Before + public void initTest() { + book = createEntity(em); + } + + @Test + @Transactional + public void createBook() throws Exception { + int databaseSizeBeforeCreate = bookRepository.findAll().size(); + + // Create the Book + BookDTO bookDTO = bookMapper.toDto(book); + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isCreated()); + + // Validate the Book in the database + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeCreate + 1); + Book testBook = bookList.get(bookList.size() - 1); + assertThat(testBook.getTitle()).isEqualTo(DEFAULT_TITLE); + assertThat(testBook.getAuthor()).isEqualTo(DEFAULT_AUTHOR); + assertThat(testBook.getPublished()).isEqualTo(DEFAULT_PUBLISHED); + assertThat(testBook.getQuantity()).isEqualTo(DEFAULT_QUANTITY); + assertThat(testBook.getPrice()).isEqualTo(DEFAULT_PRICE); + } + + @Test + @Transactional + public void createBookWithExistingId() throws Exception { + int databaseSizeBeforeCreate = bookRepository.findAll().size(); + + // Create the Book with an existing ID + book.setId(1L); + BookDTO bookDTO = bookMapper.toDto(book); + + // An entity with an existing ID cannot be created, so this API call must fail + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + // Validate the Book in the database + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void checkTitleIsRequired() throws Exception { + int databaseSizeBeforeTest = bookRepository.findAll().size(); + // set the field null + book.setTitle(null); + + // Create the Book, which fails. + BookDTO bookDTO = bookMapper.toDto(book); + + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkAuthorIsRequired() throws Exception { + int databaseSizeBeforeTest = bookRepository.findAll().size(); + // set the field null + book.setAuthor(null); + + // Create the Book, which fails. + BookDTO bookDTO = bookMapper.toDto(book); + + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkPublishedIsRequired() throws Exception { + int databaseSizeBeforeTest = bookRepository.findAll().size(); + // set the field null + book.setPublished(null); + + // Create the Book, which fails. + BookDTO bookDTO = bookMapper.toDto(book); + + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkQuantityIsRequired() throws Exception { + int databaseSizeBeforeTest = bookRepository.findAll().size(); + // set the field null + book.setQuantity(null); + + // Create the Book, which fails. + BookDTO bookDTO = bookMapper.toDto(book); + + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkPriceIsRequired() throws Exception { + int databaseSizeBeforeTest = bookRepository.findAll().size(); + // set the field null + book.setPrice(null); + + // Create the Book, which fails. + BookDTO bookDTO = bookMapper.toDto(book); + + restBookMockMvc.perform(post("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void getAllBooks() throws Exception { + // Initialize the database + bookRepository.saveAndFlush(book); + + // Get all the bookList + restBookMockMvc.perform(get("/api/books?sort=id,desc")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].id").value(hasItem(book.getId().intValue()))) + .andExpect(jsonPath("$.[*].title").value(hasItem(DEFAULT_TITLE.toString()))) + .andExpect(jsonPath("$.[*].author").value(hasItem(DEFAULT_AUTHOR.toString()))) + .andExpect(jsonPath("$.[*].published").value(hasItem(DEFAULT_PUBLISHED.toString()))) + .andExpect(jsonPath("$.[*].quantity").value(hasItem(DEFAULT_QUANTITY))) + .andExpect(jsonPath("$.[*].price").value(hasItem(DEFAULT_PRICE.doubleValue()))); + } + + @Test + @Transactional + public void getBook() throws Exception { + // Initialize the database + bookRepository.saveAndFlush(book); + + // Get the book + restBookMockMvc.perform(get("/api/books/{id}", book.getId())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.id").value(book.getId().intValue())) + .andExpect(jsonPath("$.title").value(DEFAULT_TITLE.toString())) + .andExpect(jsonPath("$.author").value(DEFAULT_AUTHOR.toString())) + .andExpect(jsonPath("$.published").value(DEFAULT_PUBLISHED.toString())) + .andExpect(jsonPath("$.quantity").value(DEFAULT_QUANTITY)) + .andExpect(jsonPath("$.price").value(DEFAULT_PRICE.doubleValue())); + } + + @Test + @Transactional + public void getNonExistingBook() throws Exception { + // Get the book + restBookMockMvc.perform(get("/api/books/{id}", Long.MAX_VALUE)) + .andExpect(status().isNotFound()); + } + + @Test + @Transactional + public void updateBook() throws Exception { + // Initialize the database + bookRepository.saveAndFlush(book); + + int databaseSizeBeforeUpdate = bookRepository.findAll().size(); + + // Update the book + Book updatedBook = bookRepository.findById(book.getId()).get(); + // Disconnect from session so that the updates on updatedBook are not directly saved in db + em.detach(updatedBook); + updatedBook + .title(UPDATED_TITLE) + .author(UPDATED_AUTHOR) + .published(UPDATED_PUBLISHED) + .quantity(UPDATED_QUANTITY) + .price(UPDATED_PRICE); + BookDTO bookDTO = bookMapper.toDto(updatedBook); + + restBookMockMvc.perform(put("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isOk()); + + // Validate the Book in the database + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeUpdate); + Book testBook = bookList.get(bookList.size() - 1); + assertThat(testBook.getTitle()).isEqualTo(UPDATED_TITLE); + assertThat(testBook.getAuthor()).isEqualTo(UPDATED_AUTHOR); + assertThat(testBook.getPublished()).isEqualTo(UPDATED_PUBLISHED); + assertThat(testBook.getQuantity()).isEqualTo(UPDATED_QUANTITY); + assertThat(testBook.getPrice()).isEqualTo(UPDATED_PRICE); + } + + @Test + @Transactional + public void updateNonExistingBook() throws Exception { + int databaseSizeBeforeUpdate = bookRepository.findAll().size(); + + // Create the Book + BookDTO bookDTO = bookMapper.toDto(book); + + // If the entity doesn't have an ID, it will throw BadRequestAlertException + restBookMockMvc.perform(put("/api/books") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(bookDTO))) + .andExpect(status().isBadRequest()); + + // Validate the Book in the database + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeUpdate); + } + + @Test + @Transactional + public void deleteBook() throws Exception { + // Initialize the database + bookRepository.saveAndFlush(book); + + int databaseSizeBeforeDelete = bookRepository.findAll().size(); + + // Delete the book + restBookMockMvc.perform(delete("/api/books/{id}", book.getId()) + .accept(TestUtil.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + + // Validate the database is empty + List bookList = bookRepository.findAll(); + assertThat(bookList).hasSize(databaseSizeBeforeDelete - 1); + } + + @Test + @Transactional + public void equalsVerifier() throws Exception { + TestUtil.equalsVerifier(Book.class); + Book book1 = new Book(); + book1.setId(1L); + Book book2 = new Book(); + book2.setId(book1.getId()); + assertThat(book1).isEqualTo(book2); + book2.setId(2L); + assertThat(book1).isNotEqualTo(book2); + book1.setId(null); + assertThat(book1).isNotEqualTo(book2); + } + + @Test + @Transactional + public void dtoEqualsVerifier() throws Exception { + TestUtil.equalsVerifier(BookDTO.class); + BookDTO bookDTO1 = new BookDTO(); + bookDTO1.setId(1L); + BookDTO bookDTO2 = new BookDTO(); + assertThat(bookDTO1).isNotEqualTo(bookDTO2); + bookDTO2.setId(bookDTO1.getId()); + assertThat(bookDTO1).isEqualTo(bookDTO2); + bookDTO2.setId(2L); + assertThat(bookDTO1).isNotEqualTo(bookDTO2); + bookDTO1.setId(null); + assertThat(bookDTO1).isNotEqualTo(bookDTO2); + } + + @Test + @Transactional + public void testEntityFromId() { + assertThat(bookMapper.fromId(42L).getId()).isEqualTo(42); + assertThat(bookMapper.fromId(null)).isNull(); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/LogsResourceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/LogsResourceIntTest.java new file mode 100644 index 0000000000..62f7f3f17c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/LogsResourceIntTest.java @@ -0,0 +1,66 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.web.rest.vm.LoggerVM; +import ch.qos.logback.classic.AsyncAppender; +import ch.qos.logback.classic.LoggerContext; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Test class for the LogsResource REST controller. + * + * @see LogsResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class LogsResourceIntTest { + + private MockMvc restLogsMockMvc; + + @Before + public void setup() { + LogsResource logsResource = new LogsResource(); + this.restLogsMockMvc = MockMvcBuilders + .standaloneSetup(logsResource) + .build(); + } + + @Test + public void getAllLogs() throws Exception { + restLogsMockMvc.perform(get("/management/logs")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)); + } + + @Test + public void changeLogs() throws Exception { + LoggerVM logger = new LoggerVM(); + logger.setLevel("INFO"); + logger.setName("ROOT"); + + restLogsMockMvc.perform(put("/management/logs") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(logger))) + .andExpect(status().isNoContent()); + } + + @Test + public void testLogstashAppender() { + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + assertThat(context.getLogger("ROOT").getAppender("ASYNC_LOGSTASH")).isInstanceOf(AsyncAppender.class); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/TestUtil.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/TestUtil.java new file mode 100644 index 0000000000..403bb9c9b0 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/TestUtil.java @@ -0,0 +1,141 @@ +package com.baeldung.jhipster5.web.rest; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; +import org.springframework.format.support.DefaultFormattingConversionService; +import org.springframework.format.support.FormattingConversionService; +import org.springframework.http.MediaType; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Utility class for testing REST controllers. + */ +public final class TestUtil { + + private static final ObjectMapper mapper = createObjectMapper(); + + /** MediaType for JSON UTF8 */ + public static final MediaType APPLICATION_JSON_UTF8 = new MediaType( + MediaType.APPLICATION_JSON.getType(), + MediaType.APPLICATION_JSON.getSubtype(), StandardCharsets.UTF_8); + + + private static ObjectMapper createObjectMapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + mapper.registerModule(new JavaTimeModule()); + return mapper; + } + + /** + * Convert an object to JSON byte array. + * + * @param object + * the object to convert + * @return the JSON byte array + * @throws IOException + */ + public static byte[] convertObjectToJsonBytes(Object object) + throws IOException { + return mapper.writeValueAsBytes(object); + } + + /** + * Create a byte array with a specific size filled with specified data. + * + * @param size the size of the byte array + * @param data the data to put in the byte array + * @return the JSON byte array + */ + public static byte[] createByteArray(int size, String data) { + byte[] byteArray = new byte[size]; + for (int i = 0; i < size; i++) { + byteArray[i] = Byte.parseByte(data, 2); + } + return byteArray; + } + + /** + * A matcher that tests that the examined string represents the same instant as the reference datetime. + */ + public static class ZonedDateTimeMatcher extends TypeSafeDiagnosingMatcher { + + private final ZonedDateTime date; + + public ZonedDateTimeMatcher(ZonedDateTime date) { + this.date = date; + } + + @Override + protected boolean matchesSafely(String item, Description mismatchDescription) { + try { + if (!date.isEqual(ZonedDateTime.parse(item))) { + mismatchDescription.appendText("was ").appendValue(item); + return false; + } + return true; + } catch (DateTimeParseException e) { + mismatchDescription.appendText("was ").appendValue(item) + .appendText(", which could not be parsed as a ZonedDateTime"); + return false; + } + + } + + @Override + public void describeTo(Description description) { + description.appendText("a String representing the same Instant as ").appendValue(date); + } + } + + /** + * Creates a matcher that matches when the examined string reprensents the same instant as the reference datetime + * @param date the reference datetime against which the examined string is checked + */ + public static ZonedDateTimeMatcher sameInstant(ZonedDateTime date) { + return new ZonedDateTimeMatcher(date); + } + + /** + * Verifies the equals/hashcode contract on the domain object. + */ + public static void equalsVerifier(Class clazz) throws Exception { + T domainObject1 = clazz.getConstructor().newInstance(); + assertThat(domainObject1.toString()).isNotNull(); + assertThat(domainObject1).isEqualTo(domainObject1); + assertThat(domainObject1.hashCode()).isEqualTo(domainObject1.hashCode()); + // Test with an instance of another class + Object testOtherObject = new Object(); + assertThat(domainObject1).isNotEqualTo(testOtherObject); + assertThat(domainObject1).isNotEqualTo(null); + // Test with an instance of the same class + T domainObject2 = clazz.getConstructor().newInstance(); + assertThat(domainObject1).isNotEqualTo(domainObject2); + // HashCodes are equals because the objects are not persisted yet + assertThat(domainObject1.hashCode()).isEqualTo(domainObject2.hashCode()); + } + + /** + * Create a FormattingConversionService which use ISO date format, instead of the localized one. + * @return the FormattingConversionService + */ + public static FormattingConversionService createFormattingConversionService() { + DefaultFormattingConversionService dfcs = new DefaultFormattingConversionService (); + DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); + registrar.setUseIsoFormat(true); + registrar.registerFormatters(dfcs); + return dfcs; + } + + private TestUtil() {} +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserJWTControllerIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserJWTControllerIntTest.java new file mode 100644 index 0000000000..3886710438 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserJWTControllerIntTest.java @@ -0,0 +1,125 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.jwt.TokenProvider; +import com.baeldung.jhipster5.web.rest.errors.ExceptionTranslator; +import com.baeldung.jhipster5.web.rest.vm.LoginVM; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.isEmptyString; +import static org.hamcrest.Matchers.not; + +/** + * Test class for the UserJWTController REST controller. + * + * @see UserJWTController + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class UserJWTControllerIntTest { + + @Autowired + private TokenProvider tokenProvider; + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private UserRepository userRepository; + + @Autowired + private PasswordEncoder passwordEncoder; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + private MockMvc mockMvc; + + @Before + public void setup() { + UserJWTController userJWTController = new UserJWTController(tokenProvider, authenticationManager); + this.mockMvc = MockMvcBuilders.standaloneSetup(userJWTController) + .setControllerAdvice(exceptionTranslator) + .build(); + } + + @Test + @Transactional + public void testAuthorize() throws Exception { + User user = new User(); + user.setLogin("user-jwt-controller"); + user.setEmail("user-jwt-controller@example.com"); + user.setActivated(true); + user.setPassword(passwordEncoder.encode("test")); + + userRepository.saveAndFlush(user); + + LoginVM login = new LoginVM(); + login.setUsername("user-jwt-controller"); + login.setPassword("test"); + mockMvc.perform(post("/api/authenticate") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(login))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id_token").isString()) + .andExpect(jsonPath("$.id_token").isNotEmpty()) + .andExpect(header().string("Authorization", not(nullValue()))) + .andExpect(header().string("Authorization", not(isEmptyString()))); + } + + @Test + @Transactional + public void testAuthorizeWithRememberMe() throws Exception { + User user = new User(); + user.setLogin("user-jwt-controller-remember-me"); + user.setEmail("user-jwt-controller-remember-me@example.com"); + user.setActivated(true); + user.setPassword(passwordEncoder.encode("test")); + + userRepository.saveAndFlush(user); + + LoginVM login = new LoginVM(); + login.setUsername("user-jwt-controller-remember-me"); + login.setPassword("test"); + login.setRememberMe(true); + mockMvc.perform(post("/api/authenticate") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(login))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id_token").isString()) + .andExpect(jsonPath("$.id_token").isNotEmpty()) + .andExpect(header().string("Authorization", not(nullValue()))) + .andExpect(header().string("Authorization", not(isEmptyString()))); + } + + @Test + @Transactional + public void testAuthorizeFails() throws Exception { + LoginVM login = new LoginVM(); + login.setUsername("wrong-user"); + login.setPassword("wrong password"); + mockMvc.perform(post("/api/authenticate") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(login))) + .andExpect(status().isUnauthorized()) + .andExpect(jsonPath("$.id_token").doesNotExist()) + .andExpect(header().doesNotExist("Authorization")); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserResourceIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserResourceIntTest.java new file mode 100644 index 0000000000..d31df3b15c --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/UserResourceIntTest.java @@ -0,0 +1,596 @@ +package com.baeldung.jhipster5.web.rest; + +import com.baeldung.jhipster5.BookstoreApp; +import com.baeldung.jhipster5.domain.Authority; +import com.baeldung.jhipster5.domain.User; +import com.baeldung.jhipster5.repository.UserRepository; +import com.baeldung.jhipster5.security.AuthoritiesConstants; +import com.baeldung.jhipster5.service.MailService; +import com.baeldung.jhipster5.service.UserService; +import com.baeldung.jhipster5.service.dto.UserDTO; +import com.baeldung.jhipster5.service.mapper.UserMapper; +import com.baeldung.jhipster5.web.rest.errors.ExceptionTranslator; +import com.baeldung.jhipster5.web.rest.vm.ManagedUserVM; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import java.time.Instant; +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the UserResource REST controller. + * + * @see UserResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class UserResourceIntTest { + + private static final String DEFAULT_LOGIN = "johndoe"; + private static final String UPDATED_LOGIN = "jhipster"; + + private static final Long DEFAULT_ID = 1L; + + private static final String DEFAULT_PASSWORD = "passjohndoe"; + private static final String UPDATED_PASSWORD = "passjhipster"; + + private static final String DEFAULT_EMAIL = "johndoe@localhost"; + private static final String UPDATED_EMAIL = "jhipster@localhost"; + + private static final String DEFAULT_FIRSTNAME = "john"; + private static final String UPDATED_FIRSTNAME = "jhipsterFirstName"; + + private static final String DEFAULT_LASTNAME = "doe"; + private static final String UPDATED_LASTNAME = "jhipsterLastName"; + + private static final String DEFAULT_IMAGEURL = "http://placehold.it/50x50"; + private static final String UPDATED_IMAGEURL = "http://placehold.it/40x40"; + + private static final String DEFAULT_LANGKEY = "en"; + private static final String UPDATED_LANGKEY = "fr"; + + @Autowired + private UserRepository userRepository; + + @Autowired + private MailService mailService; + + @Autowired + private UserService userService; + + @Autowired + private UserMapper userMapper; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + @Autowired + private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Autowired + private EntityManager em; + + private MockMvc restUserMockMvc; + + private User user; + + @Before + public void setup() { + UserResource userResource = new UserResource(userService, userRepository, mailService); + + this.restUserMockMvc = MockMvcBuilders.standaloneSetup(userResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .build(); + } + + /** + * Create a User. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which has a required relationship to the User entity. + */ + public static User createEntity(EntityManager em) { + User user = new User(); + user.setLogin(DEFAULT_LOGIN + RandomStringUtils.randomAlphabetic(5)); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setEmail(RandomStringUtils.randomAlphabetic(5) + DEFAULT_EMAIL); + user.setFirstName(DEFAULT_FIRSTNAME); + user.setLastName(DEFAULT_LASTNAME); + user.setImageUrl(DEFAULT_IMAGEURL); + user.setLangKey(DEFAULT_LANGKEY); + return user; + } + + @Before + public void initTest() { + user = createEntity(em); + user.setLogin(DEFAULT_LOGIN); + user.setEmail(DEFAULT_EMAIL); + } + + @Test + @Transactional + public void createUser() throws Exception { + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + // Create the User + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setLogin(DEFAULT_LOGIN); + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail(DEFAULT_EMAIL); + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isCreated()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate + 1); + User testUser = userList.get(userList.size() - 1); + assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); + assertThat(testUser.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); + assertThat(testUser.getLastName()).isEqualTo(DEFAULT_LASTNAME); + assertThat(testUser.getEmail()).isEqualTo(DEFAULT_EMAIL); + assertThat(testUser.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL); + assertThat(testUser.getLangKey()).isEqualTo(DEFAULT_LANGKEY); + } + + @Test + @Transactional + public void createUserWithExistingId() throws Exception { + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(1L); + managedUserVM.setLogin(DEFAULT_LOGIN); + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail(DEFAULT_EMAIL); + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + // An entity with an existing ID cannot be created, so this API call must fail + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void createUserWithExistingLogin() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setLogin(DEFAULT_LOGIN);// this login should already be used + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail("anothermail@localhost"); + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + // Create the User + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void createUserWithExistingEmail() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setLogin("anotherlogin"); + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail(DEFAULT_EMAIL);// this email should already be used + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + // Create the User + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void getAllUsers() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + + // Get all the users + restUserMockMvc.perform(get("/api/users?sort=id,desc") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].login").value(hasItem(DEFAULT_LOGIN))) + .andExpect(jsonPath("$.[*].firstName").value(hasItem(DEFAULT_FIRSTNAME))) + .andExpect(jsonPath("$.[*].lastName").value(hasItem(DEFAULT_LASTNAME))) + .andExpect(jsonPath("$.[*].email").value(hasItem(DEFAULT_EMAIL))) + .andExpect(jsonPath("$.[*].imageUrl").value(hasItem(DEFAULT_IMAGEURL))) + .andExpect(jsonPath("$.[*].langKey").value(hasItem(DEFAULT_LANGKEY))); + } + + @Test + @Transactional + public void getUser() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + + // Get the user + restUserMockMvc.perform(get("/api/users/{login}", user.getLogin())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.login").value(user.getLogin())) + .andExpect(jsonPath("$.firstName").value(DEFAULT_FIRSTNAME)) + .andExpect(jsonPath("$.lastName").value(DEFAULT_LASTNAME)) + .andExpect(jsonPath("$.email").value(DEFAULT_EMAIL)) + .andExpect(jsonPath("$.imageUrl").value(DEFAULT_IMAGEURL)) + .andExpect(jsonPath("$.langKey").value(DEFAULT_LANGKEY)); + } + + @Test + @Transactional + public void getNonExistingUser() throws Exception { + restUserMockMvc.perform(get("/api/users/unknown")) + .andExpect(status().isNotFound()); + } + + @Test + @Transactional + public void updateUser() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeUpdate = userRepository.findAll().size(); + + // Update the user + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin(updatedUser.getLogin()); + managedUserVM.setPassword(UPDATED_PASSWORD); + managedUserVM.setFirstName(UPDATED_FIRSTNAME); + managedUserVM.setLastName(UPDATED_LASTNAME); + managedUserVM.setEmail(UPDATED_EMAIL); + managedUserVM.setActivated(updatedUser.getActivated()); + managedUserVM.setImageUrl(UPDATED_IMAGEURL); + managedUserVM.setLangKey(UPDATED_LANGKEY); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isOk()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeUpdate); + User testUser = userList.get(userList.size() - 1); + assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); + assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); + assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); + assertThat(testUser.getImageUrl()).isEqualTo(UPDATED_IMAGEURL); + assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); + } + + @Test + @Transactional + public void updateUserLogin() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeUpdate = userRepository.findAll().size(); + + // Update the user + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin(UPDATED_LOGIN); + managedUserVM.setPassword(UPDATED_PASSWORD); + managedUserVM.setFirstName(UPDATED_FIRSTNAME); + managedUserVM.setLastName(UPDATED_LASTNAME); + managedUserVM.setEmail(UPDATED_EMAIL); + managedUserVM.setActivated(updatedUser.getActivated()); + managedUserVM.setImageUrl(UPDATED_IMAGEURL); + managedUserVM.setLangKey(UPDATED_LANGKEY); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isOk()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeUpdate); + User testUser = userList.get(userList.size() - 1); + assertThat(testUser.getLogin()).isEqualTo(UPDATED_LOGIN); + assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); + assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); + assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); + assertThat(testUser.getImageUrl()).isEqualTo(UPDATED_IMAGEURL); + assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); + } + + @Test + @Transactional + public void updateUserExistingEmail() throws Exception { + // Initialize the database with 2 users + userRepository.saveAndFlush(user); + + User anotherUser = new User(); + anotherUser.setLogin("jhipster"); + anotherUser.setPassword(RandomStringUtils.random(60)); + anotherUser.setActivated(true); + anotherUser.setEmail("jhipster@localhost"); + anotherUser.setFirstName("java"); + anotherUser.setLastName("hipster"); + anotherUser.setImageUrl(""); + anotherUser.setLangKey("en"); + userRepository.saveAndFlush(anotherUser); + + // Update the user + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin(updatedUser.getLogin()); + managedUserVM.setPassword(updatedUser.getPassword()); + managedUserVM.setFirstName(updatedUser.getFirstName()); + managedUserVM.setLastName(updatedUser.getLastName()); + managedUserVM.setEmail("jhipster@localhost");// this email should already be used by anotherUser + managedUserVM.setActivated(updatedUser.getActivated()); + managedUserVM.setImageUrl(updatedUser.getImageUrl()); + managedUserVM.setLangKey(updatedUser.getLangKey()); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + } + + @Test + @Transactional + public void updateUserExistingLogin() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + + User anotherUser = new User(); + anotherUser.setLogin("jhipster"); + anotherUser.setPassword(RandomStringUtils.random(60)); + anotherUser.setActivated(true); + anotherUser.setEmail("jhipster@localhost"); + anotherUser.setFirstName("java"); + anotherUser.setLastName("hipster"); + anotherUser.setImageUrl(""); + anotherUser.setLangKey("en"); + userRepository.saveAndFlush(anotherUser); + + // Update the user + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin("jhipster");// this login should already be used by anotherUser + managedUserVM.setPassword(updatedUser.getPassword()); + managedUserVM.setFirstName(updatedUser.getFirstName()); + managedUserVM.setLastName(updatedUser.getLastName()); + managedUserVM.setEmail(updatedUser.getEmail()); + managedUserVM.setActivated(updatedUser.getActivated()); + managedUserVM.setImageUrl(updatedUser.getImageUrl()); + managedUserVM.setLangKey(updatedUser.getLangKey()); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + } + + @Test + @Transactional + public void deleteUser() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeDelete = userRepository.findAll().size(); + + // Delete the user + restUserMockMvc.perform(delete("/api/users/{login}", user.getLogin()) + .accept(TestUtil.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + + // Validate the database is empty + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeDelete - 1); + } + + @Test + @Transactional + public void getAllAuthorities() throws Exception { + restUserMockMvc.perform(get("/api/users/authorities") + .accept(TestUtil.APPLICATION_JSON_UTF8) + .contentType(TestUtil.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$").isArray()) + .andExpect(jsonPath("$").value(hasItems(AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN))); + } + + @Test + @Transactional + public void testUserEquals() throws Exception { + TestUtil.equalsVerifier(User.class); + User user1 = new User(); + user1.setId(1L); + User user2 = new User(); + user2.setId(user1.getId()); + assertThat(user1).isEqualTo(user2); + user2.setId(2L); + assertThat(user1).isNotEqualTo(user2); + user1.setId(null); + assertThat(user1).isNotEqualTo(user2); + } + + @Test + public void testUserDTOtoUser() { + UserDTO userDTO = new UserDTO(); + userDTO.setId(DEFAULT_ID); + userDTO.setLogin(DEFAULT_LOGIN); + userDTO.setFirstName(DEFAULT_FIRSTNAME); + userDTO.setLastName(DEFAULT_LASTNAME); + userDTO.setEmail(DEFAULT_EMAIL); + userDTO.setActivated(true); + userDTO.setImageUrl(DEFAULT_IMAGEURL); + userDTO.setLangKey(DEFAULT_LANGKEY); + userDTO.setCreatedBy(DEFAULT_LOGIN); + userDTO.setLastModifiedBy(DEFAULT_LOGIN); + userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + + User user = userMapper.userDTOToUser(userDTO); + assertThat(user.getId()).isEqualTo(DEFAULT_ID); + assertThat(user.getLogin()).isEqualTo(DEFAULT_LOGIN); + assertThat(user.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); + assertThat(user.getLastName()).isEqualTo(DEFAULT_LASTNAME); + assertThat(user.getEmail()).isEqualTo(DEFAULT_EMAIL); + assertThat(user.getActivated()).isEqualTo(true); + assertThat(user.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL); + assertThat(user.getLangKey()).isEqualTo(DEFAULT_LANGKEY); + assertThat(user.getCreatedBy()).isNull(); + assertThat(user.getCreatedDate()).isNotNull(); + assertThat(user.getLastModifiedBy()).isNull(); + assertThat(user.getLastModifiedDate()).isNotNull(); + assertThat(user.getAuthorities()).extracting("name").containsExactly(AuthoritiesConstants.USER); + } + + @Test + public void testUserToUserDTO() { + user.setId(DEFAULT_ID); + user.setCreatedBy(DEFAULT_LOGIN); + user.setCreatedDate(Instant.now()); + user.setLastModifiedBy(DEFAULT_LOGIN); + user.setLastModifiedDate(Instant.now()); + Set authorities = new HashSet<>(); + Authority authority = new Authority(); + authority.setName(AuthoritiesConstants.USER); + authorities.add(authority); + user.setAuthorities(authorities); + + UserDTO userDTO = userMapper.userToUserDTO(user); + + assertThat(userDTO.getId()).isEqualTo(DEFAULT_ID); + assertThat(userDTO.getLogin()).isEqualTo(DEFAULT_LOGIN); + assertThat(userDTO.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); + assertThat(userDTO.getLastName()).isEqualTo(DEFAULT_LASTNAME); + assertThat(userDTO.getEmail()).isEqualTo(DEFAULT_EMAIL); + assertThat(userDTO.isActivated()).isEqualTo(true); + assertThat(userDTO.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL); + assertThat(userDTO.getLangKey()).isEqualTo(DEFAULT_LANGKEY); + assertThat(userDTO.getCreatedBy()).isEqualTo(DEFAULT_LOGIN); + assertThat(userDTO.getCreatedDate()).isEqualTo(user.getCreatedDate()); + assertThat(userDTO.getLastModifiedBy()).isEqualTo(DEFAULT_LOGIN); + assertThat(userDTO.getLastModifiedDate()).isEqualTo(user.getLastModifiedDate()); + assertThat(userDTO.getAuthorities()).containsExactly(AuthoritiesConstants.USER); + assertThat(userDTO.toString()).isNotNull(); + } + + @Test + public void testAuthorityEquals() { + Authority authorityA = new Authority(); + assertThat(authorityA).isEqualTo(authorityA); + assertThat(authorityA).isNotEqualTo(null); + assertThat(authorityA).isNotEqualTo(new Object()); + assertThat(authorityA.hashCode()).isEqualTo(0); + assertThat(authorityA.toString()).isNotNull(); + + Authority authorityB = new Authority(); + assertThat(authorityA).isEqualTo(authorityB); + + authorityB.setName(AuthoritiesConstants.ADMIN); + assertThat(authorityA).isNotEqualTo(authorityB); + + authorityA.setName(AuthoritiesConstants.USER); + assertThat(authorityA).isNotEqualTo(authorityB); + + authorityB.setName(AuthoritiesConstants.USER); + assertThat(authorityA).isEqualTo(authorityB); + assertThat(authorityA.hashCode()).isEqualTo(authorityB.hashCode()); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorIntTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorIntTest.java new file mode 100644 index 0000000000..a94d54063b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorIntTest.java @@ -0,0 +1,150 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import com.baeldung.jhipster5.BookstoreApp; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Test class for the ExceptionTranslator controller advice. + * + * @see ExceptionTranslator + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BookstoreApp.class) +public class ExceptionTranslatorIntTest { + + @Autowired + private ExceptionTranslatorTestController controller; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + private MockMvc mockMvc; + + @Before + public void setup() { + mockMvc = MockMvcBuilders.standaloneSetup(controller) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .build(); + } + + @Test + public void testConcurrencyFailure() throws Exception { + mockMvc.perform(get("/test/concurrency-failure")) + .andExpect(status().isConflict()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value(ErrorConstants.ERR_CONCURRENCY_FAILURE)); + } + + @Test + public void testMethodArgumentNotValid() throws Exception { + mockMvc.perform(post("/test/method-argument").content("{}").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value(ErrorConstants.ERR_VALIDATION)) + .andExpect(jsonPath("$.fieldErrors.[0].objectName").value("testDTO")) + .andExpect(jsonPath("$.fieldErrors.[0].field").value("test")) + .andExpect(jsonPath("$.fieldErrors.[0].message").value("NotNull")); + } + + @Test + public void testParameterizedError() throws Exception { + mockMvc.perform(get("/test/parameterized-error")) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("test parameterized error")) + .andExpect(jsonPath("$.params.param0").value("param0_value")) + .andExpect(jsonPath("$.params.param1").value("param1_value")); + } + + @Test + public void testParameterizedError2() throws Exception { + mockMvc.perform(get("/test/parameterized-error2")) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("test parameterized error")) + .andExpect(jsonPath("$.params.foo").value("foo_value")) + .andExpect(jsonPath("$.params.bar").value("bar_value")); + } + + @Test + public void testMissingServletRequestPartException() throws Exception { + mockMvc.perform(get("/test/missing-servlet-request-part")) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.400")); + } + + @Test + public void testMissingServletRequestParameterException() throws Exception { + mockMvc.perform(get("/test/missing-servlet-request-parameter")) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.400")); + } + + @Test + public void testAccessDenied() throws Exception { + mockMvc.perform(get("/test/access-denied")) + .andExpect(status().isForbidden()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.403")) + .andExpect(jsonPath("$.detail").value("test access denied!")); + } + + @Test + public void testUnauthorized() throws Exception { + mockMvc.perform(get("/test/unauthorized")) + .andExpect(status().isUnauthorized()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.401")) + .andExpect(jsonPath("$.path").value("/test/unauthorized")) + .andExpect(jsonPath("$.detail").value("test authentication failed!")); + } + + @Test + public void testMethodNotSupported() throws Exception { + mockMvc.perform(post("/test/access-denied")) + .andExpect(status().isMethodNotAllowed()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.405")) + .andExpect(jsonPath("$.detail").value("Request method 'POST' not supported")); + } + + @Test + public void testExceptionWithResponseStatus() throws Exception { + mockMvc.perform(get("/test/response-status")) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.400")) + .andExpect(jsonPath("$.title").value("test response status")); + } + + @Test + public void testInternalServerError() throws Exception { + mockMvc.perform(get("/test/internal-server-error")) + .andExpect(status().isInternalServerError()) + .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) + .andExpect(jsonPath("$.message").value("error.http.500")) + .andExpect(jsonPath("$.title").value("Internal Server Error")); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorTestController.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorTestController.java new file mode 100644 index 0000000000..f8d84151b9 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/errors/ExceptionTranslatorTestController.java @@ -0,0 +1,86 @@ +package com.baeldung.jhipster5.web.rest.errors; + +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.HashMap; +import java.util.Map; + +@RestController +public class ExceptionTranslatorTestController { + + @GetMapping("/test/concurrency-failure") + public void concurrencyFailure() { + throw new ConcurrencyFailureException("test concurrency failure"); + } + + @PostMapping("/test/method-argument") + public void methodArgument(@Valid @RequestBody TestDTO testDTO) { + } + + @GetMapping("/test/parameterized-error") + public void parameterizedError() { + throw new CustomParameterizedException("test parameterized error", "param0_value", "param1_value"); + } + + @GetMapping("/test/parameterized-error2") + public void parameterizedError2() { + Map params = new HashMap<>(); + params.put("foo", "foo_value"); + params.put("bar", "bar_value"); + throw new CustomParameterizedException("test parameterized error", params); + } + + @GetMapping("/test/missing-servlet-request-part") + public void missingServletRequestPartException(@RequestPart String part) { + } + + @GetMapping("/test/missing-servlet-request-parameter") + public void missingServletRequestParameterException(@RequestParam String param) { + } + + @GetMapping("/test/access-denied") + public void accessdenied() { + throw new AccessDeniedException("test access denied!"); + } + + @GetMapping("/test/unauthorized") + public void unauthorized() { + throw new BadCredentialsException("test authentication failed!"); + } + + @GetMapping("/test/response-status") + public void exceptionWithReponseStatus() { + throw new TestResponseStatusException(); + } + + @GetMapping("/test/internal-server-error") + public void internalServerError() { + throw new RuntimeException(); + } + + public static class TestDTO { + + @NotNull + private String test; + + public String getTest() { + return test; + } + + public void setTest(String test) { + this.test = test; + } + } + + @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "test response status") + @SuppressWarnings("serial") + public static class TestResponseStatusException extends RuntimeException { + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/util/PaginationUtilUnitTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/util/PaginationUtilUnitTest.java new file mode 100644 index 0000000000..78b17ee859 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/web/rest/util/PaginationUtilUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.jhipster5.web.rest.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.http.HttpHeaders; + +/** + * Tests based on parsing algorithm in app/components/util/pagination-util.service.js + * + * @see PaginationUtil + */ +public class PaginationUtilUnitTest { + + @Test + public void generatePaginationHttpHeadersTest() { + String baseUrl = "/api/_search/example"; + List content = new ArrayList<>(); + Page page = new PageImpl<>(content, PageRequest.of(6, 50), 400L); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, baseUrl); + List strHeaders = headers.get(HttpHeaders.LINK); + assertNotNull(strHeaders); + assertTrue(strHeaders.size() == 1); + String headerData = strHeaders.get(0); + assertTrue(headerData.split(",").length == 4); + String expectedData = "; rel=\"next\"," + + "; rel=\"prev\"," + + "; rel=\"last\"," + + "; rel=\"first\""; + assertEquals(expectedData, headerData); + List xTotalCountHeaders = headers.get("X-Total-Count"); + assertTrue(xTotalCountHeaders.size() == 1); + assertTrue(Long.valueOf(xTotalCountHeaders.get(0)).equals(400L)); + } + +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/jest-global-mocks.ts b/jhipster-5/bookstore-monolith/src/test/javascript/jest-global-mocks.ts new file mode 100644 index 0000000000..a998259857 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/jest-global-mocks.ts @@ -0,0 +1,15 @@ +const mock = () => { + let storage = {}; + return { + getItem: key => (key in storage ? storage[key] : null), + setItem: (key, value) => (storage[key] = value || ''), + removeItem: key => delete storage[key], + clear: () => (storage = {}) + }; +}; + +Object.defineProperty(window, 'localStorage', { value: mock() }); +Object.defineProperty(window, 'sessionStorage', { value: mock() }); +Object.defineProperty(window, 'getComputedStyle', { + value: () => ['-webkit-appearance'] +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/jest.conf.js b/jhipster-5/bookstore-monolith/src/test/javascript/jest.conf.js new file mode 100644 index 0000000000..05054a94b8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/jest.conf.js @@ -0,0 +1,26 @@ +module.exports = { + preset: 'jest-preset-angular', + setupTestFrameworkScriptFile: '/src/test/javascript/jest.ts', + coverageDirectory: '/target/test-results/', + globals: { + 'ts-jest': { + tsConfigFile: 'tsconfig.json' + }, + __TRANSFORM_HTML__: true + }, + coveragePathIgnorePatterns: [ + '/src/test/javascript' + ], + moduleNameMapper: { + 'app/(.*)': '/src/main/webapp/app/$1' + }, + reporters: [ + 'default', + [ 'jest-junit', { output: './target/test-results/TESTS-results-jest.xml' } ] + ], + testResultsProcessor: 'jest-sonar-reporter', + transformIgnorePatterns: ['node_modules/(?!@angular/common/locales)'], + testMatch: ['/src/test/javascript/spec/**/+(*.)+(spec.ts)'], + rootDir: '../../../', + testURL: "http://localhost/" +}; diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/jest.ts b/jhipster-5/bookstore-monolith/src/test/javascript/jest.ts new file mode 100644 index 0000000000..904329f538 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/jest.ts @@ -0,0 +1,2 @@ +import 'jest-preset-angular'; +import './jest-global-mocks'; diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/activate/activate.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/activate/activate.component.spec.ts new file mode 100644 index 0000000000..87a550e8ef --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/activate/activate.component.spec.ts @@ -0,0 +1,72 @@ +import { TestBed, async, tick, fakeAsync, inject } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { Observable, of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { MockActivatedRoute } from '../../../helpers/mock-route.service'; +import { ActivateService } from 'app/account/activate/activate.service'; +import { ActivateComponent } from 'app/account/activate/activate.component'; + +describe('Component Tests', () => { + describe('ActivateComponent', () => { + let comp: ActivateComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [ActivateComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: new MockActivatedRoute({ key: 'ABC123' }) + } + ] + }) + .overrideTemplate(ActivateComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + const fixture = TestBed.createComponent(ActivateComponent); + comp = fixture.componentInstance; + }); + + it('calls activate.get with the key from params', inject( + [ActivateService], + fakeAsync((service: ActivateService) => { + spyOn(service, 'get').and.returnValue(of()); + + comp.ngOnInit(); + tick(); + + expect(service.get).toHaveBeenCalledWith('ABC123'); + }) + )); + + it('should set set success to OK upon successful activation', inject( + [ActivateService], + fakeAsync((service: ActivateService) => { + spyOn(service, 'get').and.returnValue(of({})); + + comp.ngOnInit(); + tick(); + + expect(comp.error).toBe(null); + expect(comp.success).toEqual('OK'); + }) + )); + + it('should set set error to ERROR upon activation failure', inject( + [ActivateService], + fakeAsync((service: ActivateService) => { + spyOn(service, 'get').and.returnValue(throwError('ERROR')); + + comp.ngOnInit(); + tick(); + + expect(comp.error).toBe('ERROR'); + expect(comp.success).toEqual(null); + }) + )); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/finish/password-reset-finish.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/finish/password-reset-finish.component.spec.ts new file mode 100644 index 0000000000..36a3b8db65 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/finish/password-reset-finish.component.spec.ts @@ -0,0 +1,119 @@ +import { ComponentFixture, TestBed, inject, tick, fakeAsync } from '@angular/core/testing'; +import { Observable, of, throwError } from 'rxjs'; +import { Renderer, ElementRef } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { BookstoreTestModule } from '../../../../test.module'; +import { PasswordResetFinishComponent } from 'app/account/password-reset/finish/password-reset-finish.component'; +import { PasswordResetFinishService } from 'app/account/password-reset/finish/password-reset-finish.service'; +import { MockActivatedRoute } from '../../../../helpers/mock-route.service'; + +describe('Component Tests', () => { + describe('PasswordResetFinishComponent', () => { + let fixture: ComponentFixture; + let comp: PasswordResetFinishComponent; + + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [PasswordResetFinishComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: new MockActivatedRoute({ key: 'XYZPDQ' }) + }, + { + provide: Renderer, + useValue: { + invokeElementMethod(renderElement: any, methodName: string, args?: any[]) {} + } + }, + { + provide: ElementRef, + useValue: new ElementRef(null) + } + ] + }) + .overrideTemplate(PasswordResetFinishComponent, '') + .createComponent(PasswordResetFinishComponent); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PasswordResetFinishComponent); + comp = fixture.componentInstance; + comp.ngOnInit(); + }); + + it('should define its initial state', () => { + comp.ngOnInit(); + + expect(comp.keyMissing).toBeFalsy(); + expect(comp.key).toEqual('XYZPDQ'); + expect(comp.resetAccount).toEqual({}); + }); + + it('sets focus after the view has been initialized', inject([ElementRef], (elementRef: ElementRef) => { + const element = fixture.nativeElement; + const node = { + focus() {} + }; + + elementRef.nativeElement = element; + spyOn(element, 'querySelector').and.returnValue(node); + spyOn(node, 'focus'); + + comp.ngAfterViewInit(); + + expect(element.querySelector).toHaveBeenCalledWith('#password'); + expect(node.focus).toHaveBeenCalled(); + })); + + it('should ensure the two passwords entered match', () => { + comp.resetAccount.password = 'password'; + comp.confirmPassword = 'non-matching'; + + comp.finishReset(); + + expect(comp.doNotMatch).toEqual('ERROR'); + }); + + it('should update success to OK after resetting password', inject( + [PasswordResetFinishService], + fakeAsync((service: PasswordResetFinishService) => { + spyOn(service, 'save').and.returnValue(of({})); + + comp.resetAccount.password = 'password'; + comp.confirmPassword = 'password'; + + comp.finishReset(); + tick(); + + expect(service.save).toHaveBeenCalledWith({ + key: 'XYZPDQ', + newPassword: 'password' + }); + expect(comp.success).toEqual('OK'); + }) + )); + + it('should notify of generic error', inject( + [PasswordResetFinishService], + fakeAsync((service: PasswordResetFinishService) => { + spyOn(service, 'save').and.returnValue(throwError('ERROR')); + + comp.resetAccount.password = 'password'; + comp.confirmPassword = 'password'; + + comp.finishReset(); + tick(); + + expect(service.save).toHaveBeenCalledWith({ + key: 'XYZPDQ', + newPassword: 'password' + }); + expect(comp.success).toBeNull(); + expect(comp.error).toEqual('ERROR'); + }) + )); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/init/password-reset-init.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/init/password-reset-init.component.spec.ts new file mode 100644 index 0000000000..f121a4dd27 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password-reset/init/password-reset-init.component.spec.ts @@ -0,0 +1,110 @@ +import { ComponentFixture, TestBed, inject } from '@angular/core/testing'; +import { Renderer, ElementRef } from '@angular/core'; +import { Observable, of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../../test.module'; +import { PasswordResetInitComponent } from 'app/account/password-reset/init/password-reset-init.component'; +import { PasswordResetInitService } from 'app/account/password-reset/init/password-reset-init.service'; +import { EMAIL_NOT_FOUND_TYPE } from 'app/shared'; + +describe('Component Tests', () => { + describe('PasswordResetInitComponent', () => { + let fixture: ComponentFixture; + let comp: PasswordResetInitComponent; + + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [PasswordResetInitComponent], + providers: [ + { + provide: Renderer, + useValue: { + invokeElementMethod(renderElement: any, methodName: string, args?: any[]) {} + } + }, + { + provide: ElementRef, + useValue: new ElementRef(null) + } + ] + }) + .overrideTemplate(PasswordResetInitComponent, '') + .createComponent(PasswordResetInitComponent); + comp = fixture.componentInstance; + comp.ngOnInit(); + }); + + it('should define its initial state', () => { + expect(comp.success).toBeUndefined(); + expect(comp.error).toBeUndefined(); + expect(comp.errorEmailNotExists).toBeUndefined(); + expect(comp.resetAccount).toEqual({}); + }); + + it('sets focus after the view has been initialized', inject([ElementRef], (elementRef: ElementRef) => { + const element = fixture.nativeElement; + const node = { + focus() {} + }; + + elementRef.nativeElement = element; + spyOn(element, 'querySelector').and.returnValue(node); + spyOn(node, 'focus'); + + comp.ngAfterViewInit(); + + expect(element.querySelector).toHaveBeenCalledWith('#email'); + expect(node.focus).toHaveBeenCalled(); + })); + + it('notifies of success upon successful requestReset', inject([PasswordResetInitService], (service: PasswordResetInitService) => { + spyOn(service, 'save').and.returnValue(of({})); + comp.resetAccount.email = 'user@domain.com'; + + comp.requestReset(); + + expect(service.save).toHaveBeenCalledWith('user@domain.com'); + expect(comp.success).toEqual('OK'); + expect(comp.error).toBeNull(); + expect(comp.errorEmailNotExists).toBeNull(); + })); + + it('notifies of unknown email upon email address not registered/400', inject( + [PasswordResetInitService], + (service: PasswordResetInitService) => { + spyOn(service, 'save').and.returnValue( + throwError({ + status: 400, + error: { type: EMAIL_NOT_FOUND_TYPE } + }) + ); + comp.resetAccount.email = 'user@domain.com'; + + comp.requestReset(); + + expect(service.save).toHaveBeenCalledWith('user@domain.com'); + expect(comp.success).toBeNull(); + expect(comp.error).toBeNull(); + expect(comp.errorEmailNotExists).toEqual('ERROR'); + } + )); + + it('notifies of error upon error response', inject([PasswordResetInitService], (service: PasswordResetInitService) => { + spyOn(service, 'save').and.returnValue( + throwError({ + status: 503, + data: 'something else' + }) + ); + comp.resetAccount.email = 'user@domain.com'; + + comp.requestReset(); + + expect(service.save).toHaveBeenCalledWith('user@domain.com'); + expect(comp.success).toBeNull(); + expect(comp.errorEmailNotExists).toBeNull(); + expect(comp.error).toEqual('ERROR'); + })); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password-strength-bar.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password-strength-bar.component.spec.ts new file mode 100644 index 0000000000..35e923ac00 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password-strength-bar.component.spec.ts @@ -0,0 +1,48 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; + +import { PasswordStrengthBarComponent } from 'app/account/password/password-strength-bar.component'; + +describe('Component Tests', () => { + describe('PasswordStrengthBarComponent', () => { + let comp: PasswordStrengthBarComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PasswordStrengthBarComponent] + }) + .overrideTemplate(PasswordStrengthBarComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PasswordStrengthBarComponent); + comp = fixture.componentInstance; + }); + + describe('PasswordStrengthBarComponents', () => { + it('should initialize with default values', () => { + expect(comp.measureStrength('')).toBe(0); + expect(comp.colors).toEqual(['#F00', '#F90', '#FF0', '#9F0', '#0F0']); + expect(comp.getColor(0).idx).toBe(1); + expect(comp.getColor(0).col).toBe(comp.colors[0]); + }); + + it('should increase strength upon password value change', () => { + expect(comp.measureStrength('')).toBe(0); + expect(comp.measureStrength('aa')).toBeGreaterThanOrEqual(comp.measureStrength('')); + expect(comp.measureStrength('aa^6')).toBeGreaterThanOrEqual(comp.measureStrength('aa')); + expect(comp.measureStrength('Aa090(**)')).toBeGreaterThanOrEqual(comp.measureStrength('aa^6')); + expect(comp.measureStrength('Aa090(**)+-07365')).toBeGreaterThanOrEqual(comp.measureStrength('Aa090(**)')); + }); + + it('should change the color based on strength', () => { + expect(comp.getColor(0).col).toBe(comp.colors[0]); + expect(comp.getColor(11).col).toBe(comp.colors[1]); + expect(comp.getColor(22).col).toBe(comp.colors[2]); + expect(comp.getColor(33).col).toBe(comp.colors[3]); + expect(comp.getColor(44).col).toBe(comp.colors[4]); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password.component.spec.ts new file mode 100644 index 0000000000..86edf940bd --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/password/password.component.spec.ts @@ -0,0 +1,89 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { Observable, of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { PasswordComponent } from 'app/account/password/password.component'; +import { PasswordService } from 'app/account/password/password.service'; + +describe('Component Tests', () => { + describe('PasswordComponent', () => { + let comp: PasswordComponent; + let fixture: ComponentFixture; + let service: PasswordService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [PasswordComponent], + providers: [] + }) + .overrideTemplate(PasswordComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PasswordComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(PasswordService); + }); + + it('should show error if passwords do not match', () => { + // GIVEN + comp.newPassword = 'password1'; + comp.confirmPassword = 'password2'; + // WHEN + comp.changePassword(); + // THEN + expect(comp.doNotMatch).toBe('ERROR'); + expect(comp.error).toBeNull(); + expect(comp.success).toBeNull(); + }); + + it('should call Auth.changePassword when passwords match', () => { + // GIVEN + const passwordValues = { + currentPassword: 'oldPassword', + newPassword: 'myPassword' + }; + + spyOn(service, 'save').and.returnValue(of(new HttpResponse({ body: true }))); + comp.currentPassword = passwordValues.currentPassword; + comp.newPassword = comp.confirmPassword = passwordValues.newPassword; + + // WHEN + comp.changePassword(); + + // THEN + expect(service.save).toHaveBeenCalledWith(passwordValues.newPassword, passwordValues.currentPassword); + }); + + it('should set success to OK upon success', function() { + // GIVEN + spyOn(service, 'save').and.returnValue(of(new HttpResponse({ body: true }))); + comp.newPassword = comp.confirmPassword = 'myPassword'; + + // WHEN + comp.changePassword(); + + // THEN + expect(comp.doNotMatch).toBeNull(); + expect(comp.error).toBeNull(); + expect(comp.success).toBe('OK'); + }); + + it('should notify of error if change password fails', function() { + // GIVEN + spyOn(service, 'save').and.returnValue(throwError('ERROR')); + comp.newPassword = comp.confirmPassword = 'myPassword'; + + // WHEN + comp.changePassword(); + + // THEN + expect(comp.doNotMatch).toBeNull(); + expect(comp.success).toBeNull(); + expect(comp.error).toBe('ERROR'); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/register/register.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/register/register.component.spec.ts new file mode 100644 index 0000000000..ae02abbb91 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/register/register.component.spec.ts @@ -0,0 +1,118 @@ +import { ComponentFixture, TestBed, async, inject, tick, fakeAsync } from '@angular/core/testing'; +import { Observable, of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { EMAIL_ALREADY_USED_TYPE, LOGIN_ALREADY_USED_TYPE } from 'app/shared'; +import { Register } from 'app/account/register/register.service'; +import { RegisterComponent } from 'app/account/register/register.component'; + +describe('Component Tests', () => { + describe('RegisterComponent', () => { + let fixture: ComponentFixture; + let comp: RegisterComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [RegisterComponent] + }) + .overrideTemplate(RegisterComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RegisterComponent); + comp = fixture.componentInstance; + comp.ngOnInit(); + }); + + it('should ensure the two passwords entered match', () => { + comp.registerAccount.password = 'password'; + comp.confirmPassword = 'non-matching'; + + comp.register(); + + expect(comp.doNotMatch).toEqual('ERROR'); + }); + + it('should update success to OK after creating an account', inject( + [Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue(of({})); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(service.save).toHaveBeenCalledWith({ + password: 'password', + langKey: 'en' + }); + expect(comp.success).toEqual(true); + expect(comp.registerAccount.langKey).toEqual('en'); + expect(comp.errorUserExists).toBeNull(); + expect(comp.errorEmailExists).toBeNull(); + expect(comp.error).toBeNull(); + }) + )); + + it('should notify of user existence upon 400/login already in use', inject( + [Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue( + throwError({ + status: 400, + error: { type: LOGIN_ALREADY_USED_TYPE } + }) + ); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(comp.errorUserExists).toEqual('ERROR'); + expect(comp.errorEmailExists).toBeNull(); + expect(comp.error).toBeNull(); + }) + )); + + it('should notify of email existence upon 400/email address already in use', inject( + [Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue( + throwError({ + status: 400, + error: { type: EMAIL_ALREADY_USED_TYPE } + }) + ); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(comp.errorEmailExists).toEqual('ERROR'); + expect(comp.errorUserExists).toBeNull(); + expect(comp.error).toBeNull(); + }) + )); + + it('should notify of generic error', inject( + [Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue( + throwError({ + status: 503 + }) + ); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(comp.errorUserExists).toBeNull(); + expect(comp.errorEmailExists).toBeNull(); + expect(comp.error).toEqual('ERROR'); + }) + )); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/settings/settings.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/settings/settings.component.spec.ts new file mode 100644 index 0000000000..b6a6d34c19 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/account/settings/settings.component.spec.ts @@ -0,0 +1,81 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { Observable, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { AccountService } from 'app/core'; +import { SettingsComponent } from 'app/account/settings/settings.component'; + +describe('Component Tests', () => { + describe('SettingsComponent', () => { + let comp: SettingsComponent; + let fixture: ComponentFixture; + let mockAuth: any; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [SettingsComponent], + providers: [] + }) + .overrideTemplate(SettingsComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SettingsComponent); + comp = fixture.componentInstance; + mockAuth = fixture.debugElement.injector.get(AccountService); + }); + + it('should send the current identity upon save', () => { + // GIVEN + const accountValues = { + firstName: 'John', + lastName: 'Doe', + + activated: true, + email: 'john.doe@mail.com', + langKey: 'en', + login: 'john' + }; + mockAuth.setIdentityResponse(accountValues); + + // WHEN + comp.settingsAccount = accountValues; + comp.save(); + + // THEN + expect(mockAuth.identitySpy).toHaveBeenCalled(); + expect(mockAuth.saveSpy).toHaveBeenCalledWith(accountValues); + expect(comp.settingsAccount).toEqual(accountValues); + }); + + it('should notify of success upon successful save', () => { + // GIVEN + const accountValues = { + firstName: 'John', + lastName: 'Doe' + }; + mockAuth.setIdentityResponse(accountValues); + + // WHEN + comp.save(); + + // THEN + expect(comp.error).toBeNull(); + expect(comp.success).toBe('OK'); + }); + + it('should notify of error upon failed save', () => { + // GIVEN + mockAuth.saveSpy.and.returnValue(throwError('ERROR')); + + // WHEN + comp.save(); + + // THEN + expect(comp.error).toEqual('ERROR'); + expect(comp.success).toBeNull(); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.component.spec.ts new file mode 100644 index 0000000000..254791f51a --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.component.spec.ts @@ -0,0 +1,133 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { Observable, of } from 'rxjs'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; + +import { BookstoreTestModule } from '../../../test.module'; +import { AuditsComponent } from 'app/admin/audits/audits.component'; +import { AuditsService } from 'app/admin/audits/audits.service'; +import { Audit } from 'app/admin/audits/audit.model'; +import { ITEMS_PER_PAGE } from 'app/shared'; + +function build2DigitsDatePart(datePart: number) { + return `0${datePart}`.slice(-2); +} + +function getDate(isToday = true) { + let date: Date = new Date(); + if (isToday) { + // Today + 1 day - needed if the current day must be included + date.setDate(date.getDate() + 1); + } else { + // get last month + if (date.getMonth() === 0) { + date = new Date(date.getFullYear() - 1, 11, date.getDate()); + } else { + date = new Date(date.getFullYear(), date.getMonth() - 1, date.getDate()); + } + } + const monthString = build2DigitsDatePart(date.getMonth() + 1); + const dateString = build2DigitsDatePart(date.getDate()); + return `${date.getFullYear()}-${monthString}-${dateString}`; +} + +describe('Component Tests', () => { + describe('AuditsComponent', () => { + let comp: AuditsComponent; + let fixture: ComponentFixture; + let service: AuditsService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [AuditsComponent], + providers: [AuditsService] + }) + .overrideTemplate(AuditsComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AuditsComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(AuditsService); + }); + + describe('today function ', () => { + it('should set toDate to current date', () => { + comp.today(); + expect(comp.toDate).toBe(getDate()); + }); + }); + + describe('previousMonth function ', () => { + it('should set fromDate to current date', () => { + comp.previousMonth(); + expect(comp.fromDate).toBe(getDate(false)); + }); + }); + + describe('By default, on init', () => { + it('should set all default values correctly', () => { + fixture.detectChanges(); + expect(comp.toDate).toBe(getDate()); + expect(comp.fromDate).toBe(getDate(false)); + expect(comp.itemsPerPage).toBe(ITEMS_PER_PAGE); + expect(comp.page).toBe(10); + expect(comp.reverse).toBeFalsy(); + expect(comp.predicate).toBe('id'); + }); + }); + + describe('OnInit', () => { + it('Should call load all on init', () => { + // GIVEN + const headers = new HttpHeaders().append('link', 'link;link'); + const audit = new Audit({ remoteAddress: '127.0.0.1', sessionId: '123' }, 'user', '20140101', 'AUTHENTICATION_SUCCESS'); + spyOn(service, 'query').and.returnValue( + of( + new HttpResponse({ + body: [audit], + headers + }) + ) + ); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.audits[0]).toEqual(jasmine.objectContaining(audit)); + }); + }); + + describe('Create sort object', () => { + it('Should sort only by id asc', () => { + // GIVEN + comp.predicate = 'id'; + comp.reverse = false; + + // WHEN + const sort = comp.sort(); + + // THEN + expect(sort.length).toEqual(1); + expect(sort[0]).toEqual('id,desc'); + }); + + it('Should sort by timestamp asc then by id', () => { + // GIVEN + comp.predicate = 'timestamp'; + comp.reverse = true; + + // WHEN + const sort = comp.sort(); + + // THEN + expect(sort.length).toEqual(2); + expect(sort[0]).toEqual('timestamp,asc'); + expect(sort[1]).toEqual('id'); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.service.spec.ts new file mode 100644 index 0000000000..84ff79f633 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/audits/audits.service.spec.ts @@ -0,0 +1,59 @@ +import { TestBed } from '@angular/core/testing'; + +import { AuditsService } from 'app/admin/audits/audits.service'; +import { Audit } from 'app/admin/audits/audit.model'; +import { SERVER_API_URL } from 'app/app.constants'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +describe('Service Tests', () => { + describe('Audits Service', () => { + let service: AuditsService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + + service = TestBed.get(AuditsService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call correct URL', () => { + service.query({}).subscribe(() => {}); + + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'management/audits'; + expect(req.request.url).toEqual(resourceUrl); + }); + + it('should return Audits', () => { + const audit = new Audit({ remoteAddress: '127.0.0.1', sessionId: '123' }, 'user', '20140101', 'AUTHENTICATION_SUCCESS'); + + service.query({}).subscribe(received => { + expect(received.body[0]).toEqual(audit); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([audit]); + }); + + it('should propagate not found response', () => { + service.query({}).subscribe(null, (_error: any) => { + expect(_error.status).toEqual(404); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush('Invalid request parameters', { + status: 404, + statusText: 'Bad Request' + }); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.component.spec.ts new file mode 100644 index 0000000000..d21f87b57b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.component.spec.ts @@ -0,0 +1,71 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { of } from 'rxjs'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; + +import { BookstoreTestModule } from '../../../test.module'; +import { JhiConfigurationComponent } from 'app/admin/configuration/configuration.component'; +import { JhiConfigurationService } from 'app/admin/configuration/configuration.service'; +import { ITEMS_PER_PAGE } from 'app/shared'; +import { Log } from 'app/admin'; + +describe('Component Tests', () => { + describe('JhiConfigurationComponent', () => { + let comp: JhiConfigurationComponent; + let fixture: ComponentFixture; + let service: JhiConfigurationService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [JhiConfigurationComponent], + providers: [JhiConfigurationService] + }) + .overrideTemplate(JhiConfigurationComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiConfigurationComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(JhiConfigurationService); + }); + + describe('OnInit', () => { + it('should set all default values correctly', () => { + expect(comp.configKeys).toEqual([]); + expect(comp.filter).toBe(''); + expect(comp.orderProp).toBe('prefix'); + expect(comp.reverse).toBe(false); + }); + it('Should call load all on init', () => { + // GIVEN + const body = [{ config: 'test', properties: 'test' }, { config: 'test2' }]; + const envConfig = { envConfig: 'test' }; + spyOn(service, 'get').and.returnValue(of(body)); + spyOn(service, 'getEnv').and.returnValue(of(envConfig)); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.get).toHaveBeenCalled(); + expect(service.getEnv).toHaveBeenCalled(); + expect(comp.configKeys).toEqual([['0', '1', '2', '3']]); + expect(comp.allConfiguration).toEqual(envConfig); + }); + }); + describe('keys method', () => { + it('should return the keys of an Object', () => { + // GIVEN + const data = { + key1: 'test', + key2: 'test2' + }; + + // THEN + expect(comp.keys(data)).toEqual(['key1', 'key2']); + expect(comp.keys(undefined)).toEqual([]); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.service.spec.ts new file mode 100644 index 0000000000..6039044b7f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/configuration/configuration.service.spec.ts @@ -0,0 +1,64 @@ +import { TestBed } from '@angular/core/testing'; + +import { JhiConfigurationService } from 'app/admin/configuration/configuration.service'; +import { SERVER_API_URL } from 'app/app.constants'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { HttpResponse } from '@angular/common/http'; + +describe('Service Tests', () => { + describe('Logs Service', () => { + let service: JhiConfigurationService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + + service = TestBed.get(JhiConfigurationService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call correct URL', () => { + service.get().subscribe(() => {}); + + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'management/configprops'; + expect(req.request.url).toEqual(resourceUrl); + }); + + it('should get the config', () => { + const angularConfig = { + contexts: { + angular: { + beans: ['test2'] + } + } + }; + service.get().subscribe(received => { + expect(received.body[0]).toEqual(angularConfig); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(angularConfig); + }); + + it('should get the env', () => { + const propertySources = new HttpResponse({ + body: [{ name: 'test1', properties: 'test1' }, { name: 'test2', properties: 'test2' }] + }); + service.get().subscribe(received => { + expect(received.body[0]).toEqual(propertySources); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(propertySources); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/health/health.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/health/health.component.spec.ts new file mode 100644 index 0000000000..549b430f67 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/health/health.component.spec.ts @@ -0,0 +1,321 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; +import { of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { JhiHealthCheckComponent } from 'app/admin/health/health.component'; +import { JhiHealthService } from 'app/admin/health/health.service'; + +describe('Component Tests', () => { + describe('JhiHealthCheckComponent', () => { + let comp: JhiHealthCheckComponent; + let fixture: ComponentFixture; + let service: JhiHealthService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [JhiHealthCheckComponent] + }) + .overrideTemplate(JhiHealthCheckComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiHealthCheckComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(JhiHealthService); + }); + + describe('baseName and subSystemName', () => { + it('should return the basename when it has no sub system', () => { + expect(comp.baseName('base')).toBe('base'); + }); + + it('should return the basename when it has sub systems', () => { + expect(comp.baseName('base.subsystem.system')).toBe('base'); + }); + + it('should return the sub system name', () => { + expect(comp.subSystemName('subsystem')).toBe(''); + }); + + it('should return the subsystem when it has multiple keys', () => { + expect(comp.subSystemName('subsystem.subsystem.system')).toBe(' - subsystem.system'); + }); + }); + + describe('transformHealthData', () => { + it('should flatten empty health data', () => { + const data = {}; + const expected = []; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with no subsystems', () => { + const data = { + details: { + status: 'UP', + db: { + status: 'UP', + database: 'H2', + hello: '1' + }, + mail: { + status: 'UP', + error: 'mail.a.b.c' + } + } + }; + const expected = [ + { + name: 'db', + status: 'UP', + details: { + database: 'H2', + hello: '1' + } + }, + { + name: 'mail', + error: 'mail.a.b.c', + status: 'UP' + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with subsystems at level 1, main system has no additional information', () => { + const data = { + details: { + status: 'UP', + db: { + status: 'UP', + database: 'H2', + hello: '1' + }, + mail: { + status: 'UP', + error: 'mail.a.b.c' + }, + system: { + status: 'DOWN', + subsystem1: { + status: 'UP', + property1: 'system.subsystem1.property1' + }, + subsystem2: { + status: 'DOWN', + error: 'system.subsystem1.error', + property2: 'system.subsystem2.property2' + } + } + } + }; + const expected = [ + { + name: 'db', + status: 'UP', + details: { + database: 'H2', + hello: '1' + } + }, + { + name: 'mail', + error: 'mail.a.b.c', + status: 'UP' + }, + { + name: 'system.subsystem1', + status: 'UP', + details: { + property1: 'system.subsystem1.property1' + } + }, + { + name: 'system.subsystem2', + error: 'system.subsystem1.error', + status: 'DOWN', + details: { + property2: 'system.subsystem2.property2' + } + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with subsystems at level 1, main system has additional information', () => { + const data = { + details: { + status: 'UP', + db: { + status: 'UP', + database: 'H2', + hello: '1' + }, + mail: { + status: 'UP', + error: 'mail.a.b.c' + }, + system: { + status: 'DOWN', + property1: 'system.property1', + subsystem1: { + status: 'UP', + property1: 'system.subsystem1.property1' + }, + subsystem2: { + status: 'DOWN', + error: 'system.subsystem1.error', + property2: 'system.subsystem2.property2' + } + } + } + }; + const expected = [ + { + name: 'db', + status: 'UP', + details: { + database: 'H2', + hello: '1' + } + }, + { + name: 'mail', + error: 'mail.a.b.c', + status: 'UP' + }, + { + name: 'system', + status: 'DOWN', + details: { + property1: 'system.property1' + } + }, + { + name: 'system.subsystem1', + status: 'UP', + details: { + property1: 'system.subsystem1.property1' + } + }, + { + name: 'system.subsystem2', + error: 'system.subsystem1.error', + status: 'DOWN', + details: { + property2: 'system.subsystem2.property2' + } + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with subsystems at level 1, main system has additional error', () => { + const data = { + details: { + status: 'UP', + db: { + status: 'UP', + database: 'H2', + hello: '1' + }, + mail: { + status: 'UP', + error: 'mail.a.b.c' + }, + system: { + status: 'DOWN', + error: 'show me', + subsystem1: { + status: 'UP', + property1: 'system.subsystem1.property1' + }, + subsystem2: { + status: 'DOWN', + error: 'system.subsystem1.error', + property2: 'system.subsystem2.property2' + } + } + } + }; + const expected = [ + { + name: 'db', + status: 'UP', + details: { + database: 'H2', + hello: '1' + } + }, + { + name: 'mail', + error: 'mail.a.b.c', + status: 'UP' + }, + { + name: 'system', + error: 'show me', + status: 'DOWN' + }, + { + name: 'system.subsystem1', + status: 'UP', + details: { + property1: 'system.subsystem1.property1' + } + }, + { + name: 'system.subsystem2', + error: 'system.subsystem1.error', + status: 'DOWN', + details: { + property2: 'system.subsystem2.property2' + } + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + }); + + describe('getBadgeClass', () => { + it('should get badge class', () => { + const upBadgeClass = comp.getBadgeClass('UP'); + const downBadgeClass = comp.getBadgeClass('DOWN'); + expect(upBadgeClass).toEqual('badge-success'); + expect(downBadgeClass).toEqual('badge-danger'); + }); + }); + + describe('refresh', () => { + it('should call refresh on init', () => { + // GIVEN + spyOn(service, 'checkHealth').and.returnValue(of(new HttpResponse())); + spyOn(service, 'transformHealthData').and.returnValue(of({ data: 'test' })); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.checkHealth).toHaveBeenCalled(); + expect(service.transformHealthData).toHaveBeenCalled(); + expect(comp.healthData.value).toEqual({ data: 'test' }); + }); + it('should handle a 503 on refreshing health data', () => { + // GIVEN + spyOn(service, 'checkHealth').and.returnValue(throwError(new HttpErrorResponse({ status: 503, error: 'Mail down' }))); + spyOn(service, 'transformHealthData').and.returnValue(of({ health: 'down' })); + + // WHEN + comp.refresh(); + + // THEN + expect(service.checkHealth).toHaveBeenCalled(); + expect(service.transformHealthData).toHaveBeenCalled(); + expect(comp.healthData.value).toEqual({ health: 'down' }); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.component.spec.ts new file mode 100644 index 0000000000..def356c0f2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.component.spec.ts @@ -0,0 +1,77 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { of } from 'rxjs'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; + +import { BookstoreTestModule } from '../../../test.module'; +import { LogsComponent } from 'app/admin/logs/logs.component'; +import { LogsService } from 'app/admin/logs/logs.service'; +import { ITEMS_PER_PAGE } from 'app/shared'; +import { Log } from 'app/admin'; + +describe('Component Tests', () => { + describe('LogsComponent', () => { + let comp: LogsComponent; + let fixture: ComponentFixture; + let service: LogsService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [LogsComponent], + providers: [LogsService] + }) + .overrideTemplate(LogsComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LogsComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(LogsService); + }); + + describe('OnInit', () => { + it('should set all default values correctly', () => { + expect(comp.filter).toBe(''); + expect(comp.orderProp).toBe('name'); + expect(comp.reverse).toBe(false); + }); + it('Should call load all on init', () => { + // GIVEN + const headers = new HttpHeaders().append('link', 'link;link'); + const log = new Log('main', 'WARN'); + spyOn(service, 'findAll').and.returnValue( + of( + new HttpResponse({ + body: [log], + headers + }) + ) + ); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.findAll).toHaveBeenCalled(); + expect(comp.loggers[0]).toEqual(jasmine.objectContaining(log)); + }); + }); + describe('change log level', () => { + it('should change log level correctly', () => { + // GIVEN + const log = new Log('main', 'ERROR'); + spyOn(service, 'changeLevel').and.returnValue(of(new HttpResponse())); + spyOn(service, 'findAll').and.returnValue(of(new HttpResponse({ body: [log] }))); + + // WHEN + comp.changeLevel('main', 'ERROR'); + + // THEN + expect(service.changeLevel).toHaveBeenCalled(); + expect(service.findAll).toHaveBeenCalled(); + expect(comp.loggers[0]).toEqual(jasmine.objectContaining(log)); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.service.spec.ts new file mode 100644 index 0000000000..c34833922e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/logs/logs.service.spec.ts @@ -0,0 +1,58 @@ +import { TestBed } from '@angular/core/testing'; + +import { LogsService } from 'app/admin/logs/logs.service'; +import { Log } from 'app/admin/logs/log.model'; +import { SERVER_API_URL } from 'app/app.constants'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +describe('Service Tests', () => { + describe('Logs Service', () => { + let service: LogsService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + + service = TestBed.get(LogsService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call correct URL', () => { + service.findAll().subscribe(() => {}); + + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'management/logs'; + expect(req.request.url).toEqual(resourceUrl); + }); + + it('should return Logs', () => { + const log = new Log('main', 'ERROR'); + + service.findAll().subscribe(received => { + expect(received.body[0]).toEqual(log); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([log]); + }); + + it('should change log level', () => { + const log = new Log('main', 'ERROR'); + + service.changeLevel(log).subscribe(received => { + expect(received.body[0]).toEqual(log); + }); + + const req = httpMock.expectOne({ method: 'PUT' }); + req.flush([log]); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.component.spec.ts new file mode 100644 index 0000000000..d4a992b963 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.component.spec.ts @@ -0,0 +1,55 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; +import { of, throwError } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { JhiMetricsMonitoringComponent } from 'app/admin/metrics/metrics.component'; +import { JhiMetricsService } from 'app/admin/metrics/metrics.service'; + +describe('Component Tests', () => { + describe('JhiMetricsMonitoringComponent', () => { + let comp: JhiMetricsMonitoringComponent; + let fixture: ComponentFixture; + let service: JhiMetricsService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [JhiMetricsMonitoringComponent] + }) + .overrideTemplate(JhiMetricsMonitoringComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiMetricsMonitoringComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(JhiMetricsService); + }); + + describe('refresh', () => { + it('should call refresh on init', () => { + // GIVEN + const response = { + timers: { + service: 'test', + unrelatedKey: 'test' + }, + gauges: { + 'jcache.statistics': { + value: 2 + }, + unrelatedKey: 'test' + } + }; + spyOn(service, 'getMetrics').and.returnValue(of(response)); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.getMetrics).toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.service.spec.ts new file mode 100644 index 0000000000..2c3665b062 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/metrics/metrics.service.spec.ts @@ -0,0 +1,57 @@ +import { TestBed } from '@angular/core/testing'; + +import { JhiMetricsService } from 'app/admin/metrics/metrics.service'; +import { SERVER_API_URL } from 'app/app.constants'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +describe('Service Tests', () => { + describe('Logs Service', () => { + let service: JhiMetricsService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + + service = TestBed.get(JhiMetricsService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call correct URL', () => { + service.getMetrics().subscribe(() => {}); + + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'management/jhi-metrics'; + expect(req.request.url).toEqual(resourceUrl); + }); + + it('should return Metrics', () => { + const metrics = []; + + service.getMetrics().subscribe(received => { + expect(received.body[0]).toEqual(metrics); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([metrics]); + }); + + it('should return Thread Dump', () => { + const dump = [{ name: 'test1', threadState: 'RUNNABLE' }]; + + service.threadDump().subscribe(received => { + expect(received.body[0]).toEqual(dump); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([dump]); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-delete-dialog.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-delete-dialog.component.spec.ts new file mode 100644 index 0000000000..596e1b5609 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-delete-dialog.component.spec.ts @@ -0,0 +1,54 @@ +import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Observable, of } from 'rxjs'; +import { JhiEventManager } from 'ng-jhipster'; + +import { BookstoreTestModule } from '../../../test.module'; +import { UserMgmtDeleteDialogComponent } from 'app/admin/user-management/user-management-delete-dialog.component'; +import { UserService } from 'app/core'; + +describe('Component Tests', () => { + describe('User Management Delete Component', () => { + let comp: UserMgmtDeleteDialogComponent; + let fixture: ComponentFixture; + let service: UserService; + let mockEventManager: any; + let mockActiveModal: any; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [UserMgmtDeleteDialogComponent] + }) + .overrideTemplate(UserMgmtDeleteDialogComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserMgmtDeleteDialogComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(UserService); + mockEventManager = fixture.debugElement.injector.get(JhiEventManager); + mockActiveModal = fixture.debugElement.injector.get(NgbActiveModal); + }); + + describe('confirmDelete', () => { + it('Should call delete service on confirmDelete', inject( + [], + fakeAsync(() => { + // GIVEN + spyOn(service, 'delete').and.returnValue(of({})); + + // WHEN + comp.confirmDelete('user'); + tick(); + + // THEN + expect(service.delete).toHaveBeenCalledWith('user'); + expect(mockActiveModal.dismissSpy).toHaveBeenCalled(); + expect(mockEventManager.broadcastSpy).toHaveBeenCalled(); + }) + )); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-detail.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-detail.component.spec.ts new file mode 100644 index 0000000000..f64b8bb88b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-detail.component.spec.ts @@ -0,0 +1,65 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { of } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { UserMgmtDetailComponent } from 'app/admin/user-management/user-management-detail.component'; +import { User } from 'app/core'; + +describe('Component Tests', () => { + describe('User Management Detail Component', () => { + let comp: UserMgmtDetailComponent; + let fixture: ComponentFixture; + const route = ({ + data: of({ user: new User(1, 'user', 'first', 'last', 'first@last.com', true, 'en', ['ROLE_USER'], 'admin', null, null, null) }) + } as any) as ActivatedRoute; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [UserMgmtDetailComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: route + } + ] + }) + .overrideTemplate(UserMgmtDetailComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserMgmtDetailComponent); + comp = fixture.componentInstance; + }); + + describe('OnInit', () => { + it('Should call load all on init', () => { + // GIVEN + + // WHEN + comp.ngOnInit(); + + // THEN + expect(comp.user).toEqual( + jasmine.objectContaining({ + id: 1, + login: 'user', + firstName: 'first', + lastName: 'last', + email: 'first@last.com', + activated: true, + langKey: 'en', + authorities: ['ROLE_USER'], + createdBy: 'admin', + createdDate: null, + lastModifiedBy: null, + lastModifiedDate: null, + password: null + }) + ); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-update.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-update.component.spec.ts new file mode 100644 index 0000000000..c98694ba82 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management-update.component.spec.ts @@ -0,0 +1,99 @@ +import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { ActivatedRoute } from '@angular/router'; +import { Observable, of } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { UserMgmtUpdateComponent } from 'app/admin/user-management/user-management-update.component'; +import { UserService, User } from 'app/core'; + +describe('Component Tests', () => { + describe('User Management Update Component', () => { + let comp: UserMgmtUpdateComponent; + let fixture: ComponentFixture; + let service: UserService; + const route = ({ + data: of({ user: new User(1, 'user', 'first', 'last', 'first@last.com', true, 'en', ['ROLE_USER'], 'admin', null, null, null) }) + } as any) as ActivatedRoute; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [UserMgmtUpdateComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: route + } + ] + }) + .overrideTemplate(UserMgmtUpdateComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserMgmtUpdateComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(UserService); + }); + + describe('OnInit', () => { + it('Should load authorities and language on init', inject( + [], + fakeAsync(() => { + // GIVEN + spyOn(service, 'authorities').and.returnValue(of(['USER'])); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.authorities).toHaveBeenCalled(); + expect(comp.authorities).toEqual(['USER']); + }) + )); + }); + + describe('save', () => { + it('Should call update service on save for existing user', inject( + [], + fakeAsync(() => { + // GIVEN + const entity = new User(123); + spyOn(service, 'update').and.returnValue( + of( + new HttpResponse({ + body: entity + }) + ) + ); + comp.user = entity; + // WHEN + comp.save(); + tick(); // simulate async + + // THEN + expect(service.update).toHaveBeenCalledWith(entity); + expect(comp.isSaving).toEqual(false); + }) + )); + + it('Should call create service on save for new user', inject( + [], + fakeAsync(() => { + // GIVEN + const entity = new User(); + spyOn(service, 'create').and.returnValue(of(new HttpResponse({ body: entity }))); + comp.user = entity; + // WHEN + comp.save(); + tick(); // simulate async + + // THEN + expect(service.create).toHaveBeenCalledWith(entity); + expect(comp.isSaving).toEqual(false); + }) + )); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management.component.spec.ts new file mode 100644 index 0000000000..31fea387b8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/admin/user-management/user-management.component.spec.ts @@ -0,0 +1,85 @@ +import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing'; +import { Observable, of } from 'rxjs'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; + +import { BookstoreTestModule } from '../../../test.module'; +import { UserMgmtComponent } from 'app/admin/user-management/user-management.component'; +import { UserService, User } from 'app/core'; + +describe('Component Tests', () => { + describe('User Management Component', () => { + let comp: UserMgmtComponent; + let fixture: ComponentFixture; + let service: UserService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [UserMgmtComponent] + }) + .overrideTemplate(UserMgmtComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserMgmtComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(UserService); + }); + + describe('OnInit', () => { + it('Should call load all on init', inject( + [], + fakeAsync(() => { + // GIVEN + const headers = new HttpHeaders().append('link', 'link;link'); + spyOn(service, 'query').and.returnValue( + of( + new HttpResponse({ + body: [new User(123)], + headers + }) + ) + ); + + // WHEN + comp.ngOnInit(); + tick(); // simulate async + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.users[0]).toEqual(jasmine.objectContaining({ id: 123 })); + }) + )); + }); + + describe('setActive', () => { + it('Should update user and call load all', inject( + [], + fakeAsync(() => { + // GIVEN + const headers = new HttpHeaders().append('link', 'link;link'); + const user = new User(123); + spyOn(service, 'query').and.returnValue( + of( + new HttpResponse({ + body: [user], + headers + }) + ) + ); + spyOn(service, 'update').and.returnValue(of(new HttpResponse({ status: 200 }))); + + // WHEN + comp.setActive(user, true); + tick(); // simulate async + + // THEN + expect(service.update).toHaveBeenCalledWith(user); + expect(service.query).toHaveBeenCalled(); + expect(comp.users[0]).toEqual(jasmine.objectContaining({ id: 123 })); + }) + )); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/account.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/account.service.spec.ts new file mode 100644 index 0000000000..01ed421f57 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/account.service.spec.ts @@ -0,0 +1,102 @@ +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { TestBed } from '@angular/core/testing'; +import { SERVER_API_URL } from 'app/app.constants'; +import { AccountService } from 'app/core'; +import { JhiDateUtils } from 'ng-jhipster'; +import { SessionStorageService } from 'ngx-webstorage'; + +describe('Service Tests', () => { + describe('Account Service', () => { + let service: AccountService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [JhiDateUtils, SessionStorageService] + }); + + service = TestBed.get(AccountService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call /account if user is undefined', () => { + service.identity().then(() => {}); + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'api/account'; + + expect(req.request.url).toEqual(`${resourceUrl}`); + }); + + it('should call /account only once', () => { + service.identity().then(() => service.identity().then(() => {})); + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'api/account'; + + expect(req.request.url).toEqual(`${resourceUrl}`); + req.flush({ + firstName: 'John' + }); + }); + + describe('hasAuthority', () => { + it('should return false if user is not logged', async () => { + const hasAuthority = await service.hasAuthority('ROLE_USER'); + expect(hasAuthority).toBeFalsy(); + }); + + it('should return false if user is logged and has not authority', async () => { + service.authenticate({ + authorities: ['ROLE_USER'] + }); + + const hasAuthority = await service.hasAuthority('ROLE_ADMIN'); + + expect(hasAuthority).toBeFalsy(); + }); + + it('should return true if user is logged and has authority', async () => { + service.authenticate({ + authorities: ['ROLE_USER'] + }); + + const hasAuthority = await service.hasAuthority('ROLE_USER'); + + expect(hasAuthority).toBeTruthy(); + }); + }); + + describe('hasAnyAuthority', () => { + it('should return false if user is not logged', async () => { + const hasAuthority = await service.hasAnyAuthority(['ROLE_USER']); + expect(hasAuthority).toBeFalsy(); + }); + + it('should return false if user is logged and has not authority', async () => { + service.authenticate({ + authorities: ['ROLE_USER'] + }); + + const hasAuthority = await service.hasAnyAuthority(['ROLE_ADMIN']); + + expect(hasAuthority).toBeFalsy(); + }); + + it('should return true if user is logged and has authority', async () => { + service.authenticate({ + authorities: ['ROLE_USER'] + }); + + const hasAuthority = await service.hasAnyAuthority(['ROLE_USER', 'ROLE_ADMIN']); + + expect(hasAuthority).toBeTruthy(); + }); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/user.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/user.service.spec.ts new file mode 100644 index 0000000000..9c05839a57 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/core/user/user.service.spec.ts @@ -0,0 +1,66 @@ +import { TestBed } from '@angular/core/testing'; +import { JhiDateUtils } from 'ng-jhipster'; + +import { UserService, User } from 'app/core'; +import { SERVER_API_URL } from 'app/app.constants'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +describe('Service Tests', () => { + describe('User Service', () => { + let service: UserService; + let httpMock; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [JhiDateUtils] + }); + + service = TestBed.get(UserService); + httpMock = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); + }); + + describe('Service methods', () => { + it('should call correct URL', () => { + service.find('user').subscribe(() => {}); + + const req = httpMock.expectOne({ method: 'GET' }); + const resourceUrl = SERVER_API_URL + 'api/users'; + expect(req.request.url).toEqual(`${resourceUrl}/user`); + }); + it('should return User', () => { + service.find('user').subscribe(received => { + expect(received.body.login).toEqual('user'); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(new User(1, 'user')); + }); + + it('should return Authorities', () => { + service.authorities().subscribe(_authorities => { + expect(_authorities).toEqual(['ROLE_USER', 'ROLE_ADMIN']); + }); + const req = httpMock.expectOne({ method: 'GET' }); + + req.flush(['ROLE_USER', 'ROLE_ADMIN']); + }); + + it('should propagate not found response', () => { + service.find('user').subscribe(null, (_error: any) => { + expect(_error.status).toEqual(404); + }); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush('Invalid request parameters', { + status: 404, + statusText: 'Bad Request' + }); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-delete-dialog.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-delete-dialog.component.spec.ts new file mode 100644 index 0000000000..6ffba6ee1e --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-delete-dialog.component.spec.ts @@ -0,0 +1,52 @@ +/* tslint:disable max-line-length */ +import { ComponentFixture, TestBed, inject, fakeAsync, tick } from '@angular/core/testing'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Observable, of } from 'rxjs'; +import { JhiEventManager } from 'ng-jhipster'; + +import { BookstoreTestModule } from '../../../test.module'; +import { BookDeleteDialogComponent } from 'app/entities/book/book-delete-dialog.component'; +import { BookService } from 'app/entities/book/book.service'; + +describe('Component Tests', () => { + describe('Book Management Delete Component', () => { + let comp: BookDeleteDialogComponent; + let fixture: ComponentFixture; + let service: BookService; + let mockEventManager: any; + let mockActiveModal: any; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [BookDeleteDialogComponent] + }) + .overrideTemplate(BookDeleteDialogComponent, '') + .compileComponents(); + fixture = TestBed.createComponent(BookDeleteDialogComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(BookService); + mockEventManager = fixture.debugElement.injector.get(JhiEventManager); + mockActiveModal = fixture.debugElement.injector.get(NgbActiveModal); + }); + + describe('confirmDelete', () => { + it('Should call delete service on confirmDelete', inject( + [], + fakeAsync(() => { + // GIVEN + spyOn(service, 'delete').and.returnValue(of({})); + + // WHEN + comp.confirmDelete(123); + tick(); + + // THEN + expect(service.delete).toHaveBeenCalledWith(123); + expect(mockActiveModal.dismissSpy).toHaveBeenCalled(); + expect(mockEventManager.broadcastSpy).toHaveBeenCalled(); + }) + )); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-detail.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-detail.component.spec.ts new file mode 100644 index 0000000000..b0ff94b3ea --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-detail.component.spec.ts @@ -0,0 +1,40 @@ +/* tslint:disable max-line-length */ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { of } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { BookDetailComponent } from 'app/entities/book/book-detail.component'; +import { Book } from 'app/shared/model/book.model'; + +describe('Component Tests', () => { + describe('Book Management Detail Component', () => { + let comp: BookDetailComponent; + let fixture: ComponentFixture; + const route = ({ data: of({ book: new Book(123) }) } as any) as ActivatedRoute; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [BookDetailComponent], + providers: [{ provide: ActivatedRoute, useValue: route }] + }) + .overrideTemplate(BookDetailComponent, '') + .compileComponents(); + fixture = TestBed.createComponent(BookDetailComponent); + comp = fixture.componentInstance; + }); + + describe('OnInit', () => { + it('Should call load all on init', () => { + // GIVEN + + // WHEN + comp.ngOnInit(); + + // THEN + expect(comp.book).toEqual(jasmine.objectContaining({ id: 123 })); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-update.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-update.component.spec.ts new file mode 100644 index 0000000000..336a2e2397 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book-update.component.spec.ts @@ -0,0 +1,60 @@ +/* tslint:disable max-line-length */ +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { Observable, of } from 'rxjs'; + +import { BookstoreTestModule } from '../../../test.module'; +import { BookUpdateComponent } from 'app/entities/book/book-update.component'; +import { BookService } from 'app/entities/book/book.service'; +import { Book } from 'app/shared/model/book.model'; + +describe('Component Tests', () => { + describe('Book Management Update Component', () => { + let comp: BookUpdateComponent; + let fixture: ComponentFixture; + let service: BookService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [BookUpdateComponent] + }) + .overrideTemplate(BookUpdateComponent, '') + .compileComponents(); + + fixture = TestBed.createComponent(BookUpdateComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(BookService); + }); + + describe('save', () => { + it('Should call update service on save for existing entity', fakeAsync(() => { + // GIVEN + const entity = new Book(123); + spyOn(service, 'update').and.returnValue(of(new HttpResponse({ body: entity }))); + comp.book = entity; + // WHEN + comp.save(); + tick(); // simulate async + + // THEN + expect(service.update).toHaveBeenCalledWith(entity); + expect(comp.isSaving).toEqual(false); + })); + + it('Should call create service on save for new entity', fakeAsync(() => { + // GIVEN + const entity = new Book(); + spyOn(service, 'create').and.returnValue(of(new HttpResponse({ body: entity }))); + comp.book = entity; + // WHEN + comp.save(); + tick(); // simulate async + + // THEN + expect(service.create).toHaveBeenCalledWith(entity); + expect(comp.isSaving).toEqual(false); + })); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.component.spec.ts new file mode 100644 index 0000000000..3b3d472650 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.component.spec.ts @@ -0,0 +1,51 @@ +/* tslint:disable max-line-length */ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Observable, of } from 'rxjs'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; + +import { BookstoreTestModule } from '../../../test.module'; +import { BookComponent } from 'app/entities/book/book.component'; +import { BookService } from 'app/entities/book/book.service'; +import { Book } from 'app/shared/model/book.model'; + +describe('Component Tests', () => { + describe('Book Management Component', () => { + let comp: BookComponent; + let fixture: ComponentFixture; + let service: BookService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [BookComponent], + providers: [] + }) + .overrideTemplate(BookComponent, '') + .compileComponents(); + + fixture = TestBed.createComponent(BookComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(BookService); + }); + + it('Should call load all on init', () => { + // GIVEN + const headers = new HttpHeaders().append('link', 'link;link'); + spyOn(service, 'query').and.returnValue( + of( + new HttpResponse({ + body: [new Book(123)], + headers + }) + ) + ); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.books[0]).toEqual(jasmine.objectContaining({ id: 123 })); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.service.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.service.spec.ts new file mode 100644 index 0000000000..cd0c5b7318 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/entities/book/book.service.spec.ts @@ -0,0 +1,137 @@ +/* tslint:disable max-line-length */ +import { TestBed, getTestBed } from '@angular/core/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { of } from 'rxjs'; +import { take, map } from 'rxjs/operators'; +import * as moment from 'moment'; +import { DATE_FORMAT } from 'app/shared/constants/input.constants'; +import { BookService } from 'app/entities/book/book.service'; +import { IBook, Book } from 'app/shared/model/book.model'; + +describe('Service Tests', () => { + describe('Book Service', () => { + let injector: TestBed; + let service: BookService; + let httpMock: HttpTestingController; + let elemDefault: IBook; + let currentDate: moment.Moment; + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + injector = getTestBed(); + service = injector.get(BookService); + httpMock = injector.get(HttpTestingController); + currentDate = moment(); + + elemDefault = new Book(0, 'AAAAAAA', 'AAAAAAA', currentDate, 0, 0); + }); + + describe('Service methods', async () => { + it('should find an element', async () => { + const returnedFromService = Object.assign( + { + published: currentDate.format(DATE_FORMAT) + }, + elemDefault + ); + service + .find(123) + .pipe(take(1)) + .subscribe(resp => expect(resp).toMatchObject({ body: elemDefault })); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(JSON.stringify(returnedFromService)); + }); + + it('should create a Book', async () => { + const returnedFromService = Object.assign( + { + id: 0, + published: currentDate.format(DATE_FORMAT) + }, + elemDefault + ); + const expected = Object.assign( + { + published: currentDate + }, + returnedFromService + ); + service + .create(new Book(null)) + .pipe(take(1)) + .subscribe(resp => expect(resp).toMatchObject({ body: expected })); + const req = httpMock.expectOne({ method: 'POST' }); + req.flush(JSON.stringify(returnedFromService)); + }); + + it('should update a Book', async () => { + const returnedFromService = Object.assign( + { + title: 'BBBBBB', + author: 'BBBBBB', + published: currentDate.format(DATE_FORMAT), + quantity: 1, + price: 1 + }, + elemDefault + ); + + const expected = Object.assign( + { + published: currentDate + }, + returnedFromService + ); + service + .update(expected) + .pipe(take(1)) + .subscribe(resp => expect(resp).toMatchObject({ body: expected })); + const req = httpMock.expectOne({ method: 'PUT' }); + req.flush(JSON.stringify(returnedFromService)); + }); + + it('should return a list of Book', async () => { + const returnedFromService = Object.assign( + { + title: 'BBBBBB', + author: 'BBBBBB', + published: currentDate.format(DATE_FORMAT), + quantity: 1, + price: 1 + }, + elemDefault + ); + const expected = Object.assign( + { + published: currentDate + }, + returnedFromService + ); + service + .query(expected) + .pipe( + take(1), + map(resp => resp.body) + ) + .subscribe(body => expect(body).toContainEqual(expected)); + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(JSON.stringify([returnedFromService])); + httpMock.verify(); + }); + + it('should delete a Book', async () => { + const rxPromise = service.delete(123).subscribe(resp => expect(resp.ok)); + + const req = httpMock.expectOne({ method: 'DELETE' }); + req.flush({ status: 200 }); + }); + }); + + afterEach(() => { + httpMock.verify(); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/alert/alert-error.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/alert/alert-error.component.spec.ts new file mode 100644 index 0000000000..93f344e633 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/alert/alert-error.component.spec.ts @@ -0,0 +1,134 @@ +import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing'; +import { HttpErrorResponse, HttpHeaders } from '@angular/common/http'; +import { JhiAlertService, JhiEventManager } from 'ng-jhipster'; + +import { BookstoreTestModule } from '../../../test.module'; +import { JhiAlertErrorComponent } from 'app/shared/alert/alert-error.component'; +import { MockAlertService } from '../../../helpers/mock-alert.service'; + +describe('Component Tests', () => { + describe('Alert Error Component', () => { + let comp: JhiAlertErrorComponent; + let fixture: ComponentFixture; + let eventManager: JhiEventManager; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [JhiAlertErrorComponent], + providers: [ + JhiEventManager, + { + provide: JhiAlertService, + useClass: MockAlertService + } + ] + }) + .overrideTemplate(JhiAlertErrorComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiAlertErrorComponent); + comp = fixture.componentInstance; + eventManager = fixture.debugElement.injector.get(JhiEventManager); + }); + + describe('Error Handling', () => { + it('Should display an alert on status 0', () => { + // GIVEN + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: { status: 0 } }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('Server not reachable'); + }); + it('Should display an alert on status 404', () => { + // GIVEN + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: { status: 404 } }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('Not found'); + }); + it('Should display an alert on generic error', () => { + // GIVEN + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: { error: { message: 'Error Message' } } }); + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: { error: 'Second Error Message' } }); + // THEN + expect(comp.alerts.length).toBe(2); + expect(comp.alerts[0].msg).toBe('Error Message'); + expect(comp.alerts[1].msg).toBe('Second Error Message'); + }); + it('Should display an alert on status 400 for generic error', () => { + // GIVEN + const response = new HttpErrorResponse({ + url: 'http://localhost:8080/api/foos', + headers: new HttpHeaders(), + status: 400, + statusText: 'Bad Request', + error: { + type: 'https://www.jhipster.tech/problem/constraint-violation', + title: 'Bad Request', + status: 400, + path: '/api/foos', + message: 'error.validation' + } + }); + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: response }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('error.validation'); + }); + it('Should display an alert on status 400 for generic error without message', () => { + // GIVEN + const response = new HttpErrorResponse({ + url: 'http://localhost:8080/api/foos', + headers: new HttpHeaders(), + status: 400, + error: 'Bad Request' + }); + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: response }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('Bad Request'); + }); + it('Should display an alert on status 400 for invalid parameters', () => { + // GIVEN + const response = new HttpErrorResponse({ + url: 'http://localhost:8080/api/foos', + headers: new HttpHeaders(), + status: 400, + statusText: 'Bad Request', + error: { + type: 'https://www.jhipster.tech/problem/constraint-violation', + title: 'Method argument not valid', + status: 400, + path: '/api/foos', + message: 'error.validation', + fieldErrors: [{ objectName: 'foo', field: 'minField', message: 'Min' }] + } + }); + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: response }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('Error on field "MinField"'); + }); + it('Should display an alert on status 400 for error headers', () => { + // GIVEN + const response = new HttpErrorResponse({ + url: 'http://localhost:8080/api/foos', + headers: new HttpHeaders().append('app-error', 'Error Message').append('app-params', 'foo'), + status: 400, + statusText: 'Bad Request', + error: { + status: 400, + message: 'error.validation' + } + }); + eventManager.broadcast({ name: 'bookstoreApp.httpError', content: response }); + // THEN + expect(comp.alerts.length).toBe(1); + expect(comp.alerts[0].msg).toBe('Error Message'); + }); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/login/login.component.spec.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/login/login.component.spec.ts new file mode 100644 index 0000000000..814af64610 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/app/shared/login/login.component.spec.ts @@ -0,0 +1,157 @@ +import { ComponentFixture, TestBed, async, inject, fakeAsync, tick } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { JhiEventManager } from 'ng-jhipster'; + +import { LoginService } from 'app/core/login/login.service'; +import { JhiLoginModalComponent } from 'app/shared/login/login.component'; +import { StateStorageService } from 'app/core/auth/state-storage.service'; +import { BookstoreTestModule } from '../../../test.module'; +import { MockLoginService } from '../../../helpers/mock-login.service'; +import { MockStateStorageService } from '../../../helpers/mock-state-storage.service'; + +describe('Component Tests', () => { + describe('LoginComponent', () => { + let comp: JhiLoginModalComponent; + let fixture: ComponentFixture; + let mockLoginService: any; + let mockStateStorageService: any; + let mockRouter: any; + let mockEventManager: any; + let mockActiveModal: any; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BookstoreTestModule], + declarations: [JhiLoginModalComponent], + providers: [ + { + provide: LoginService, + useClass: MockLoginService + }, + { + provide: StateStorageService, + useClass: MockStateStorageService + } + ] + }) + .overrideTemplate(JhiLoginModalComponent, '') + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiLoginModalComponent); + comp = fixture.componentInstance; + mockLoginService = fixture.debugElement.injector.get(LoginService); + mockStateStorageService = fixture.debugElement.injector.get(StateStorageService); + mockRouter = fixture.debugElement.injector.get(Router); + mockEventManager = fixture.debugElement.injector.get(JhiEventManager); + mockActiveModal = fixture.debugElement.injector.get(NgbActiveModal); + }); + + it('should authenticate the user upon login when previous state was set', inject( + [], + fakeAsync(() => { + // GIVEN + const credentials = { + username: 'admin', + password: 'admin', + rememberMe: true + }; + comp.username = 'admin'; + comp.password = 'admin'; + comp.rememberMe = true; + comp.credentials = credentials; + mockLoginService.setResponse({}); + mockStateStorageService.setResponse({ redirect: 'dummy' }); + + // WHEN/ + comp.login(); + tick(); // simulate async + + // THEN + expect(comp.authenticationError).toEqual(false); + expect(mockActiveModal.dismissSpy).toHaveBeenCalledWith('login success'); + expect(mockEventManager.broadcastSpy).toHaveBeenCalledTimes(1); + expect(mockLoginService.loginSpy).toHaveBeenCalledWith(credentials); + expect(mockStateStorageService.getUrlSpy).toHaveBeenCalledTimes(1); + expect(mockStateStorageService.storeUrlSpy).toHaveBeenCalledWith(null); + expect(mockRouter.navigateSpy).toHaveBeenCalledWith([{ redirect: 'dummy' }]); + }) + )); + + it('should authenticate the user upon login when previous state was not set', inject( + [], + fakeAsync(() => { + // GIVEN + const credentials = { + username: 'admin', + password: 'admin', + rememberMe: true + }; + comp.username = 'admin'; + comp.password = 'admin'; + comp.rememberMe = true; + comp.credentials = credentials; + mockLoginService.setResponse({}); + mockStateStorageService.setResponse(null); + + // WHEN + comp.login(); + tick(); // simulate async + + // THEN + expect(comp.authenticationError).toEqual(false); + expect(mockActiveModal.dismissSpy).toHaveBeenCalledWith('login success'); + expect(mockEventManager.broadcastSpy).toHaveBeenCalledTimes(1); + expect(mockLoginService.loginSpy).toHaveBeenCalledWith(credentials); + expect(mockStateStorageService.getUrlSpy).toHaveBeenCalledTimes(1); + expect(mockStateStorageService.storeUrlSpy).not.toHaveBeenCalled(); + expect(mockRouter.navigateSpy).not.toHaveBeenCalled(); + }) + )); + + it('should empty the credentials upon cancel', () => { + // GIVEN + const credentials = { + username: 'admin', + password: 'admin', + rememberMe: true + }; + + const expected = { + username: null, + password: null, + rememberMe: true + }; + + comp.credentials = credentials; + + // WHEN + comp.cancel(); + + // THEN + expect(comp.authenticationError).toEqual(false); + expect(comp.credentials).toEqual(expected); + expect(mockActiveModal.dismissSpy).toHaveBeenCalledWith('cancel'); + }); + + it('should redirect user when register', () => { + // WHEN + comp.register(); + + // THEN + expect(mockActiveModal.dismissSpy).toHaveBeenCalledWith('to state register'); + expect(mockRouter.navigateSpy).toHaveBeenCalledWith(['/register']); + }); + + it('should redirect user when request password', () => { + // WHEN + comp.requestResetPassword(); + + // THEN + expect(mockActiveModal.dismissSpy).toHaveBeenCalledWith('to state requestReset'); + expect(mockRouter.navigateSpy).toHaveBeenCalledWith(['/reset', 'request']); + }); + }); +}); diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-account.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-account.service.ts new file mode 100644 index 0000000000..659bf4d379 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-account.service.ts @@ -0,0 +1,35 @@ +import { SpyObject } from './spyobject'; +import { AccountService } from 'app/core/auth/account.service'; +import Spy = jasmine.Spy; + +export class MockAccountService extends SpyObject { + getSpy: Spy; + saveSpy: Spy; + fakeResponse: any; + identitySpy: Spy; + + constructor() { + super(AccountService); + + this.fakeResponse = null; + this.getSpy = this.spy('get').andReturn(this); + this.saveSpy = this.spy('save').andReturn(this); + this.setIdentitySpy({}); + } + + subscribe(callback: any) { + callback(this.fakeResponse); + } + + setResponse(json: any): void { + this.fakeResponse = json; + } + + setIdentitySpy(json: any): any { + this.identitySpy = this.spy('identity').andReturn(Promise.resolve(json)); + } + + setIdentityResponse(json: any): void { + this.setIdentitySpy(json); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-active-modal.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-active-modal.service.ts new file mode 100644 index 0000000000..8bf0cc966f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-active-modal.service.ts @@ -0,0 +1,12 @@ +import { SpyObject } from './spyobject'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import Spy = jasmine.Spy; + +export class MockActiveModal extends SpyObject { + dismissSpy: Spy; + + constructor() { + super(NgbActiveModal); + this.dismissSpy = this.spy('dismiss').andReturn(this); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-alert.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-alert.service.ts new file mode 100644 index 0000000000..87f36c71e2 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-alert.service.ts @@ -0,0 +1,11 @@ +import { SpyObject } from './spyobject'; +import { JhiAlertService, JhiAlert } from 'ng-jhipster'; + +export class MockAlertService extends SpyObject { + constructor() { + super(JhiAlertService); + } + addAlert(alertOptions: JhiAlert) { + return alertOptions; + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-event-manager.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-event-manager.service.ts new file mode 100644 index 0000000000..a71b5d9314 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-event-manager.service.ts @@ -0,0 +1,12 @@ +import { SpyObject } from './spyobject'; +import { JhiEventManager } from 'ng-jhipster'; +import Spy = jasmine.Spy; + +export class MockEventManager extends SpyObject { + broadcastSpy: Spy; + + constructor() { + super(JhiEventManager); + this.broadcastSpy = this.spy('broadcast').andReturn(this); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-login.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-login.service.ts new file mode 100644 index 0000000000..93a8ca575f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-login.service.ts @@ -0,0 +1,29 @@ +import { SpyObject } from './spyobject'; +import { LoginService } from 'app/core/login/login.service'; +import Spy = jasmine.Spy; + +export class MockLoginService extends SpyObject { + loginSpy: Spy; + logoutSpy: Spy; + registerSpy: Spy; + requestResetPasswordSpy: Spy; + cancelSpy: Spy; + + constructor() { + super(LoginService); + + this.setLoginSpy({}); + this.logoutSpy = this.spy('logout').andReturn(this); + this.registerSpy = this.spy('register').andReturn(this); + this.requestResetPasswordSpy = this.spy('requestResetPassword').andReturn(this); + this.cancelSpy = this.spy('cancel').andReturn(this); + } + + setLoginSpy(json: any) { + this.loginSpy = this.spy('login').andReturn(Promise.resolve(json)); + } + + setResponse(json: any): void { + this.setLoginSpy(json); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-route.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-route.service.ts new file mode 100644 index 0000000000..3465e05524 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-route.service.ts @@ -0,0 +1,29 @@ +import { ActivatedRoute, Router } from '@angular/router'; +import { SpyObject } from './spyobject'; +import { Observable, of } from 'rxjs'; +import Spy = jasmine.Spy; + +export class MockActivatedRoute extends ActivatedRoute { + constructor(parameters?: any) { + super(); + this.queryParams = of(parameters); + this.params = of(parameters); + this.data = of({ + ...parameters, + pagingParams: { + page: 10, + ascending: false, + predicate: 'id' + } + }); + } +} + +export class MockRouter extends SpyObject { + navigateSpy: Spy; + + constructor() { + super(Router); + this.navigateSpy = this.spy('navigate'); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-state-storage.service.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-state-storage.service.ts new file mode 100644 index 0000000000..1398c7b28b --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/mock-state-storage.service.ts @@ -0,0 +1,22 @@ +import { SpyObject } from './spyobject'; +import { StateStorageService } from 'app/core/auth/state-storage.service'; +import Spy = jasmine.Spy; + +export class MockStateStorageService extends SpyObject { + getUrlSpy: Spy; + storeUrlSpy: Spy; + + constructor() { + super(StateStorageService); + this.setUrlSpy({}); + this.storeUrlSpy = this.spy('storeUrl').andReturn(this); + } + + setUrlSpy(json) { + this.getUrlSpy = this.spy('getUrl').andReturn(json); + } + + setResponse(json: any): void { + this.setUrlSpy(json); + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/spyobject.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/spyobject.ts new file mode 100644 index 0000000000..949e067ef5 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/helpers/spyobject.ts @@ -0,0 +1,69 @@ +export interface GuinessCompatibleSpy extends jasmine.Spy { + /** By chaining the spy with and.returnValue, all calls to the function will return a specific + * value. */ + andReturn(val: any): void; + /** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied + * function. */ + andCallFake(fn: Function): GuinessCompatibleSpy; + /** removes all recorded calls */ + reset(); +} + +export class SpyObject { + static stub(object = null, config = null, overrides = null) { + if (!(object instanceof SpyObject)) { + overrides = config; + config = object; + object = new SpyObject(); + } + + const m = {}; + Object.keys(config).forEach(key => (m[key] = config[key])); + Object.keys(overrides).forEach(key => (m[key] = overrides[key])); + Object.keys(m).forEach(key => { + object.spy(key).andReturn(m[key]); + }); + return object; + } + + constructor(type = null) { + if (type) { + Object.keys(type.prototype).forEach(prop => { + let m = null; + try { + m = type.prototype[prop]; + } catch (e) { + // As we are creating spys for abstract classes, + // these classes might have getters that throw when they are accessed. + // As we are only auto creating spys for methods, this + // should not matter. + } + if (typeof m === 'function') { + this.spy(prop); + } + }); + } + } + + spy(name) { + if (!this[name]) { + this[name] = this._createGuinnessCompatibleSpy(name); + } + return this[name]; + } + + prop(name, value) { + this[name] = value; + } + + /** @internal */ + _createGuinnessCompatibleSpy(name): GuinessCompatibleSpy { + const newSpy: GuinessCompatibleSpy = jasmine.createSpy(name); + newSpy.andCallFake = newSpy.and.callFake; + newSpy.andReturn = newSpy.and.returnValue; + newSpy.reset = newSpy.calls.reset; + // revisit return null here (previously needed for rtts_assert). + newSpy.and.returnValue(null); + return newSpy; + } +} diff --git a/jhipster-5/bookstore-monolith/src/test/javascript/spec/test.module.ts b/jhipster-5/bookstore-monolith/src/test/javascript/spec/test.module.ts new file mode 100644 index 0000000000..c66241f9bb --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/javascript/spec/test.module.ts @@ -0,0 +1,63 @@ +import { DatePipe } from '@angular/common'; +import { ActivatedRoute, Router } from '@angular/router'; +import { NgModule, ElementRef, Renderer } from '@angular/core'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { JhiDataUtils, JhiDateUtils, JhiEventManager, JhiAlertService, JhiParseLinks } from 'ng-jhipster'; + +import { AccountService, LoginModalService } from 'app/core'; +import { MockAccountService } from './helpers/mock-account.service'; +import { MockActivatedRoute, MockRouter } from './helpers/mock-route.service'; +import { MockActiveModal } from './helpers/mock-active-modal.service'; +import { MockEventManager } from './helpers/mock-event-manager.service'; + +@NgModule({ + providers: [ + DatePipe, + JhiDataUtils, + JhiDateUtils, + JhiParseLinks, + { + provide: JhiEventManager, + useClass: MockEventManager + }, + { + provide: NgbActiveModal, + useClass: MockActiveModal + }, + { + provide: ActivatedRoute, + useValue: new MockActivatedRoute({ id: 123 }) + }, + { + provide: Router, + useClass: MockRouter + }, + { + provide: AccountService, + useClass: MockAccountService + }, + { + provide: LoginModalService, + useValue: null + }, + { + provide: ElementRef, + useValue: null + }, + { + provide: Renderer, + useValue: null + }, + { + provide: JhiAlertService, + useValue: null + }, + { + provide: NgbModal, + useValue: null + } + ], + imports: [HttpClientTestingModule] +}) +export class BookstoreTestModule {} diff --git a/jhipster-5/bookstore-monolith/src/test/resources/config/application.yml b/jhipster-5/bookstore-monolith/src/test/resources/config/application.yml new file mode 100644 index 0000000000..34c6ca3e15 --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/resources/config/application.yml @@ -0,0 +1,105 @@ +# =================================================================== +# Spring Boot configuration. +# +# This configuration is used for unit/integration tests. +# +# More information on profiles: https://www.jhipster.tech/profiles/ +# More information on configuration properties: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + + +spring: + application: + name: Bookstore + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:h2:mem:Bookstore;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + name: + username: + password: + hikari: + auto-commit: false + jpa: + database-platform: io.github.jhipster.domain.util.FixedH2Dialect + database: H2 + open-in-view: false + show-sql: false + hibernate: + ddl-auto: none + naming: + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + properties: + hibernate.id.new_generator_mappings: true + hibernate.connection.provider_disables_autocommit: true + hibernate.cache.use_second_level_cache: false + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: false + hibernate.hbm2ddl.auto: validate + hibernate.jdbc.time_zone: UTC + liquibase: + contexts: test + mail: + host: localhost + messages: + basename: i18n/messages + mvc: + favicon: + enabled: false + thymeleaf: + mode: HTML + + +server: + port: 10344 + address: localhost + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +jhipster: + async: + core-pool-size: 1 + max-pool-size: 50 + queue-capacity: 10000 + # To test logstash appender + logging: + logstash: + enabled: true + host: localhost + port: 5000 + queue-size: 512 + mail: + from: test@localhost + base-url: http://127.0.0.1:8080 + security: + authentication: + jwt: + # This token must be encoded using Base64 (you can type `echo 'secret-key'|base64` on your command line) + base64-secret: NDJmOTVlZjI2NzhlZDRjNmVkNTM1NDE2NjkyNDljZDJiNzBlMjI5YmZjMjY3MzdjZmZlMjI3NjE4OTRkNzc5MWYzNDNlYWMzYmJjOWRmMjc5ZWQyZTZmOWZkOTMxZWZhNWE1MTVmM2U2NjFmYjhlNDc2Y2Q3NzliMGY0YzFkNmI= + # Token is valid 24 hours + token-validity-in-seconds: 86400 + metrics: + logs: # Reports metrics in the logs + enabled: true + report-frequency: 60 # in seconds + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://www.jhipster.tech/common-application-properties/ +# =================================================================== + +# application: diff --git a/jhipster-5/bookstore-monolith/src/test/resources/i18n/messages_en.properties b/jhipster-5/bookstore-monolith/src/test/resources/i18n/messages_en.properties new file mode 100644 index 0000000000..f19db8692f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/resources/i18n/messages_en.properties @@ -0,0 +1 @@ +email.test.title=test title diff --git a/jhipster-5/bookstore-monolith/src/test/resources/logback.xml b/jhipster-5/bookstore-monolith/src/test/resources/logback.xml new file mode 100644 index 0000000000..6244807dfa --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/resources/logback.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster-5/bookstore-monolith/src/test/resources/templates/mail/testEmail.html b/jhipster-5/bookstore-monolith/src/test/resources/templates/mail/testEmail.html new file mode 100644 index 0000000000..a4ca16a79f --- /dev/null +++ b/jhipster-5/bookstore-monolith/src/test/resources/templates/mail/testEmail.html @@ -0,0 +1 @@ + diff --git a/jhipster-5/bookstore-monolith/tsconfig-aot.json b/jhipster-5/bookstore-monolith/tsconfig-aot.json new file mode 100644 index 0000000000..110cde9fd6 --- /dev/null +++ b/jhipster-5/bookstore-monolith/tsconfig-aot.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": false, + "suppressImplicitAnyIndexErrors": true, + "skipLibCheck": true, + "outDir": "target/www/app", + "lib": ["es7", "dom"], + "typeRoots": ["node_modules/@types"], + "baseUrl": "./", + "paths": { + "app/*": ["src/main/webapp/app/*"] + }, + "importHelpers": true + }, + "angularCompilerOptions": { + "genDir": "target/aot", + "skipMetadataEmit": true, + "fullTemplateTypeCheck": true, + "preserveWhitespaces": true + } +} diff --git a/jhipster-5/bookstore-monolith/tsconfig.json b/jhipster-5/bookstore-monolith/tsconfig.json new file mode 100644 index 0000000000..dd6343ab62 --- /dev/null +++ b/jhipster-5/bookstore-monolith/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": false, + "skipLibCheck": true, + "suppressImplicitAnyIndexErrors": true, + "outDir": "target/www/app", + "lib": ["es7", "dom"], + "typeRoots": ["node_modules/@types"], + "baseUrl": "./", + "paths": { + "app/*": ["src/main/webapp/app/*"] + }, + "importHelpers": true, + "allowJs": true + }, + "include": ["src/main/webapp/app", "src/test/javascript/"], + "exclude": ["node_modules"] +} diff --git a/jhipster-5/bookstore-monolith/tslint.json b/jhipster-5/bookstore-monolith/tslint.json new file mode 100644 index 0000000000..3b8456d2fd --- /dev/null +++ b/jhipster-5/bookstore-monolith/tslint.json @@ -0,0 +1,76 @@ +{ + "rulesDirectory": ["node_modules/codelyzer"], + "extends": ["tslint-config-prettier"], + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": true, + "forin": true, + "indent": [true, "spaces"], + "label-position": true, + "member-access": false, + "member-ordering": [true, "static-before-instance", "variables-before-functions"], + "no-arg": true, + "no-bitwise": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-variable": true, + "no-empty": false, + "no-eval": true, + "no-inferrable-types": [true], + "no-shadowed-variable": true, + "no-string-literal": false, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "radix": true, + "semicolon": [true, "always", "ignore-bound-class-methods"], + "triple-equals": [true, "allow-null-check"], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "variable-name": false, + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"], + "prefer-const": true, + "arrow-parens": [true, "ban-single-arg-parens"], + "arrow-return-shorthand": [true], + "import-spacing": true, + "no-consecutive-blank-lines": [true], + "object-literal-shorthand": true, + "space-before-function-paren": [ + true, + { + "asyncArrow": "always", + "anonymous": "never", + "constructor": "never", + "method": "never", + "named": "never" + } + ], + + "directive-selector": [true, "attribute", "jhi", "camelCase"], + "component-selector": [true, "element", "jhi", "kebab-case"], + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": false, + "component-class-suffix": true, + "directive-class-suffix": true + } +} diff --git a/jhipster-5/bookstore-monolith/webpack/logo-jhipster.png b/jhipster-5/bookstore-monolith/webpack/logo-jhipster.png new file mode 100644 index 0000000000..d8eb48da05 Binary files /dev/null and b/jhipster-5/bookstore-monolith/webpack/logo-jhipster.png differ diff --git a/jhipster-5/bookstore-monolith/webpack/utils.js b/jhipster-5/bookstore-monolith/webpack/utils.js new file mode 100644 index 0000000000..2fce772341 --- /dev/null +++ b/jhipster-5/bookstore-monolith/webpack/utils.js @@ -0,0 +1,44 @@ +const fs = require('fs'); +const path = require('path'); + +module.exports = { + parseVersion, + root, + isExternalLib +}; + +const parseString = require('xml2js').parseString; +// return the version number from `pom.xml` file +function parseVersion() { + let version = null; + const pomXml = fs.readFileSync('pom.xml', 'utf8'); + parseString(pomXml, (err, result) => { + if (err) { + throw new Error('Failed to parse pom.xml: ' + err); + } + if (result.project.version && result.project.version[0]) { + version = result.project.version[0]; + } else if (result.project.parent && result.project.parent[0] && result.project.parent[0].version && result.project.parent[0].version[0]) { + version = result.project.parent[0].version[0]; + } + }); + if (version === null) { + throw new Error('pom.xml is malformed. No version is defined'); + } + return version; +} + +const _root = path.resolve(__dirname, '..'); + +function root(args) { + args = Array.prototype.slice.call(arguments, 0); + return path.join.apply(path, [_root].concat(args)); +} + +function isExternalLib(module, check = /node_modules/) { + const req = module.userRequest; + if (typeof req !== 'string') { + return false; + } + return req.search(check) >= 0; +} diff --git a/jhipster-5/bookstore-monolith/webpack/webpack.common.js b/jhipster-5/bookstore-monolith/webpack/webpack.common.js new file mode 100644 index 0000000000..d8fd26c157 --- /dev/null +++ b/jhipster-5/bookstore-monolith/webpack/webpack.common.js @@ -0,0 +1,86 @@ +const webpack = require('webpack'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const rxPaths = require('rxjs/_esm5/path-mapping'); + +const utils = require('./utils.js'); + +module.exports = (options) => ({ + resolve: { + extensions: ['.ts', '.js'], + modules: ['node_modules'], + alias: { + app: utils.root('src/main/webapp/app/'), + ...rxPaths() + } + }, + stats: { + children: false + }, + module: { + rules: [ + { + test: /\.html$/, + loader: 'html-loader', + options: { + minimize: true, + caseSensitive: true, + removeAttributeQuotes:false, + minifyJS:false, + minifyCSS:false + }, + exclude: /(src\/main\/webapp\/index.html)/ + }, + { + test: /\.(jpe?g|png|gif|svg|woff2?|ttf|eot)$/i, + loader: 'file-loader', + options: { + digest: 'hex', + hash: 'sha512', + name: 'content/[hash].[ext]' + } + }, + { + test: /manifest.webapp$/, + loader: 'file-loader', + options: { + name: 'manifest.webapp' + } + }, + // Ignore warnings about System.import in Angular + { test: /[\/\\]@angular[\/\\].+\.js$/, parser: { system: true } }, + ] + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: `'${options.env}'`, + BUILD_TIMESTAMP: `'${new Date().getTime()}'`, + VERSION: `'${utils.parseVersion()}'`, + DEBUG_INFO_ENABLED: options.env === 'development', + // The root URL for API calls, ending with a '/' - for example: `"https://www.jhipster.tech:8081/myservice/"`. + // If this URL is left empty (""), then it will be relative to the current context. + // If you use an API server, in `prod` mode, you will need to enable CORS + // (see the `jhipster.cors` common JHipster property in the `application-*.yml` configurations) + SERVER_API_URL: `''` + } + }), + new CopyWebpackPlugin([ + { from: './node_modules/swagger-ui/dist/css', to: 'swagger-ui/dist/css' }, + { from: './node_modules/swagger-ui/dist/lib', to: 'swagger-ui/dist/lib' }, + { from: './node_modules/swagger-ui/dist/swagger-ui.min.js', to: 'swagger-ui/dist/swagger-ui.min.js' }, + { from: './src/main/webapp/swagger-ui/', to: 'swagger-ui' }, + { from: './src/main/webapp/content/', to: 'content' }, + { from: './src/main/webapp/favicon.ico', to: 'favicon.ico' }, + { from: './src/main/webapp/manifest.webapp', to: 'manifest.webapp' }, + // jhipster-needle-add-assets-to-webpack - JHipster will add/remove third-party resources in this array + { from: './src/main/webapp/robots.txt', to: 'robots.txt' } + ]), + new HtmlWebpackPlugin({ + template: './src/main/webapp/index.html', + chunks: ['vendors', 'polyfills', 'main', 'global'], + chunksSortMode: 'manual', + inject: 'body' + }) + ] +}); diff --git a/jhipster-5/bookstore-monolith/webpack/webpack.dev.js b/jhipster-5/bookstore-monolith/webpack/webpack.dev.js new file mode 100644 index 0000000000..d05a7ddea8 --- /dev/null +++ b/jhipster-5/bookstore-monolith/webpack/webpack.dev.js @@ -0,0 +1,148 @@ +const webpack = require('webpack'); +const writeFilePlugin = require('write-file-webpack-plugin'); +const webpackMerge = require('webpack-merge'); +const BrowserSyncPlugin = require('browser-sync-webpack-plugin'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin'); +const SimpleProgressWebpackPlugin = require('simple-progress-webpack-plugin'); +const WebpackNotifierPlugin = require('webpack-notifier'); +const path = require('path'); +const sass = require('sass'); + +const utils = require('./utils.js'); +const commonConfig = require('./webpack.common.js'); + +const ENV = 'development'; + +module.exports = (options) => webpackMerge(commonConfig({ env: ENV }), { + devtool: 'eval-source-map', + devServer: { + contentBase: './target/www', + proxy: [{ + context: [ + /* jhipster-needle-add-entity-to-webpack - JHipster will add entity api paths here */ + '/api', + '/management', + '/swagger-resources', + '/v2/api-docs', + '/h2-console', + '/auth' + ], + target: `http${options.tls ? 's' : ''}://127.0.0.1:8080`, + secure: false, + changeOrigin: options.tls, + headers: { host: 'localhost:9000' } + }], + stats: options.stats, + watchOptions: { + ignored: /node_modules/ + } + }, + entry: { + polyfills: './src/main/webapp/app/polyfills', + global: './src/main/webapp/content/scss/global.scss', + main: './src/main/webapp/app/app.main' + }, + output: { + path: utils.root('target/www'), + filename: 'app/[name].bundle.js', + chunkFilename: 'app/[id].chunk.js' + }, + module: { + rules: [{ + test: /\.ts$/, + enforce: 'pre', + loader: 'tslint-loader', + exclude: [/(node_modules)/, new RegExp('reflect-metadata\\' + path.sep + 'Reflect\\.ts')] + }, + { + test: /\.ts$/, + use: [ + 'angular2-template-loader', + { + loader: 'cache-loader', + options: { + cacheDirectory: path.resolve('target/cache-loader') + } + }, + { + loader: 'thread-loader', + options: { + // there should be 1 cpu for the fork-ts-checker-webpack-plugin + workers: require('os').cpus().length - 1 + } + }, + { + loader: 'ts-loader', + options: { + transpileOnly: true, + happyPackMode: true + } + }, + 'angular-router-loader' + ], + exclude: /(node_modules)/ + }, + { + test: /\.scss$/, + use: ['to-string-loader', 'css-loader', { + loader: 'sass-loader', + options: { implementation: sass } + }], + exclude: /(vendor\.scss|global\.scss)/ + }, + { + test: /(vendor\.scss|global\.scss)/, + use: ['style-loader', 'css-loader', 'postcss-loader', { + loader: 'sass-loader', + options: { implementation: sass } + }] + }, + { + test: /\.css$/, + use: ['to-string-loader', 'css-loader'], + exclude: /(vendor\.css|global\.css)/ + }, + { + test: /(vendor\.css|global\.css)/, + use: ['style-loader', 'css-loader'] + }] + }, + stats: process.env.JHI_DISABLE_WEBPACK_LOGS ? 'none' : options.stats, + plugins: [ + process.env.JHI_DISABLE_WEBPACK_LOGS + ? null + : new SimpleProgressWebpackPlugin({ + format: options.stats === 'minimal' ? 'compact' : 'expanded' + }), + new FriendlyErrorsWebpackPlugin(), + new ForkTsCheckerWebpackPlugin(), + new BrowserSyncPlugin({ + host: 'localhost', + port: 9000, + proxy: { + target: 'http://localhost:9060' + }, + socket: { + clients: { + heartbeatTimeout: 60000 + } + } + }, { + reload: false + }), + new webpack.ContextReplacementPlugin( + /angular(\\|\/)core(\\|\/)/, + path.resolve(__dirname, './src/main/webapp') + ), + new writeFilePlugin(), + new webpack.WatchIgnorePlugin([ + utils.root('src/test'), + ]), + new WebpackNotifierPlugin({ + title: 'JHipster', + contentImage: path.join(__dirname, 'logo-jhipster.png') + }) + ].filter(Boolean), + mode: 'development' +}); diff --git a/jhipster-5/bookstore-monolith/webpack/webpack.prod.js b/jhipster-5/bookstore-monolith/webpack/webpack.prod.js new file mode 100644 index 0000000000..ebafa2f631 --- /dev/null +++ b/jhipster-5/bookstore-monolith/webpack/webpack.prod.js @@ -0,0 +1,144 @@ +const webpack = require('webpack'); +const webpackMerge = require('webpack-merge'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); +const Visualizer = require('webpack-visualizer-plugin'); +const MomentLocalesPlugin = require('moment-locales-webpack-plugin'); +const TerserPlugin = require('terser-webpack-plugin'); +const WorkboxPlugin = require('workbox-webpack-plugin'); +const AngularCompilerPlugin = require('@ngtools/webpack').AngularCompilerPlugin; +const path = require('path'); + +const utils = require('./utils.js'); +const commonConfig = require('./webpack.common.js'); + +const ENV = 'production'; +const sass = require('sass'); + +module.exports = webpackMerge(commonConfig({ env: ENV }), { + // Enable source maps. Please note that this will slow down the build. + // You have to enable it in UglifyJSPlugin config below and in tsconfig-aot.json as well + // devtool: 'source-map', + entry: { + polyfills: './src/main/webapp/app/polyfills', + global: './src/main/webapp/content/scss/global.scss', + main: './src/main/webapp/app/app.main' + }, + output: { + path: utils.root('target/www'), + filename: 'app/[name].[hash].bundle.js', + chunkFilename: 'app/[id].[hash].chunk.js' + }, + module: { + rules: [{ + test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, + loader: '@ngtools/webpack' + }, + { + test: /\.scss$/, + use: ['to-string-loader', 'css-loader', { + loader: 'sass-loader', + options: { implementation: sass } + }], + exclude: /(vendor\.scss|global\.scss)/ + }, + { + test: /(vendor\.scss|global\.scss)/, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader', + 'postcss-loader', + { + loader: 'sass-loader', + options: { implementation: sass } + } + ] + }, + { + test: /\.css$/, + use: ['to-string-loader', 'css-loader'], + exclude: /(vendor\.css|global\.css)/ + }, + { + test: /(vendor\.css|global\.css)/, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader', + 'postcss-loader' + ] + }] + }, + optimization: { + runtimeChunk: false, + splitChunks: { + cacheGroups: { + commons: { + test: /[\\/]node_modules[\\/]/, + name: 'vendors', + chunks: 'all' + } + } + }, + minimizer: [ + new TerserPlugin({ + parallel: true, + cache: true, + terserOptions: { + ie8: false, + // sourceMap: true, // Enable source maps. Please note that this will slow down the build + compress: { + dead_code: true, + warnings: false, + properties: true, + drop_debugger: true, + conditionals: true, + booleans: true, + loops: true, + unused: true, + toplevel: true, + if_return: true, + inline: true, + join_vars: true + }, + output: { + comments: false, + beautify: false, + indent_level: 2 + } + } + }), + new OptimizeCSSAssetsPlugin({}) + ] + }, + plugins: [ + new MiniCssExtractPlugin({ + // Options similar to the same options in webpackOptions.output + // both options are optional + filename: '[name].[contenthash].css', + chunkFilename: '[id].css' + }), + new MomentLocalesPlugin({ + localesToKeep: [ + // jhipster-needle-i18n-language-moment-webpack - JHipster will add/remove languages in this array + ] + }), + new Visualizer({ + // Webpack statistics in target folder + filename: '../stats.html' + }), + new AngularCompilerPlugin({ + mainPath: utils.root('src/main/webapp/app/app.main.ts'), + tsConfigPath: utils.root('tsconfig-aot.json'), + sourceMap: true + }), + new webpack.LoaderOptionsPlugin({ + minimize: true, + debug: false + }), + new WorkboxPlugin.GenerateSW({ + clientsClaim: true, + skipWaiting: true, + }) + ], + mode: 'production' +}); diff --git a/jhipster-5/pom.xml b/jhipster-5/pom.xml new file mode 100644 index 0000000000..df60b01317 --- /dev/null +++ b/jhipster-5/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + com.baeldung.jhipster + jhipster-5 + 1.0.0-SNAPSHOT + JHipster + pom + + + parent-boot-1 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-1 + + + + bookstore-monolith + + + diff --git a/jhipster/README.md b/jhipster/README.md index 91ba54bf60..289bfac754 100644 --- a/jhipster/README.md +++ b/jhipster/README.md @@ -3,3 +3,4 @@ - [JHipster with a Microservice Architecture](http://www.baeldung.com/jhipster-microservices) - [Intro to JHipster](http://www.baeldung.com/jhipster) - [Building a Basic UAA-Secured JHipster Microservice](https://www.baeldung.com/jhipster-uaa-secured-micro-service) +- [Creating New Roles and Authorities in JHipster](https://www.baeldung.com/jhipster-new-roles) diff --git a/jhipster/jhipster-monolithic/src/main/java/com/baeldung/security/AuthoritiesConstants.java b/jhipster/jhipster-monolithic/src/main/java/com/baeldung/security/AuthoritiesConstants.java index 40cf54e4f6..a28edd97de 100644 --- a/jhipster/jhipster-monolithic/src/main/java/com/baeldung/security/AuthoritiesConstants.java +++ b/jhipster/jhipster-monolithic/src/main/java/com/baeldung/security/AuthoritiesConstants.java @@ -7,6 +7,8 @@ public final class AuthoritiesConstants { public static final String ADMIN = "ROLE_ADMIN"; + public static final String MANAGER = "ROLE_MANAGER"; + public static final String USER = "ROLE_USER"; public static final String ANONYMOUS = "ROLE_ANONYMOUS"; diff --git a/jhipster/jhipster-monolithic/src/main/resources/config/liquibase/authorities.csv b/jhipster/jhipster-monolithic/src/main/resources/config/liquibase/authorities.csv index af5c6dfa18..91f05d6303 100644 --- a/jhipster/jhipster-monolithic/src/main/resources/config/liquibase/authorities.csv +++ b/jhipster/jhipster-monolithic/src/main/resources/config/liquibase/authorities.csv @@ -1,3 +1,4 @@ name ROLE_ADMIN +ROLE_MANAGER ROLE_USER diff --git a/jhipster/jhipster-uaa/pom.xml b/jhipster/jhipster-uaa/pom.xml index 88df59b735..a59b19d1fd 100644 --- a/jhipster/jhipster-uaa/pom.xml +++ b/jhipster/jhipster-uaa/pom.xml @@ -2,9 +2,8 @@ 4.0.0 - com.baeldung.jhipster - jhipster-microservice-uaa - JHipster Microservice with UAA + jhipster-uaa + jhipster-uaa pom diff --git a/jhipster/pom.xml b/jhipster/pom.xml index 3fcc53b354..c50aac0c7a 100644 --- a/jhipster/pom.xml +++ b/jhipster/pom.xml @@ -15,6 +15,13 @@ ../parent-boot-1 + + + org.hibernate + hibernate-java8 + + + jhipster-monolithic jhipster-microservice diff --git a/jib/pom.xml b/jib/pom.xml index 5c9f242a20..2341fcca0c 100644 --- a/jib/pom.xml +++ b/jib/pom.xml @@ -39,7 +39,6 @@ - 1.8 0.9.10 diff --git a/jjwt/README.md b/jjwt/README.md index 54a5226056..ed18363dfc 100644 --- a/jjwt/README.md +++ b/jjwt/README.md @@ -42,7 +42,6 @@ Available commands (assumes httpie - https://github.com/jkbrzt/httpie): Parse passed in JWT enforcing the 'iss' registered claim and the 'hasMotorcycle' custom claim ``` -The Baeldung post that compliments this repo can be found [here](http://www.baeldung.com/) ## Relevant articles: diff --git a/jooby/README.md b/jooby/README.md index 032e595354..aa867b2c56 100644 --- a/jooby/README.md +++ b/jooby/README.md @@ -1,3 +1,3 @@ ## Relevant articles: -- [Introduction to Jooby Project](http://www.baeldung.com/jooby) +- [Introduction to Jooby](http://www.baeldung.com/jooby) diff --git a/jsf/README.md b/jsf/README.md index 6e0891182d..d96c1eb8e3 100644 --- a/jsf/README.md +++ b/jsf/README.md @@ -1,5 +1,5 @@ ### Relevant Articles: -- [Introduction to JSF Expression Language 3.0](http://www.baeldung.com/jsf-expression-language-el-3) +- [Guide to JSF Expression Language 3.0](http://www.baeldung.com/jsf-expression-language-el-3) - [Introduction to JSF EL 2](http://www.baeldung.com/intro-to-jsf-expression-language) - [JavaServer Faces (JSF) with Spring](http://www.baeldung.com/spring-jsf) - [Introduction to Primefaces](http://www.baeldung.com/jsf-primefaces) diff --git a/json/README.md b/json/README.md index 2e253a4ae9..7ef4cc9b01 100644 --- a/json/README.md +++ b/json/README.md @@ -11,3 +11,5 @@ - [Overview of JSON Pointer](https://www.baeldung.com/json-pointer) - [Introduction to the JSON Binding API (JSR 367) in Java](http://www.baeldung.com/java-json-binding-api) - [Get a Value by Key in a JSONArray](https://www.baeldung.com/java-jsonarray-get-value-by-key) +- [Iterating Over an Instance of org.json.JSONObject](https://www.baeldung.com/jsonobject-iteration) +- [Escape JSON String in Java](https://www.baeldung.com/java-json-escaping) diff --git a/json/pom.xml b/json/pom.xml index 23955e5a75..c76625a6fa 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -42,7 +42,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson-databind.version} + ${jackson.version} javax.json.bind @@ -73,6 +73,12 @@ ${commons-collections4.version} test + + org.assertj + assertj-core + ${assertj-core.version} + test + @@ -83,9 +89,8 @@ 1.0.1 20171018 2.8.5 - 2.9.7 - 4.12 1.1.2 + 3.11.1 diff --git a/json/src/main/java/com/baeldung/jsonobject/iterate/JSONObjectIterator.java b/json/src/main/java/com/baeldung/jsonobject/iterate/JSONObjectIterator.java new file mode 100644 index 0000000000..0ff8650652 --- /dev/null +++ b/json/src/main/java/com/baeldung/jsonobject/iterate/JSONObjectIterator.java @@ -0,0 +1,50 @@ +package com.baeldung.jsonobject.iterate; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONObject; + +public class JSONObjectIterator { + + private Map keyValuePairs; + + public JSONObjectIterator() { + keyValuePairs = new HashMap<>(); + } + + public void handleValue(String key, Object value) { + if (value instanceof JSONArray) { + handleJSONArray(key, (JSONArray) value); + } else if (value instanceof JSONObject) { + handleJSONObject((JSONObject) value); + } + keyValuePairs.put(key, value); + } + + public void handleJSONObject(JSONObject jsonObject) { + Iterator jsonObjectIterator = jsonObject.keys(); + jsonObjectIterator.forEachRemaining(key -> { + Object value = jsonObject.get(key); + handleValue(key, value); + }); + } + + public void handleJSONArray(String key, JSONArray jsonArray) { + Iterator jsonArrayIterator = jsonArray.iterator(); + jsonArrayIterator.forEachRemaining(element -> { + handleValue(key, element); + }); + } + + public Map getKeyValuePairs() { + return keyValuePairs; + } + + public void setKeyValuePairs(Map keyValuePairs) { + this.keyValuePairs = keyValuePairs; + } + +} diff --git a/json/src/test/java/com/baeldung/jsonobject/iterate/JSONObjectIteratorUnitTest.java b/json/src/test/java/com/baeldung/jsonobject/iterate/JSONObjectIteratorUnitTest.java new file mode 100644 index 0000000000..55cfdab53b --- /dev/null +++ b/json/src/test/java/com/baeldung/jsonobject/iterate/JSONObjectIteratorUnitTest.java @@ -0,0 +1,79 @@ +package com.baeldung.jsonobject.iterate; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Test; + +public class JSONObjectIteratorUnitTest { + + private JSONObjectIterator jsonObjectIterator = new JSONObjectIterator(); + + @Test + public void givenJSONObject_whenIterating_thenGetKeyValuePairs() { + JSONObject jsonObject = getJsonObject(); + + jsonObjectIterator.handleJSONObject(jsonObject); + + Map keyValuePairs = jsonObjectIterator.getKeyValuePairs(); + assertThat(keyValuePairs.get("rType")).isEqualTo("Regular"); + assertThat(keyValuePairs.get("rId")).isEqualTo("1001"); + assertThat(keyValuePairs.get("cType")).isEqualTo("Chocolate"); + assertThat(keyValuePairs.get("cId")).isEqualTo("1002"); + assertThat(keyValuePairs.get("bType")).isEqualTo("BlueBerry"); + assertThat(keyValuePairs.get("bId")).isEqualTo("1003"); + assertThat(keyValuePairs.get("name")).isEqualTo("Cake"); + assertThat(keyValuePairs.get("cakeId")).isEqualTo("0001"); + assertThat(keyValuePairs.get("type")).isEqualTo("donut"); + assertThat(keyValuePairs.get("Type")).isEqualTo("Maple"); + assertThat(keyValuePairs.get("tId")).isEqualTo("5001"); + assertThat(keyValuePairs.get("batters") + .toString()).isEqualTo("[{\"rType\":\"Regular\",\"rId\":\"1001\"},{\"cType\":\"Chocolate\",\"cId\":\"1002\"},{\"bType\":\"BlueBerry\",\"bId\":\"1003\"}]"); + assertThat(keyValuePairs.get("cakeShapes") + .toString()).isEqualTo("[\"square\",\"circle\",\"heart\"]"); + assertThat(keyValuePairs.get("topping") + .toString()).isEqualTo("{\"Type\":\"Maple\",\"tId\":\"5001\"}"); + } + + private JSONObject getJsonObject() { + JSONObject cake = new JSONObject(); + cake.put("cakeId", "0001"); + cake.put("type", "donut"); + cake.put("name", "Cake"); + + JSONArray batters = new JSONArray(); + JSONObject regular = new JSONObject(); + regular.put("rId", "1001"); + regular.put("rType", "Regular"); + batters.put(regular); + JSONObject chocolate = new JSONObject(); + chocolate.put("cId", "1002"); + chocolate.put("cType", "Chocolate"); + batters.put(chocolate); + JSONObject blueberry = new JSONObject(); + blueberry.put("bId", "1003"); + blueberry.put("bType", "BlueBerry"); + batters.put(blueberry); + + JSONArray cakeShapes = new JSONArray(); + cakeShapes.put("square"); + cakeShapes.put("circle"); + cakeShapes.put("heart"); + + cake.put("cakeShapes", cakeShapes); + + cake.put("batters", batters); + + JSONObject topping = new JSONObject(); + topping.put("tId", "5001"); + topping.put("Type", "Maple"); + + cake.put("topping", topping); + + return cake; + } + +} diff --git a/jta/pom.xml b/jta/pom.xml index 038f1dc8d1..6a31733996 100644 --- a/jta/pom.xml +++ b/jta/pom.xml @@ -10,10 +10,10 @@ JEE JTA demo - org.springframework.boot - spring-boot-starter-parent - 2.0.4.RELEASE - + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 @@ -85,5 +85,6 @@ UTF-8 1.8 2.4.1 + 2.0.4.RELEASE diff --git a/kotlin-libraries/pom.xml b/kotlin-libraries/pom.xml index 507e5820d4..3d2c7337b0 100644 --- a/kotlin-libraries/pom.xml +++ b/kotlin-libraries/pom.xml @@ -19,6 +19,14 @@ exposed https://dl.bintray.com/kotlin/exposed + + + false + + kotlinx + bintray + https://dl.bintray.com/kotlin/kotlinx + @@ -112,9 +120,56 @@ 3.3.0 pom + + + + junit + junit + ${junit.version} + test + + + + com.google.guava + guava + 27.1-jre + + + + org.jetbrains.kotlinx + kotlinx-collections-immutable + 0.1 + + + + + io.mockk + mockk + ${mockk.version} + test + + + net.bytebuddy + byte-buddy + 1.8.13 + compile + + + net.bytebuddy + byte-buddy-agent + 1.8.13 + compile + + + org.objenesis + objenesis + 2.6 + compile + + 4.12 1.5.0 4.1.0 3.0.4 @@ -125,6 +180,7 @@ 3.10.0 1.4.197 0.10.4 + 1.9.3 diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/KotlinxImmutablesUnitTest.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/KotlinxImmutablesUnitTest.kt new file mode 100644 index 0000000000..971f2de4c2 --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/KotlinxImmutablesUnitTest.kt @@ -0,0 +1,27 @@ +package com.baeldung.kotlin.immutable + +import junit.framework.Assert.assertEquals +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.immutableListOf +import org.junit.Rule +import org.junit.Test +import org.junit.rules.ExpectedException + +class KotlinxImmutablesUnitTest{ + + + @Rule + @JvmField + var ee : ExpectedException = ExpectedException.none() + + @Test + fun givenKICLList_whenAddTried_checkExceptionThrown(){ + + val list: ImmutableList = immutableListOf("I", "am", "immutable") + + list.add("My new item") + + assertEquals(listOf("I", "am", "immutable"), list) + + } +} \ No newline at end of file diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/ReadOnlyUnitTest.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/ReadOnlyUnitTest.kt new file mode 100644 index 0000000000..62c4a4eb88 --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/kotlin/immutable/ReadOnlyUnitTest.kt @@ -0,0 +1,73 @@ +package com.baeldung.kotlin.immutable + +import com.google.common.collect.ImmutableList +import com.google.common.collect.ImmutableSet +import junit.framework.Assert.assertEquals +import org.junit.Rule +import org.junit.Test +import org.junit.rules.ExpectedException + +class ReadOnlyUnitTest{ + + @Test + fun givenReadOnlyList_whenCastToMutableList_checkNewElementsAdded(){ + + val list: List = listOf("This", "Is", "Totally", "Immutable") + + (list as MutableList)[2] = "Not" + + assertEquals(listOf("This", "Is", "Not", "Immutable"), list) + + } + + @Rule + @JvmField + var ee : ExpectedException = ExpectedException.none() + + @Test + fun givenImmutableList_whenAddTried_checkExceptionThrown(){ + + val list: List = ImmutableList.of("I", "am", "actually", "immutable") + + ee.expect(UnsupportedOperationException::class.java) + + (list as MutableList).add("Oops") + + } + + @Test + fun givenMutableList_whenCopiedAndAddTried_checkExceptionThrown(){ + + val mutableList : List = listOf("I", "Am", "Definitely", "Immutable") + + (mutableList as MutableList)[2] = "100% Not" + + assertEquals(listOf("I", "Am", "100% Not", "Immutable"), mutableList) + + val list: List = ImmutableList.copyOf(mutableList) + + ee.expect(UnsupportedOperationException::class.java) + + (list as MutableList)[2] = "Really?" + + } + + @Test + fun givenImmutableSetBuilder_whenAddTried_checkExceptionThrown(){ + + val mutableList : List = listOf("Hello", "Baeldung") + val set: ImmutableSet = ImmutableSet.builder() + .add("I","am","immutable") + .addAll(mutableList) + .build() + + assertEquals(setOf("Hello", "Baeldung", "I", "am", "immutable"), set) + + ee.expect(UnsupportedOperationException::class.java) + + (set as MutableSet).add("Oops") + + } + + +} \ No newline at end of file diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/AnnotationMockKUnitTest.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/AnnotationMockKUnitTest.kt new file mode 100644 index 0000000000..56cd8b43eb --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/AnnotationMockKUnitTest.kt @@ -0,0 +1,44 @@ +package com.baeldung.mockk + +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.InjectMockKs +import io.mockk.impl.annotations.MockK +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class InjectTestService { + lateinit var service1: TestableService + lateinit var service2: TestableService + + fun invokeService1(): String { + return service1.getDataFromDb("Test Param") + } +} + +class AnnotationMockKUnitTest { + + @MockK + lateinit var service1: TestableService + + @MockK + lateinit var service2: TestableService + + @InjectMockKs + var objectUnderTest = InjectTestService() + + @BeforeEach + fun setUp() = MockKAnnotations.init(this) + + @Test + fun givenServiceMock_whenCallingMockedMethod_thenCorrectlyVerified() { + // given + every { service1.getDataFromDb("Test Param") } returns "No" + // when + val result = objectUnderTest.invokeService1() + // then + assertEquals("No", result) + } + +} \ No newline at end of file diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/BasicMockKUnitTest.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/BasicMockKUnitTest.kt new file mode 100644 index 0000000000..df4c03be09 --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/BasicMockKUnitTest.kt @@ -0,0 +1,92 @@ +package com.baeldung.mockk + +import io.mockk.* +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + + +class BasicMockKUnitTest { + + @Test + fun givenServiceMock_whenCallingMockedMethod_thenCorrectlyVerified() { + // given + val service = mockk() + every { service.getDataFromDb("Expected Param") } returns "Expected Output" + // when + val result = service.getDataFromDb("Expected Param") + // then + verify { service.getDataFromDb("Expected Param") } + assertEquals("Expected Output", result) + } + + @Test + fun givenServiceSpy_whenMockingOnlyOneMethod_thenOtherMethodsShouldBehaveAsOriginalObject() { + // given + val service = spyk() + every { service.getDataFromDb(any()) } returns "Mocked Output" + // when checking mocked method + val firstResult = service.getDataFromDb("Any Param") + // then + assertEquals("Mocked Output", firstResult) + // when checking not mocked method + val secondResult = service.doSomethingElse("Any Param") + // then + assertEquals("I don't want to!", secondResult) + } + + @Test + fun givenRelaxedMock_whenCallingNotMockedMethod_thenReturnDefaultValue() { + // given + val service = mockk(relaxed = true) + // when + val result = service.getDataFromDb("Any Param") + // then + assertEquals("", result) + } + + @Test + fun givenObject_whenMockingIt_thenMockedMethodShouldReturnProperValue() { + // given + val service = TestableService() + mockkObject(service) + // when calling not mocked method + val firstResult = service.getDataFromDb("Any Param") + // then return real response + assertEquals("Value from DB", firstResult) + + // when calling mocked method + every { service.getDataFromDb(any()) } returns "Mocked Output" + val secondResult = service.getDataFromDb("Any Param") + // then return mocked response + assertEquals("Mocked Output", secondResult) + } + + @Test + fun givenMock_whenCapturingParamValue_thenProperValueShouldBeCaptured() { + // given + val service = mockk() + val slot = slot() + every { service.getDataFromDb(capture(slot)) } returns "Expected Output" + // when + service.getDataFromDb("Expected Param") + // then + assertEquals("Expected Param", slot.captured) + } + + @Test + fun givenMock_whenCapturingParamsValues_thenProperValuesShouldBeCaptured() { + // given + val service = mockk() + val list = mutableListOf() + every { service.getDataFromDb(capture(list)) } returns "Expected Output" + // when + service.getDataFromDb("Expected Param 1") + service.getDataFromDb("Expected Param 2") + // then + assertEquals(2, list.size) + assertEquals("Expected Param 1", list[0]) + assertEquals("Expected Param 2", list[1]) + } + + +} \ No newline at end of file diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/HierarchicalMockKUnitTest.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/HierarchicalMockKUnitTest.kt new file mode 100644 index 0000000000..e9ef133663 --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/HierarchicalMockKUnitTest.kt @@ -0,0 +1,33 @@ +package com.baeldung.mockk + +import io.mockk.* +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class Foo { + lateinit var name: String + lateinit var bar: Bar +} + +class Bar { + lateinit var nickname: String +} + +class HierarchicalMockKUnitTest { + + @Test + fun givenHierarchicalClass_whenMockingIt_thenReturnProperValue() { + // given + val foo = mockk { + every { name } returns "Karol" + every { bar } returns mockk { + every { nickname } returns "Tomato" + } + } + // when + val result = foo.bar.nickname + // then + assertEquals("Tomato", result) + } + +} \ No newline at end of file diff --git a/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/TestableService.kt b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/TestableService.kt new file mode 100644 index 0000000000..d6f57e5fb0 --- /dev/null +++ b/kotlin-libraries/src/test/kotlin/com/baeldung/mockk/TestableService.kt @@ -0,0 +1,12 @@ +package com.baeldung.mockk + +class TestableService { + fun getDataFromDb(testParameter: String): String { + // query database and return matching value + return "Value from DB" + } + + fun doSomethingElse(testParameter: String): String { + return "I don't want to!" + } +} \ No newline at end of file diff --git a/libraries-data/pom.xml b/libraries-data/pom.xml index daf6c8b500..85be66c067 100644 --- a/libraries-data/pom.xml +++ b/libraries-data/pom.xml @@ -434,7 +434,6 @@ 4.0.1 1.4.196 16.5.1 - 4.12 3.7.0 5.0 1.0.0 diff --git a/libraries-security/pom.xml b/libraries-security/pom.xml index ba51227ce0..9f125361ba 100644 --- a/libraries-security/pom.xml +++ b/libraries-security/pom.xml @@ -51,7 +51,6 @@ - 4.12 2.0.4.RELEASE 5.6.0 2.3.3.RELEASE diff --git a/libraries-server/pom.xml b/libraries-server/pom.xml index b30b6137a1..a6ead8fb31 100644 --- a/libraries-server/pom.xml +++ b/libraries-server/pom.xml @@ -105,7 +105,6 @@ 9.4.8.v20171121 4.1.20.Final 4.1 - 4.12 8.5.24 4.3.1 1.2.0 diff --git a/libraries/README.md b/libraries/README.md index 378317778e..57f22631f1 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -66,6 +66,7 @@ - [Implementing a FTP-Client in Java](http://www.baeldung.com/java-ftp-client) - [Introduction to Functional Java](https://www.baeldung.com/java-functional-library) - [Intro to Derive4J](https://www.baeldung.com/derive4j) +- [A Guide to the Reflections Library](https://www.baeldung.com/reflections-library) The libraries module contains examples related to small libraries that are relatively easy to use and does not require any separate module of its own. diff --git a/libraries/pom.xml b/libraries/pom.xml index d067525315..7823732224 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -223,6 +223,12 @@ serenity-spring ${serenity.version} test + + + org.springframework + spring-test + + net.serenity-bdd @@ -318,6 +324,12 @@ pact-jvm-consumer-junit_2.11 ${pact.version} test + + + org.codehaus.groovy + groovy-all + + org.codehaus.groovy @@ -675,6 +687,17 @@ ${mockftpserver.version} test + + org.asciidoctor + asciidoctor-maven-plugin + 1.5.7.1 + + + + org.reflections + reflections + ${reflections.version} + @@ -687,10 +710,6 @@ bintray http://dl.bintray.com/cuba-platform/main - - Apache Staging - https://repository.apache.org/content/groups/staging - nm-repo Numerical Method's Maven Repository @@ -734,7 +753,7 @@ JDO ${basedir}/datanucleus.properties ${basedir}/log4j.properties - true + false false @@ -826,7 +845,6 @@ 1.9.0 1.9.27 1.1.0 - 4.12 0.10 3.5.0 3.0.0 @@ -897,6 +915,8 @@ 1.1.0 2.7.1 3.6 + 0.9.11 + diff --git a/libraries/src/main/java/com/baeldung/derive4j/lazy/LazyRequest.java b/libraries/src/main/java/com/baeldung/derive4j/lazy/LazyRequest.java index 9f53f3d25b..bee947df12 100644 --- a/libraries/src/main/java/com/baeldung/derive4j/lazy/LazyRequest.java +++ b/libraries/src/main/java/com/baeldung/derive4j/lazy/LazyRequest.java @@ -6,7 +6,7 @@ import org.derive4j.Make; @Data(value = @Derive( inClass = "{ClassName}Impl", - make = {Make.lazyConstructor, Make.constructors} + make = {Make.lazyConstructor, Make.constructors, Make.getters} )) public interface LazyRequest { interface Cases{ diff --git a/libraries/src/main/java/com/baeldung/reflections/ReflectionsApp.java b/libraries/src/main/java/com/baeldung/reflections/ReflectionsApp.java new file mode 100644 index 0000000000..30da8ea837 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/reflections/ReflectionsApp.java @@ -0,0 +1,71 @@ +package com.baeldung.reflections; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Date; +import java.util.Set; +import java.util.regex.Pattern; + +import org.reflections.Reflections; +import org.reflections.scanners.MethodAnnotationsScanner; +import org.reflections.scanners.MethodParameterScanner; +import org.reflections.scanners.ResourcesScanner; +import org.reflections.scanners.Scanner; +import org.reflections.scanners.SubTypesScanner; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; + +public class ReflectionsApp { + + public Set> getReflectionsSubTypes() { + Reflections reflections = new Reflections("org.reflections"); + Set> scannersSet = reflections.getSubTypesOf(Scanner.class); + return scannersSet; + } + + public Set> getJDKFunctinalInterfaces() { + Reflections reflections = new Reflections("java.util.function"); + Set> typesSet = reflections.getTypesAnnotatedWith(FunctionalInterface.class); + return typesSet; + } + + public Set getDateDeprecatedMethods() { + Reflections reflections = new Reflections(java.util.Date.class, new MethodAnnotationsScanner()); + Set deprecatedMethodsSet = reflections.getMethodsAnnotatedWith(Deprecated.class); + return deprecatedMethodsSet; + } + + @SuppressWarnings("rawtypes") + public Set getDateDeprecatedConstructors() { + Reflections reflections = new Reflections(java.util.Date.class, new MethodAnnotationsScanner()); + Set constructorsSet = reflections.getConstructorsAnnotatedWith(Deprecated.class); + return constructorsSet; + } + + public Set getMethodsWithDateParam() { + Reflections reflections = new Reflections(java.text.SimpleDateFormat.class, new MethodParameterScanner()); + Set methodsSet = reflections.getMethodsMatchParams(Date.class); + return methodsSet; + } + + public Set getMethodsWithVoidReturn() { + Reflections reflections = new Reflections(java.text.SimpleDateFormat.class, new MethodParameterScanner()); + Set methodsSet = reflections.getMethodsReturn(void.class); + return methodsSet; + } + + public Set getPomXmlPaths() { + Reflections reflections = new Reflections(new ResourcesScanner()); + Set resourcesSet = reflections.getResources(Pattern.compile(".*pom\\.xml")); + return resourcesSet; + } + + public Set> getReflectionsSubTypesUsingBuilder() { + Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage("org.reflections")) + .setScanners(new SubTypesScanner())); + + Set> scannersSet = reflections.getSubTypesOf(Scanner.class); + return scannersSet; + } + +} diff --git a/libraries/src/test/java/com/baeldung/google/sheets/GoogleSheetsIntegrationTest.java b/libraries/src/test/java/com/baeldung/google/sheets/GoogleSheetsLiveTest.java similarity index 99% rename from libraries/src/test/java/com/baeldung/google/sheets/GoogleSheetsIntegrationTest.java rename to libraries/src/test/java/com/baeldung/google/sheets/GoogleSheetsLiveTest.java index ba1861937b..358b3390f9 100644 --- a/libraries/src/test/java/com/baeldung/google/sheets/GoogleSheetsIntegrationTest.java +++ b/libraries/src/test/java/com/baeldung/google/sheets/GoogleSheetsLiveTest.java @@ -26,7 +26,7 @@ import com.google.api.services.sheets.v4.model.ValueRange; import static org.assertj.core.api.Assertions.*; -public class GoogleSheetsIntegrationTest { +public class GoogleSheetsLiveTest { private static Sheets sheetsService; diff --git a/libraries/src/test/java/com/baeldung/reflections/ReflectionsUnitTest.java b/libraries/src/test/java/com/baeldung/reflections/ReflectionsUnitTest.java new file mode 100644 index 0000000000..9a3ef0747b --- /dev/null +++ b/libraries/src/test/java/com/baeldung/reflections/ReflectionsUnitTest.java @@ -0,0 +1,50 @@ +package com.baeldung.reflections; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +import org.junit.jupiter.api.Test; + +public class ReflectionsUnitTest { + + @Test + public void givenTypeThenGetAllSubTypes() { + ReflectionsApp reflectionsApp = new ReflectionsApp(); + assertFalse(reflectionsApp.getReflectionsSubTypes() + .isEmpty()); + } + + @Test + public void givenTypeAndUsingBuilderThenGetAllSubTypes() { + ReflectionsApp reflectionsApp = new ReflectionsApp(); + assertFalse(reflectionsApp.getReflectionsSubTypesUsingBuilder() + .isEmpty()); + } + + @Test + public void givenAnnotationThenGetAllAnnotatedMethods() { + ReflectionsApp reflectionsApp = new ReflectionsApp(); + assertFalse(reflectionsApp.getDateDeprecatedMethods() + .isEmpty()); + } + + @Test + public void givenAnnotationThenGetAllAnnotatedConstructors() { + ReflectionsApp reflectionsApp = new ReflectionsApp(); + assertFalse(reflectionsApp.getDateDeprecatedConstructors() + .isEmpty()); + } + + @Test + public void givenParamTypeThenGetAllMethods() { + ReflectionsApp reflectionsApp = new ReflectionsApp(); + assertFalse(reflectionsApp.getMethodsWithDateParam() + .isEmpty()); + } + + @Test + public void givenReturnTypeThenGetAllMethods() { + ReflectionsApp reflectionsApp = new ReflectionsApp(); + assertFalse(reflectionsApp.getMethodsWithVoidReturn() + .isEmpty()); + } +} diff --git a/libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java b/libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java index 69af042427..df7fea58f8 100644 --- a/libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java +++ b/libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java @@ -12,9 +12,10 @@ import static org.junit.Assert.*; public class SmooksIntegrationTest { - private static final String EDIFACT_MESSAGE = "UNA:+.? '\r\n" + "UNH+771+IN_PROGRESS+2018-01-14'\r\n" + "CTA+CompanyX+1234567'\r\n" + "LIN+1+PX1234+9.99'\r\n" + "LIN+2+RX990+120.32'\r\n"; - private static final String EMAIL_MESSAGE = "Hi,\r\n" + "Order number #771 created on 2018-01-14 is currently in IN_PROGRESS status.\r\n" + "Consider contact supplier \"CompanyX\" with phone number: \"1234567\".\r\n" + "Order items:\r\n" - + "1 X PX1234 (total price 9.99)\r\n" + "2 X RX990 (total price 240.64)\r\n"; + private static final String EDIFACT_MESSAGE = "UNA:+.? '" + System.lineSeparator() + "UNH+771+IN_PROGRESS+2018-01-14'" + System.lineSeparator() + "CTA+CompanyX+1234567'" + System.lineSeparator() + "LIN+1+PX1234+9.99'" + System.lineSeparator() + + "LIN+2+RX990+120.32'" + System.lineSeparator(); + private static final String EMAIL_MESSAGE = "Hi," + System.lineSeparator() + "Order number #771 created on 2018-01-14 is currently in IN_PROGRESS status." + System.lineSeparator() + "Consider contact supplier \"CompanyX\" with phone number: \"1234567\"." + + System.lineSeparator() + "Order items:" + System.lineSeparator() + "1 X PX1234 (total price 9.99)" + System.lineSeparator() + "2 X RX990 (total price 240.64)" + System.lineSeparator(); @Test public void givenOrderXML_whenConvert_thenPOJOsConstructedCorrectly() throws Exception { @@ -37,7 +38,10 @@ public class SmooksIntegrationTest { assertThat(validationResult.getErrors(), hasSize(1)); // 1234567 didn't match ^[0-9\\-\\+]{9,15}$ - assertThat(validationResult.getErrors().get(0).getFailRuleResult().getRuleName(), is("supplierPhone")); + assertThat(validationResult.getErrors() + .get(0) + .getFailRuleResult() + .getRuleName(), is("supplierPhone")); } @Test diff --git a/logging-modules/log4j/README.md b/logging-modules/log4j/README.md index 9f4184ccba..a7a7ea9643 100644 --- a/logging-modules/log4j/README.md +++ b/logging-modules/log4j/README.md @@ -1,7 +1,5 @@ ### Relevant Articles: - [Introduction to Java Logging](http://www.baeldung.com/java-logging-intro) - [Introduction to SLF4J](http://www.baeldung.com/slf4j-with-log4j2-logback) -- [Generate equals() and hashCode() with Eclipse](http://www.baeldung.com/java-eclipse-equals-and-hashcode) -- [Introduction to SLF4J](http://www.baeldung.com/slf4j-with-log4j2-logback) - [A Guide to Rolling File Appenders](http://www.baeldung.com/java-logging-rolling-file-appenders) - [Logging Exceptions Using SLF4J](https://www.baeldung.com/slf4j-log-exceptions) diff --git a/logging-modules/pom.xml b/logging-modules/pom.xml new file mode 100644 index 0000000000..a303e50ff1 --- /dev/null +++ b/logging-modules/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + logging-modules + logging-modules + pom + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + .. + + + + log4j + log4j2 + logback + log-mdc + + + diff --git a/lombok-custom/pom.xml b/lombok-custom/pom.xml index f016405fd6..cfbe629945 100644 --- a/lombok-custom/pom.xml +++ b/lombok-custom/pom.xml @@ -5,6 +5,7 @@ 4.0.0 lombok-custom + lombok-custom 0.1-SNAPSHOT diff --git a/lombok/README.md b/lombok/README.md index e3d08d4e26..4ff7ca7921 100644 --- a/lombok/README.md +++ b/lombok/README.md @@ -6,4 +6,5 @@ - [Lombok Builder with Default Value](https://www.baeldung.com/lombok-builder-default-value) - [Lombok Builder with Custom Setter](https://www.baeldung.com/lombok-builder-custom-setter) - [Setting up Lombok with Eclipse and Intellij](https://www.baeldung.com/lombok-ide) +- [Using the @Singular Annotation with Lombok Builders](https://www.baeldung.com/lombok-builder-singular) diff --git a/lombok/src/main/java/com/baeldung/lombok/builder/singular/Person.java b/lombok/src/main/java/com/baeldung/lombok/builder/singular/Person.java new file mode 100644 index 0000000000..d7d95feb66 --- /dev/null +++ b/lombok/src/main/java/com/baeldung/lombok/builder/singular/Person.java @@ -0,0 +1,25 @@ +package com.baeldung.lombok.builder.singular; + +import lombok.Builder; +import lombok.Getter; +import lombok.Singular; + +import java.time.LocalDate; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Getter +@Builder +public class Person { + + private final String givenName; + private final String additionalName; + private final String familyName; + + private final List tags; + @Singular private final List interests; + @Singular private final Set skills; + @Singular private final Map awards; +} diff --git a/lombok/src/main/java/com/baeldung/lombok/builder/singular/Sea.java b/lombok/src/main/java/com/baeldung/lombok/builder/singular/Sea.java new file mode 100644 index 0000000000..8cf38e5f1a --- /dev/null +++ b/lombok/src/main/java/com/baeldung/lombok/builder/singular/Sea.java @@ -0,0 +1,14 @@ +package com.baeldung.lombok.builder.singular; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; +import lombok.Singular; + +@Getter +@Builder +public class Sea { + + @Singular private final List grasses; + @Singular("oneFish") private final List fish; +} diff --git a/lombok/src/test/java/com/baeldung/lombok/builder/singular/BuilderWithSingularSupportForCollectionsUnitTest.java b/lombok/src/test/java/com/baeldung/lombok/builder/singular/BuilderWithSingularSupportForCollectionsUnitTest.java new file mode 100644 index 0000000000..41d5b19df7 --- /dev/null +++ b/lombok/src/test/java/com/baeldung/lombok/builder/singular/BuilderWithSingularSupportForCollectionsUnitTest.java @@ -0,0 +1,192 @@ +package com.baeldung.lombok.builder.singular; + +import org.junit.Test; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class BuilderWithSingularSupportForCollectionsUnitTest { + + @Test + public void canAddMultipleElementsAsNewCollection() throws Exception { + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .tags(Arrays.asList("fictional", "incidental")) + .build(); + + assertThat(person.getTags(), containsInAnyOrder("fictional", "incidental")); + } + + @Test + public void canUpdateCollectionAfterBuildIfMutableCollectionPassedToBuilder() throws Exception { + + List tags = new ArrayList(); + tags.add("fictional"); + tags.add("incidental"); + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .tags(tags) + .build(); + person.getTags() + .clear(); + person.getTags() + .add("non-fictional"); + person.getTags() + .add("important"); + + assertThat(person.getTags(), containsInAnyOrder("non-fictional", "important")); + } + + @Test(expected = UnsupportedOperationException.class) + public void cannotUpdateCollectionAfterBuildIfImmutableCollectionPassedToBuilder() throws Exception { + List tags = Arrays.asList("fictional", "incidental"); + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .tags(tags) + .build(); + person.getTags() + .clear(); + } + + @Test + public void canAssignToSingularAnnotatedCollectionOneByOne() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .interest("history") + .interest("sport") + .build(); + + assertThat(person.getInterests(), containsInAnyOrder("sport", "history")); + } + + @Test(expected = UnsupportedOperationException.class) + public void singularAnnotatedBuilderCreatesImmutableCollection() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .interest("history") + .interest("sport") + .build(); + person.getInterests() + .clear(); + } + + @Test + public void unpopulatedListsCreatedAsNullIfNotSingularButEmptyArrayIfSingular() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .build(); + assertThat(person.getInterests(), hasSize(0)); + assertThat(person.getSkills(), hasSize(0)); + assertThat(person.getAwards() + .keySet(), hasSize(0)); + assertThat(person.getTags(), is(nullValue())); + } + + @Test + public void singularSupportsSetsToo() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .skill("singing") + .skill("dancing") + .build(); + assertThat(person.getSkills(), contains("singing", "dancing")); + } + + @Test + public void singularSetsAreLenientWithDuplicates() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .interest("singing") + .interest("singing") + .skill("singing") + .skill("singing") + .build(); + assertThat(person.getInterests(), contains("singing", "singing")); + assertThat(person.getSkills(), contains("singing")); + } + + @Test + public void singularSupportsMapsToo() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .award("Singer of the Year", LocalDate.now() + .minusYears(5)) + .award("Best Dancer", LocalDate.now() + .minusYears(2)) + .build(); + assertThat(person.getAwards() + .keySet(), contains("Singer of the Year", "Best Dancer")); + assertThat(person.getAwards() + .get("Best Dancer"), + is(LocalDate.now() + .minusYears(2))); + } + + @Test + public void singularIsLenientWithMapKeys() throws Exception { + + Person person = Person.builder() + .givenName("Aaron") + .additionalName("A") + .familyName("Aardvark") + .award("Best Dancer", LocalDate.now() + .minusYears(5)) + .award("Best Dancer", LocalDate.now() + .minusYears(4)) + .award("Best Dancer", LocalDate.now() + .minusYears(3)) + .award("Best Dancer", LocalDate.now() + .minusYears(2)) + .award("Best Dancer", LocalDate.now() + .minusYears(1)) + .build(); + assertThat(person.getAwards() + .keySet(), hasSize(1)); + assertThat(person.getAwards() + .get("Best Dancer"), + is(LocalDate.now() + .minusYears(1))); + } + + @Test + public void wordsWithNonStandardPlurals() throws Exception { + Sea sea = Sea.builder() + .grass("Dulse") + .grass("Kelp") + .oneFish("Cod") + .oneFish("Mackerel") + .build(); + assertThat(sea.getGrasses(), contains("Dulse", "Kelp")); + assertThat(sea.getFish(), contains("Cod", "Mackerel")); + } + +} diff --git a/maven/.gitignore b/maven/.gitignore index f843ae9109..bae0b0d7ce 100644 --- a/maven/.gitignore +++ b/maven/.gitignore @@ -1 +1,2 @@ -/output-resources \ No newline at end of file +/output-resources +/.idea/ diff --git a/maven/README.md b/maven/README.md index 1c0e50f95a..ca648ec203 100644 --- a/maven/README.md +++ b/maven/README.md @@ -14,3 +14,5 @@ - [Apache Maven Tutorial](https://www.baeldung.com/maven) - [Use the Latest Version of a Dependency in Maven](https://www.baeldung.com/maven-dependency-latest-version) - [Multi-Module Project with Maven](https://www.baeldung.com/maven-multi-module) +- [Maven Enforcer Plugin](https://www.baeldung.com/maven-enforcer-plugin) +- [Eclipse Error: web.xml is missing and failOnMissingWebXml is set to true](https://www.baeldung.com/eclipse-error-web-xml-missing) diff --git a/maven/compiler-plugin-java-9/pom.xml b/maven/compiler-plugin-java-9/pom.xml new file mode 100644 index 0000000000..5303cee82e --- /dev/null +++ b/maven/compiler-plugin-java-9/pom.xml @@ -0,0 +1,22 @@ + + 4.0.0 + com.baeldung + compiler-plugin-java-9 + 0.0.1-SNAPSHOT + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 9 + 9 + + + + + \ No newline at end of file diff --git a/maven/compiler-plugin-java-9/src/main/java/com/baeldung/maven/java9/MavenCompilerPlugin.java b/maven/compiler-plugin-java-9/src/main/java/com/baeldung/maven/java9/MavenCompilerPlugin.java new file mode 100644 index 0000000000..b460d6e38c --- /dev/null +++ b/maven/compiler-plugin-java-9/src/main/java/com/baeldung/maven/java9/MavenCompilerPlugin.java @@ -0,0 +1,9 @@ +package com.baeldung.maven.java9; + +import static javax.xml.XMLConstants.XML_NS_PREFIX; + +public class MavenCompilerPlugin { + public static void main(String[] args) { + System.out.println("The XML namespace prefix is: " + XML_NS_PREFIX); + } +} diff --git a/maven/compiler-plugin-java-9/src/main/java/module-info.java b/maven/compiler-plugin-java-9/src/main/java/module-info.java new file mode 100644 index 0000000000..afc1d45e71 --- /dev/null +++ b/maven/compiler-plugin-java-9/src/main/java/module-info.java @@ -0,0 +1,3 @@ +module com.baeldung.maven.java9 { + requires java.xml; +} \ No newline at end of file diff --git a/maven/custom-rule/pom.xml b/maven/custom-rule/pom.xml new file mode 100644 index 0000000000..25a3489fb9 --- /dev/null +++ b/maven/custom-rule/pom.xml @@ -0,0 +1,70 @@ + + + + maven + com.baeldung + 0.0.1-SNAPSHOT + + 4.0.0 + custom-rule + custom-rule + + + 3.0.0-M2 + 2.0.9 + + + + + + + org.apache.maven.enforcer + enforcer-api + ${api.version} + + + org.apache.maven + maven-project + ${maven.version} + + + org.apache.maven + maven-core + ${maven.version} + + + org.apache.maven + maven-artifact + ${maven.version} + + + org.apache.maven + maven-plugin-api + ${maven.version} + + + org.codehaus.plexus + plexus-container-default + 1.0-alpha-9 + + + + + + + maven-verifier-plugin + ${maven.verifier.version} + + ../input-resources/verifications.xml + false + + + + + + + + + \ No newline at end of file diff --git a/maven/custom-rule/src/main/java/com/baeldung/enforcer/MyCustomRule.java b/maven/custom-rule/src/main/java/com/baeldung/enforcer/MyCustomRule.java new file mode 100644 index 0000000000..9b72f40bf1 --- /dev/null +++ b/maven/custom-rule/src/main/java/com/baeldung/enforcer/MyCustomRule.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 PloyRef + * Created by Seun Matt + * on 19 - 2 - 2019 + */ + +package com.baeldung.enforcer; + +import org.apache.maven.enforcer.rule.api.EnforcerRule; +import org.apache.maven.enforcer.rule.api.EnforcerRuleException; +import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; + +public class MyCustomRule implements EnforcerRule { + + public void execute(EnforcerRuleHelper enforcerRuleHelper) throws EnforcerRuleException { + + try { + + String groupId = (String) enforcerRuleHelper.evaluate("${project.groupId}"); + + if (groupId == null || !groupId.startsWith("org.baeldung")) { + throw new EnforcerRuleException("Project group id does not start with org.baeldung"); + } + + } + catch (ExpressionEvaluationException ex ) { + throw new EnforcerRuleException( "Unable to lookup an expression " + ex.getLocalizedMessage(), ex ); + } + } + + public boolean isCacheable() { + return false; + } + + public boolean isResultValid(EnforcerRule enforcerRule) { + return false; + } + + public String getCacheId() { + return null; + } +} diff --git a/maven/maven-enforcer/pom.xml b/maven/maven-enforcer/pom.xml new file mode 100644 index 0000000000..9826beb0d9 --- /dev/null +++ b/maven/maven-enforcer/pom.xml @@ -0,0 +1,75 @@ + + + + maven + com.baeldung + 0.0.1-SNAPSHOT + + 4.0.0 + maven-enforcer + maven-enforcer + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0-M2 + + + + + + + + + + enforce + + enforce + + + + + + 3.0 + Invalid Maven version. It should, at least, be 3.0 + + + 1.8 + + + ui + WARN + + + cook + WARN + + + local,base + Missing active profiles + WARN + + + + + + + + + + maven-verifier-plugin + ${maven.verifier.version} + + ../input-resources/verifications.xml + false + + + + + + + \ No newline at end of file diff --git a/maven/maven-war-plugin/pom.xml b/maven/maven-war-plugin/pom.xml new file mode 100644 index 0000000000..5169a21e78 --- /dev/null +++ b/maven/maven-war-plugin/pom.xml @@ -0,0 +1,29 @@ + + 4.0.0 + com.baeldung + maven-war-plugin-property + 0.0.1-SNAPSHOT + war + maven-war-plugin-property + + + + false + + + + + + maven-war-plugin + + 3.1.0 + + + false + + + + + \ No newline at end of file diff --git a/maven/pom.xml b/maven/pom.xml index 01fd28db74..942bf683e2 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -4,8 +4,12 @@ com.baeldung maven 0.0.1-SNAPSHOT - maven - war + + custom-rule + maven-enforcer + + maven + pom diff --git a/noexception/README.md b/noexception/README.md deleted file mode 100644 index 9dd4c11190..0000000000 --- a/noexception/README.md +++ /dev/null @@ -1,2 +0,0 @@ -### Relevant Articles: -- [Introduction to NoException](http://www.baeldung.com/introduction-to-noexception) diff --git a/noexception/pom.xml b/noexception/pom.xml deleted file mode 100644 index f632f1e3a9..0000000000 --- a/noexception/pom.xml +++ /dev/null @@ -1,27 +0,0 @@ - - 4.0.0 - com.baeldung - noexception - 1.0 - noexception - - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - - - - - com.machinezoo.noexception - noexception - ${noexception.version} - - - - - 1.1.0 - - - diff --git a/noexception/src/main/java/com/baeldung/noexception/CustomExceptionHandler.java b/noexception/src/main/java/com/baeldung/noexception/CustomExceptionHandler.java deleted file mode 100644 index 59e13efaa0..0000000000 --- a/noexception/src/main/java/com/baeldung/noexception/CustomExceptionHandler.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.noexception; - -import com.machinezoo.noexception.ExceptionHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CustomExceptionHandler extends ExceptionHandler { - - private Logger logger = LoggerFactory.getLogger(CustomExceptionHandler.class); - - @Override - public boolean handle(Throwable throwable) { - - if (throwable.getClass() - .isAssignableFrom(RuntimeException.class) - || throwable.getClass() - .isAssignableFrom(Error.class)) { - return false; - } else { - logger.error("Caught Exception ", throwable); - return true; - } - } -} diff --git a/noexception/src/test/java/com/baeldung/noexception/NoExceptionUnitTest.java b/noexception/src/test/java/com/baeldung/noexception/NoExceptionUnitTest.java deleted file mode 100644 index 690ea43520..0000000000 --- a/noexception/src/test/java/com/baeldung/noexception/NoExceptionUnitTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.baeldung.noexception; - -import com.machinezoo.noexception.Exceptions; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NoExceptionUnitTest { - - private static Logger logger = LoggerFactory.getLogger(NoExceptionUnitTest.class); - - @Test - public void whenStdExceptionHandling_thenCatchAndLog() { - try { - System.out.println("Result is " + Integer.parseInt("foobar")); - } catch (Throwable exception) { - logger.error("Caught exception:", exception); - } - } - - @Test - public void whenDefaultNoException_thenCatchAndLog() { - - Exceptions.log().run(() -> System.out.println("Result is " + Integer.parseInt("foobar"))); - } - - @Test - public void givenLogger_whenDefaultNoException_thenCatchAndLogWithClassName() { - System.out.println("Result is " + Exceptions.log(logger).get(() -> +Integer.parseInt("foobar")).orElse(-1)); - } - - @Test - public void givenLoggerAndMessage_whenDefaultNoException_thenCatchAndLogWithClassNameAndMessage() { - System.out.println("Result is " + Exceptions.log(logger, "Something went wrong:").get(() -> +Integer.parseInt("foobar")).orElse(-1)); - } - - @Test - public void givenDefaultValue_whenDefaultNoException_thenCatchAndLogPrintDefault() { - System.out.println("Result is " + Exceptions.log(logger, "Something went wrong:").get(() -> +Integer.parseInt("foobar")).orElse(-1)); - } - - @Test(expected = Error.class) - public void givenCustomHandler_whenError_thenRethrowError() { - CustomExceptionHandler customExceptionHandler = new CustomExceptionHandler(); - customExceptionHandler.run(() -> throwError()); - } - - @Test - public void givenCustomHandler_whenException_thenCatchAndLog() { - CustomExceptionHandler customExceptionHandler = new CustomExceptionHandler(); - customExceptionHandler.run(() -> throwException()); - } - - private static void throwError() { - throw new Error("This is very bad."); - } - - private static void throwException() { - String testString = "foo"; - testString.charAt(5); - } - -} diff --git a/osgi/osgi-intro-sample-activator/pom.xml b/osgi/osgi-intro-sample-activator/pom.xml index 95ac1fc0fb..2bc1c20eed 100644 --- a/osgi/osgi-intro-sample-activator/pom.xml +++ b/osgi/osgi-intro-sample-activator/pom.xml @@ -3,6 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 osgi-intro-sample-activator + osgi-intro-sample-activator bundle diff --git a/osgi/osgi-intro-sample-client/pom.xml b/osgi/osgi-intro-sample-client/pom.xml index 7f5faedb30..a630625ed2 100644 --- a/osgi/osgi-intro-sample-client/pom.xml +++ b/osgi/osgi-intro-sample-client/pom.xml @@ -5,6 +5,7 @@ 4.0.0 osgi-intro-sample-client + osgi-intro-sample-client bundle diff --git a/osgi/osgi-intro-sample-service/pom.xml b/osgi/osgi-intro-sample-service/pom.xml index 8f81645ad4..4f0b108837 100644 --- a/osgi/osgi-intro-sample-service/pom.xml +++ b/osgi/osgi-intro-sample-service/pom.xml @@ -3,6 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 osgi-intro-sample-service + osgi-intro-sample-service bundle diff --git a/parent-boot-1/pom.xml b/parent-boot-1/pom.xml index 53f91f975d..1054038623 100644 --- a/parent-boot-1/pom.xml +++ b/parent-boot-1/pom.xml @@ -55,7 +55,7 @@ 3.1.0 - 1.5.16.RELEASE + 1.5.19.RELEASE diff --git a/parent-boot-2/pom.xml b/parent-boot-2/pom.xml index 280d226e95..4b81e27333 100644 --- a/parent-boot-2/pom.xml +++ b/parent-boot-2/pom.xml @@ -77,9 +77,7 @@ 3.1.0 - 1.0.11.RELEASE - 2.1.1.RELEASE + 1.0.21.RELEASE + 2.1.3.RELEASE - - diff --git a/parent-spring-4/pom.xml b/parent-spring-4/pom.xml index 6cbcf3000e..d7eea44989 100644 --- a/parent-spring-4/pom.xml +++ b/parent-spring-4/pom.xml @@ -29,7 +29,7 @@ - 4.3.20.RELEASE + 4.3.22.RELEASE 5.0.2 diff --git a/parent-spring-5/pom.xml b/parent-spring-5/pom.xml index 650305b7e2..3178682d34 100644 --- a/parent-spring-5/pom.xml +++ b/parent-spring-5/pom.xml @@ -29,11 +29,10 @@ - 5.1.2.RELEASE + 5.1.4.RELEASE 5.0.2 - 2.9.6 2.9.6 - 5.1.2.RELEASE + 5.1.4.RELEASE \ No newline at end of file diff --git a/patterns/README.md b/patterns/README.md index 9a15cdff02..1c9a59ea21 100644 --- a/patterns/README.md +++ b/patterns/README.md @@ -1,3 +1,4 @@ ### Relevant Articles: - [A Guide to the Front Controller Pattern in Java](http://www.baeldung.com/java-front-controller-pattern) - [Introduction to Intercepting Filter Pattern in Java](http://www.baeldung.com/intercepting-filter-pattern-in-java) +- [Introduction to the Null Object Pattern](https://www.baeldung.com/java-null-object-pattern) diff --git a/patterns/design-patterns-2/pom.xml b/patterns/design-patterns-2/pom.xml new file mode 100644 index 0000000000..5c3e70b046 --- /dev/null +++ b/patterns/design-patterns-2/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + design-patterns-2 + 1.0 + design-patterns-2 + jar + + + com.baeldung + patterns + 1.0.0-SNAPSHOT + .. + + + + + org.jetbrains + annotations + ${intellij.annotations.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + + UTF-8 + 1.8 + 1.8 + 16.0.2 + 3.5 + + diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Button.java b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Button.java new file mode 100644 index 0000000000..0507d27872 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Button.java @@ -0,0 +1,13 @@ +package com.baeldung.mediator; + +public class Button { + private Mediator mediator; + + public void setMediator(Mediator mediator) { + this.mediator = mediator; + } + + public void press() { + this.mediator.press(); + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Fan.java b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Fan.java new file mode 100644 index 0000000000..b7862f42d5 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Fan.java @@ -0,0 +1,24 @@ +package com.baeldung.mediator; + +public class Fan { + private Mediator mediator; + private boolean isOn = false; + + public void setMediator(Mediator mediator) { + this.mediator = mediator; + } + + public boolean isOn() { + return isOn; + } + + public void turnOn() { + this.mediator.start(); + isOn = true; + } + + public void turnOff() { + isOn = false; + this.mediator.stop(); + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Mediator.java b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Mediator.java new file mode 100644 index 0000000000..08cd023748 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/Mediator.java @@ -0,0 +1,37 @@ +package com.baeldung.mediator; + +public class Mediator { + private Button button; + private Fan fan; + private PowerSupplier powerSupplier; + + public void setButton(Button button) { + this.button = button; + this.button.setMediator(this); + } + + public void setFan(Fan fan) { + this.fan = fan; + this.fan.setMediator(this); + } + + public void setPowerSupplier(PowerSupplier powerSupplier) { + this.powerSupplier = powerSupplier; + } + + public void press() { + if (fan.isOn()) { + fan.turnOff(); + } else { + fan.turnOn(); + } + } + + public void start() { + powerSupplier.turnOn(); + } + + public void stop() { + powerSupplier.turnOff(); + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/PowerSupplier.java b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/PowerSupplier.java new file mode 100644 index 0000000000..b4a05816c7 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/mediator/PowerSupplier.java @@ -0,0 +1,11 @@ +package com.baeldung.mediator; + +public class PowerSupplier { + public void turnOn() { + // implementation + } + + public void turnOff() { + // implementation + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/JmsRouter.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/JmsRouter.java new file mode 100644 index 0000000000..7d8215fead --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/JmsRouter.java @@ -0,0 +1,10 @@ +package com.baeldung.nullobject; + +public class JmsRouter implements Router { + + @Override + public void route(Message msg) { + System.out.println("Routing to a JMS queue. Msg: " + msg); + } + +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/Message.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/Message.java new file mode 100644 index 0000000000..9086b6d92d --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/Message.java @@ -0,0 +1,24 @@ +package com.baeldung.nullobject; + +public class Message { + + private String body; + + private String priority; + + public Message(String body, String priority) { + this.body = body; + this.priority = priority; + } + + public String getPriority() { + return priority; + } + + @Override + public String toString() { + return "{body='" + body + '\'' + + ", priority='" + priority + '\'' + + '}'; + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/NullRouter.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/NullRouter.java new file mode 100644 index 0000000000..a0065a321d --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/NullRouter.java @@ -0,0 +1,10 @@ +package com.baeldung.nullobject; + +public class NullRouter implements Router { + + @Override + public void route(Message msg) { + // do nothing + } + +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/Router.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/Router.java new file mode 100644 index 0000000000..3e67de9558 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/Router.java @@ -0,0 +1,7 @@ +package com.baeldung.nullobject; + +public interface Router { + + void route(Message msg); + +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/RouterFactory.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/RouterFactory.java new file mode 100644 index 0000000000..ba80834865 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/RouterFactory.java @@ -0,0 +1,23 @@ +package com.baeldung.nullobject; + +public class RouterFactory { + + public static Router getRouterForMessage(Message msg) { + + if (msg.getPriority() == null) { + return new NullRouter(); + } + + switch (msg.getPriority()) { + case "high": + return new SmsRouter(); + + case "medium": + return new JmsRouter(); + + default: + return new NullRouter(); + } + + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/RoutingHandler.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/RoutingHandler.java new file mode 100644 index 0000000000..282b066085 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/RoutingHandler.java @@ -0,0 +1,30 @@ +package com.baeldung.nullobject; + +import java.util.Arrays; +import java.util.List; + +public class RoutingHandler { + + public void handle(Iterable messages){ + for (Message msg : messages) { + Router router = RouterFactory.getRouterForMessage(msg); + router.route(msg); + } + } + + public static void main(String[] args) { + Message highPriorityMsg = new Message("Alert!", "high"); + Message mediumPriorityMsg = new Message("Warning!", "medium"); + Message lowPriorityMsg = new Message("Take a look!", "low"); + Message nullPriorityMsg = new Message("Take a look!", null); + + List messages = Arrays.asList(highPriorityMsg, + mediumPriorityMsg, + lowPriorityMsg, + nullPriorityMsg); + + RoutingHandler routingHandler = new RoutingHandler(); + routingHandler.handle(messages); + + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/SmsRouter.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/SmsRouter.java new file mode 100644 index 0000000000..3e8e2f15f3 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nullobject/SmsRouter.java @@ -0,0 +1,10 @@ +package com.baeldung.nullobject; + +public class SmsRouter implements Router { + + @Override + public void route(Message msg) { + System.out.println("Routing to a SMS gateway. Msg: " + msg); + } + +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/APIContracts.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/APIContracts.java new file mode 100644 index 0000000000..7d6abf53b8 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/APIContracts.java @@ -0,0 +1,30 @@ +package com.baeldung.nulls; + +public class APIContracts { + + /** + * Prints the value of {@code param} if not null. Prints {@code null} otherwise. + * + * @param param + */ + public void print(Object param) { + System.out.println("Printing " + param); + } + + /** + * @return non null result + * @throws Exception - if result is null + */ + public Object process() throws Exception { + Object result = doSomething(); + if (result == null) { + throw new Exception("Processing fail. Got a null response"); + } else { + return result; + } + } + + private Object doSomething() { + return null; + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Assertions.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Assertions.java new file mode 100644 index 0000000000..a0d692623f --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Assertions.java @@ -0,0 +1,13 @@ +package com.baeldung.nulls; + +public class Assertions { + + public void accept(Object param){ + assert param != null; + + doSomething(param); + } + + private void doSomething(Object param) { + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/EmptyCollections.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/EmptyCollections.java new file mode 100644 index 0000000000..5958cf8dc6 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/EmptyCollections.java @@ -0,0 +1,25 @@ +package com.baeldung.nulls; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class EmptyCollections { + + public List names() { + if (userExist()) { + return Stream.of(readName()).collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + private boolean userExist() { + return false; + } + + private String readName() { + return "test"; + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java new file mode 100644 index 0000000000..697d5e4959 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/FindBugsAnnotations.java @@ -0,0 +1,30 @@ +package com.baeldung.nulls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + + +public class FindBugsAnnotations { + + public void accept(@NotNull Object param) { + System.out.println(param.toString()); + } + + public void print(@Nullable Object param) { + System.out.println("Printing " + param); + } + + @NotNull + public Object process() throws Exception { + Object result = doSomething(); + if (result == null) { + throw new Exception("Processing fail. Got a null response"); + } else { + return result; + } + } + + private Object doSomething() { + return null; + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Preconditions.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Preconditions.java new file mode 100644 index 0000000000..9d9633a13e --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/Preconditions.java @@ -0,0 +1,39 @@ +package com.baeldung.nulls; + +public class Preconditions { + + public void goodAccept(String one, String two, String three) { + if (one == null || two == null || three == null) { + throw new IllegalArgumentException(); + } + + process(one); + process(two); + process(three); + } + + public void badAccept(String one, String two, String three) { + if (one == null) { + throw new IllegalArgumentException(); + } else { + process(one); + } + + if (two == null) { + throw new IllegalArgumentException(); + } else { + process(two); + } + + if (three == null) { + throw new IllegalArgumentException(); + } else { + process(three); + } + + } + + private void process(String one) { + } + +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/PrimitivesAndWrapper.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/PrimitivesAndWrapper.java new file mode 100644 index 0000000000..c75918c486 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/PrimitivesAndWrapper.java @@ -0,0 +1,21 @@ +package com.baeldung.nulls; + +public class PrimitivesAndWrapper { + + public static int primitiveSum(int a, int b) { + return a + b; + } + + public static Integer wrapperSum(Integer a, Integer b) { + return a + b; + } + + public static Integer goodSum(Integer a, Integer b) { + if (a != null && b != null) { + return a + b; + } else { + throw new IllegalArgumentException(); + } + } + +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingLombok.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingLombok.java new file mode 100644 index 0000000000..73db0742c8 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingLombok.java @@ -0,0 +1,10 @@ +package com.baeldung.nulls; + +import lombok.NonNull; + +public class UsingLombok { + + public void accept(@NonNull Object param){ + System.out.println(param); + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingObjects.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingObjects.java new file mode 100644 index 0000000000..5384edee5e --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingObjects.java @@ -0,0 +1,11 @@ +package com.baeldung.nulls; + +import java.util.Objects; + +public class UsingObjects { + + public void accept(Object param) { + Objects.requireNonNull(param); + // doSomething() + } +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingOptional.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingOptional.java new file mode 100644 index 0000000000..6c17290a72 --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingOptional.java @@ -0,0 +1,27 @@ +package com.baeldung.nulls; + +import java.util.Optional; + +public class UsingOptional { + + public Optional process(boolean processed) { + + String response = doSomething(processed); + + if (response == null) { + return Optional.empty(); + } + + return Optional.of(response); + } + + private String doSomething(boolean processed) { + + if (processed) { + return "passed"; + } else { + return null; + } + } + +} diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingStringUtils.java b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingStringUtils.java new file mode 100644 index 0000000000..c7c73b73eb --- /dev/null +++ b/patterns/design-patterns-2/src/main/java/com/baeldung/nulls/UsingStringUtils.java @@ -0,0 +1,22 @@ +package com.baeldung.nulls; + +import org.apache.commons.lang3.StringUtils; + +public class UsingStringUtils { + + public void accept(String param) { + if (StringUtils.isNotEmpty(param)) { + System.out.println(param); + } else { + throw new IllegalArgumentException(); + } + } + + public void acceptOnlyNonBlank(String param) { + if (StringUtils.isNotBlank(param)) { + System.out.println(param); + } else { + throw new IllegalArgumentException(); + } + } +} diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/mediator/MediatorIntegrationTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/mediator/MediatorIntegrationTest.java new file mode 100644 index 0000000000..0bda659f3f --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/mediator/MediatorIntegrationTest.java @@ -0,0 +1,36 @@ +package com.baeldung.mediator; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class MediatorIntegrationTest { + + private Button button; + private Fan fan; + + @Before + public void setUp() { + this.button = new Button(); + this.fan = new Fan(); + PowerSupplier powerSupplier = new PowerSupplier(); + Mediator mediator = new Mediator(); + + mediator.setButton(this.button); + mediator.setFan(fan); + mediator.setPowerSupplier(powerSupplier); + } + + @Test + public void givenTurnedOffFan_whenPressingButtonTwice_fanShouldTurnOnAndOff() { + assertFalse(fan.isOn()); + + button.press(); + assertTrue(fan.isOn()); + + button.press(); + assertFalse(fan.isOn()); + } +} \ No newline at end of file diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/PrimitivesAndWrapperUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/PrimitivesAndWrapperUnitTest.java new file mode 100644 index 0000000000..49655619f6 --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/PrimitivesAndWrapperUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.nulls; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class PrimitivesAndWrapperUnitTest { + + @Test + public void givenBothArgsNonNull_whenCallingWrapperSum_thenReturnSum() { + + Integer sum = PrimitivesAndWrapper.wrapperSum(0, 0); + + assertEquals(0, sum.intValue()); + } + + @Test() + public void givenOneArgIsNull_whenCallingWrapperSum_thenThrowNullPointerException() { + assertThrows(NullPointerException.class, () -> PrimitivesAndWrapper.wrapperSum(null, 2)); + } + + @Test() + public void givenBothArgsNull_whenCallingWrapperSum_thenThrowNullPointerException() { + assertThrows(NullPointerException.class, () -> PrimitivesAndWrapper.wrapperSum(null, null)); + } + + @Test() + public void givenOneArgNull_whenCallingGoodSum_thenThrowIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> PrimitivesAndWrapper.goodSum(null, 2)); + } + + + +} \ No newline at end of file diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingLombokUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingLombokUnitTest.java new file mode 100644 index 0000000000..b322344aba --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingLombokUnitTest.java @@ -0,0 +1,24 @@ +package com.baeldung.nulls; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +class UsingLombokUnitTest { + + private UsingLombok classUnderTest; + + @BeforeEach + public void setup() { + classUnderTest = new UsingLombok(); + } + + @Test + public void whenNullArg_thenThrowNullPointerException() { + + assertThrows(NullPointerException.class, () -> classUnderTest.accept(null)); + + } + +} \ No newline at end of file diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingObjectsUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingObjectsUnitTest.java new file mode 100644 index 0000000000..e1f5a288e6 --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingObjectsUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.nulls; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class UsingObjectsUnitTest { + + private UsingObjects classUnderTest; + + @BeforeEach + public void setup() { + classUnderTest = new UsingObjects(); + } + + @Test + public void whenArgIsNull_thenThrowException() { + + assertThrows(NullPointerException.class, () -> classUnderTest.accept(null)); + } + + @Test + public void whenArgIsNonNull_thenDoesNotThrowException() { + + assertDoesNotThrow(() -> classUnderTest.accept("test ")); + } + +} \ No newline at end of file diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingOptionalUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingOptionalUnitTest.java new file mode 100644 index 0000000000..8f896cedfa --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingOptionalUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.nulls; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class UsingOptionalUnitTest { + + private UsingOptional classUnderTest; + + @BeforeEach + public void setup() { + classUnderTest = new UsingOptional(); + } + + @Test + public void whenArgIsFalse_thenReturnEmptyResponse() { + + Optional result = classUnderTest.process(false); + + assertFalse(result.isPresent()); + } + + @Test + public void whenArgIsTrue_thenReturnValidResponse() { + + Optional result = classUnderTest.process(true); + + assertTrue(result.isPresent()); + } + + @Test + public void whenArgIsFalse_thenChainResponseAndThrowException() { + + assertThrows(Exception.class, () -> classUnderTest.process(false).orElseThrow(() -> new Exception())); + } +} \ No newline at end of file diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingStringUtilsUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingStringUtilsUnitTest.java new file mode 100644 index 0000000000..f7c51a7dc5 --- /dev/null +++ b/patterns/design-patterns-2/src/test/java/com/baeldung/nulls/UsingStringUtilsUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.nulls; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +class UsingStringUtilsUnitTest { + + private UsingStringUtils classUnderTest; + + @BeforeEach + public void setup() { + classUnderTest = new UsingStringUtils(); + } + + @Test + public void givenArgIsNull_whenCallingAccept_throwIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> classUnderTest.accept(null)); + } + + @Test + public void givenArgIsEmpty_whenCallingAccept_throwIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> classUnderTest.accept("")); + } + + @Test + public void givenArgIsNull_whenCallingAcceptOnlyNonBlank_throwIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> classUnderTest.acceptOnlyNonBlank(null)); + } + + @Test + public void givenArgIsEmpty_whenCallingAcceptOnlyNonBlank_throwIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> classUnderTest.acceptOnlyNonBlank("")); + } + + @Test + public void givenArgIsBlank_whenCallingAcceptOnlyNonBlank_throwIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> classUnderTest.acceptOnlyNonBlank(" ")); + } + +} \ No newline at end of file diff --git a/patterns/design-patterns/README.md b/patterns/design-patterns/README.md index 8046d2034b..c43ea48505 100644 --- a/patterns/design-patterns/README.md +++ b/patterns/design-patterns/README.md @@ -18,3 +18,5 @@ - [Chain of Responsibility Design Pattern in Java](http://www.baeldung.com/chain-of-responsibility-pattern) - [The Command Pattern in Java](http://www.baeldung.com/java-command-pattern) - [Java Constructors vs Static Factory Methods](https://www.baeldung.com/java-constructors-vs-static-factory-methods) +- [The Adapter Pattern in Java](https://www.baeldung.com/java-adapter-pattern) +- [Currying in Java](https://baeldung.com/currying-in-java) diff --git a/patterns/design-patterns/src/main/java/com/baeldung/currying/Letter.java b/patterns/design-patterns/src/main/java/com/baeldung/currying/Letter.java new file mode 100644 index 0000000000..0939569d3c --- /dev/null +++ b/patterns/design-patterns/src/main/java/com/baeldung/currying/Letter.java @@ -0,0 +1,110 @@ +package com.baeldung.currying; + +import java.time.LocalDate; +import java.util.Objects; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class Letter { + private String returningAddress; + private String insideAddress; + private LocalDate dateOfLetter; + private String salutation; + private String body; + private String closing; + + Letter(String returningAddress, String insideAddress, LocalDate dateOfLetter, String salutation, String body, String closing) { + this.returningAddress = returningAddress; + this.insideAddress = insideAddress; + this.dateOfLetter = dateOfLetter; + this.salutation = salutation; + this.body = body; + this.closing = closing; + } + + Letter(String salutation, String body) { + this(null, null, LocalDate.now(), salutation, body, null); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Letter letter = (Letter) o; + return Objects.equals(returningAddress, letter.returningAddress) && + Objects.equals(insideAddress, letter.insideAddress) && + Objects.equals(dateOfLetter, letter.dateOfLetter) && + Objects.equals(salutation, letter.salutation) && + Objects.equals(body, letter.body) && + Objects.equals(closing, letter.closing); + } + + @Override + public int hashCode() { + return Objects.hash(returningAddress, insideAddress, dateOfLetter, salutation, body, closing); + } + + @Override + public String toString() { + return "Letter{" + "returningAddress='" + returningAddress + '\'' + ", insideAddress='" + insideAddress + '\'' + + ", dateOfLetter=" + dateOfLetter + ", salutation='" + salutation + '\'' + ", body='" + body + '\'' + + ", closing='" + closing + '\'' + '}'; + } + + static Letter createLetter(String salutation, String body) { + return new Letter(salutation, body); + } + + static BiFunction SIMPLE_LETTER_CREATOR = // + (salutation, body) -> new Letter(salutation, body); + + static Function> SIMPLE_CURRIED_LETTER_CREATOR = // + saluation -> body -> new Letter(saluation, body); + + static Function>>>>> LETTER_CREATOR = // + returnAddress + -> closing + -> dateOfLetter + -> insideAddress + -> salutation + -> body + -> new Letter(returnAddress, insideAddress, dateOfLetter, salutation, body, closing); + + static AddReturnAddress builder() { + return returnAddress + -> closing + -> dateOfLetter + -> insideAddress + -> salutation + -> body + -> new Letter(returnAddress, insideAddress, dateOfLetter, salutation, body, closing); + } + + interface AddReturnAddress { + Letter.AddClosing withReturnAddress(String returnAddress); + } + + interface AddClosing { + Letter.AddDateOfLetter withClosing(String closing); + } + + interface AddDateOfLetter { + Letter.AddInsideAddress withDateOfLetter(LocalDate dateOfLetter); + } + + interface AddInsideAddress { + Letter.AddSalutation withInsideAddress(String insideAddress); + } + + interface AddSalutation { + Letter.AddBody withSalutation(String salutation); + } + + interface AddBody { + Letter withBody(String body); + } +} \ No newline at end of file diff --git a/patterns/design-patterns/src/test/java/com/baeldung/currying/LetterUnitTest.java b/patterns/design-patterns/src/test/java/com/baeldung/currying/LetterUnitTest.java new file mode 100644 index 0000000000..bf1bafe72c --- /dev/null +++ b/patterns/design-patterns/src/test/java/com/baeldung/currying/LetterUnitTest.java @@ -0,0 +1,58 @@ +package com.baeldung.currying; + +import org.junit.Test; + +import java.time.LocalDate; + +import static com.baeldung.currying.Letter.LETTER_CREATOR; +import static com.baeldung.currying.Letter.SIMPLE_CURRIED_LETTER_CREATOR; +import static com.baeldung.currying.Letter.SIMPLE_LETTER_CREATOR; +import static org.junit.Assert.assertEquals; + +public class LetterUnitTest { + private static final String BODY = "BODY"; + private static final String SALUTATION = "SALUTATION"; + private static final String RETURNING_ADDRESS = "RETURNING ADDRESS"; + private static final String INSIDE_ADDRESS = "INSIDE ADDRESS"; + private static final LocalDate DATE_OF_LETTER = LocalDate.of(2013, 3, 1); + private static final String CLOSING = "CLOSING"; + private static final Letter SIMPLE_LETTER = new Letter(SALUTATION, BODY); + private static final Letter LETTER = new Letter(RETURNING_ADDRESS, INSIDE_ADDRESS, DATE_OF_LETTER, SALUTATION, BODY, CLOSING); + + @Test + public void whenStaticCreateMethodIsCalled_thenaSimpleLetterIsCreated() { + assertEquals(SIMPLE_LETTER, Letter.createLetter(SALUTATION, BODY)); + } + + @Test + public void whenStaticBiFunctionIsCalled_thenaSimpleLetterIsCreated() { + assertEquals(SIMPLE_LETTER, SIMPLE_LETTER_CREATOR.apply(SALUTATION, BODY)); + } + + @Test + public void whenStaticSimpleCurriedFunctionIsCalled_thenaSimpleLetterIsCreated() { + assertEquals(SIMPLE_LETTER, SIMPLE_CURRIED_LETTER_CREATOR.apply(SALUTATION).apply(BODY)); + } + + @Test + public void whenStaticCurriedFunctionIsCalled_thenaLetterIsCreated() { + assertEquals(LETTER, LETTER_CREATOR + .apply(RETURNING_ADDRESS) + .apply(CLOSING) + .apply(DATE_OF_LETTER) + .apply(INSIDE_ADDRESS) + .apply(SALUTATION) + .apply(BODY)); + } + + @Test + public void whenStaticBuilderIsCalled_thenaLetterIsCreated() { + assertEquals(LETTER, Letter.builder() + .withReturnAddress(RETURNING_ADDRESS) + .withClosing(CLOSING) + .withDateOfLetter(DATE_OF_LETTER) + .withInsideAddress(INSIDE_ADDRESS) + .withSalutation(SALUTATION) + .withBody(BODY)); + } +} \ No newline at end of file diff --git a/patterns/dip/pom.xml b/patterns/dip/pom.xml new file mode 100644 index 0000000000..dac3f824f2 --- /dev/null +++ b/patterns/dip/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + com.baeldung.dip + dip + dip + 1.0-SNAPSHOT + + + com.baeldung + patterns + 1.0.0-SNAPSHOT + .. + + + + + junit + junit + 4.12 + test + + + org.assertj + assertj-core + 3.12.1 + test + + + + + UTF-8 + 11 + 11 + + + diff --git a/patterns/dip/src/main/java/com/baeldung/dip/application/Application.java b/patterns/dip/src/main/java/com/baeldung/dip/application/Application.java new file mode 100644 index 0000000000..8cc8901f70 --- /dev/null +++ b/patterns/dip/src/main/java/com/baeldung/dip/application/Application.java @@ -0,0 +1,18 @@ +package com.baeldung.dip.application; + +import com.baeldung.dip.daoimplementations.SimpleCustomerDao; +import com.baeldung.dip.entities.Customer; +import com.baeldung.dip.services.CustomerService; +import java.util.Map; +import java.util.HashMap; + +public class Application { + + public static void main(String[] args) { + Map customers = new HashMap<>(); + customers.put(1, new Customer("John")); + customers.put(2, new Customer("Susan")); + CustomerService customerService = new CustomerService(new SimpleCustomerDao(customers)); + customerService.findAll().forEach(System.out::println); + } +} diff --git a/patterns/dip/src/main/java/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java b/patterns/dip/src/main/java/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java new file mode 100644 index 0000000000..ea2bf3f00a --- /dev/null +++ b/patterns/dip/src/main/java/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java @@ -0,0 +1,28 @@ +package com.baeldung.dip.daoimplementations; + +import com.baeldung.dip.entities.Customer; +import com.baeldung.dip.daointerfaces.CustomerDao; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class SimpleCustomerDao implements CustomerDao { + + private Map customers = new HashMap<>(); + + public SimpleCustomerDao(Map customers) { + this.customers = customers; + } + + @Override + public Optional findById(int id) { + return Optional.ofNullable(customers.get(id)); + } + + @Override + public List findAll() { + return new ArrayList<>(customers.values()); + } +} diff --git a/patterns/dip/src/main/java/com/baeldung/dip/daointerfaces/CustomerDao.java b/patterns/dip/src/main/java/com/baeldung/dip/daointerfaces/CustomerDao.java new file mode 100644 index 0000000000..8ea83673b0 --- /dev/null +++ b/patterns/dip/src/main/java/com/baeldung/dip/daointerfaces/CustomerDao.java @@ -0,0 +1,13 @@ +package com.baeldung.dip.daointerfaces; + +import com.baeldung.dip.entities.Customer; +import java.util.List; +import java.util.Optional; + +public interface CustomerDao { + + Optional findById(int id); + + List findAll(); + +} diff --git a/patterns/dip/src/main/java/com/baeldung/dip/entities/Customer.java b/patterns/dip/src/main/java/com/baeldung/dip/entities/Customer.java new file mode 100644 index 0000000000..f8d5d82102 --- /dev/null +++ b/patterns/dip/src/main/java/com/baeldung/dip/entities/Customer.java @@ -0,0 +1,19 @@ +package com.baeldung.dip.entities; + +public class Customer { + + private final String name; + + public Customer(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "Customer{" + "name=" + name + '}'; + } +} diff --git a/patterns/dip/src/main/java/com/baeldung/dip/services/CustomerService.java b/patterns/dip/src/main/java/com/baeldung/dip/services/CustomerService.java new file mode 100644 index 0000000000..4566186ced --- /dev/null +++ b/patterns/dip/src/main/java/com/baeldung/dip/services/CustomerService.java @@ -0,0 +1,23 @@ +package com.baeldung.dip.services; + +import com.baeldung.dip.daointerfaces.CustomerDao; +import com.baeldung.dip.entities.Customer; +import java.util.List; +import java.util.Optional; + +public class CustomerService { + + private final CustomerDao customerDao; + + public CustomerService(CustomerDao customerDao) { + this.customerDao = customerDao; + } + + public Optional findById(int id) { + return customerDao.findById(id); + } + + public List findAll() { + return customerDao.findAll(); + } +} diff --git a/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerDaoUnitTest.java b/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerDaoUnitTest.java new file mode 100644 index 0000000000..2a03822ce2 --- /dev/null +++ b/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerDaoUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.dip.tests; + +import com.baeldung.dip.daoimplementations.SimpleCustomerDao; +import com.baeldung.dip.daointerfaces.CustomerDao; +import com.baeldung.dip.entities.Customer; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Before; +import org.junit.Test; + +public class CustomerDaoUnitTest { + + private CustomerDao customerDao; + + @Before + public void setUpCustomerDaoInstance() { + Map customers = new HashMap<>(); + customers.put(1, new Customer("John")); + customers.put(2, new Customer("Susan")); + customerDao = new SimpleCustomerDao(customers); + } + + @Test + public void givenCustomerDaoInstance_whenCalledFindById_thenCorrect() { + assertThat(customerDao.findById(1)).isInstanceOf(Optional.class); + } + + @Test + public void givenCustomerDaoInstance_whenCalledFindAll_thenCorrect() { + assertThat(customerDao.findAll()).isInstanceOf(List.class); + } + + @Test + public void givenCustomerDaoInstance_whenCalledFindByIdWithNullCustomer_thenCorrect() { + Map customers = new HashMap(); + customers.put(1, null); + CustomerDao customerDaoObject = new SimpleCustomerDao(customers); + + Customer customer = customerDaoObject.findById(1).orElseGet(() -> new Customer("Non-existing customer")); + + assertThat(customer.getName()).isEqualTo("Non-existing customer"); + } +} diff --git a/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerServiceUnitTest.java b/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerServiceUnitTest.java new file mode 100644 index 0000000000..5ffd6fad51 --- /dev/null +++ b/patterns/dip/src/test/java/com/baeldung/dip/tests/CustomerServiceUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.dip.tests; + +import com.baeldung.dip.daoimplementations.SimpleCustomerDao; +import com.baeldung.dip.entities.Customer; +import com.baeldung.dip.services.CustomerService; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Before; +import org.junit.Test; + +public class CustomerServiceUnitTest { + + private CustomerService customerService; + + @Before + public void setUpCustomerServiceInstance() { + Map customers = new HashMap<>(); + customers.put(1, new Customer("John")); + customers.put(2, new Customer("Susan")); + customerService = new CustomerService(new SimpleCustomerDao(customers)); + } + + @Test + public void givenCustomerServiceInstance_whenCalledFindById_thenCorrect() { + assertThat(customerService.findById(1)).isInstanceOf(Optional.class); + } + + @Test + public void givenCustomerServiceInstance_whenCalledFindAll_thenCorrect() { + assertThat(customerService.findAll()).isInstanceOf(List.class); + } + + @Test + public void givenCustomerServiceInstance_whenCalledFindByIdWithNullCustomer_thenCorrect() { + Map customers = new HashMap<>(); + customers.put(1, null); + customerService = new CustomerService(new SimpleCustomerDao(customers)); + + Customer customer = customerService.findById(1).orElseGet(() -> new Customer("Non-existing customer")); + + assertThat(customer.getName()).isEqualTo("Non-existing customer"); + } +} diff --git a/patterns/dipmodular/com.baeldung.dip.daoimplementations/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java b/patterns/dipmodular/com.baeldung.dip.daoimplementations/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java new file mode 100644 index 0000000000..ef6482ecc7 --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.daoimplementations/com/baeldung/dip/daoimplementations/SimpleCustomerDao.java @@ -0,0 +1,30 @@ +package com.baeldung.dip.daoimplementations; + +import com.baeldung.dip.daos.CustomerDao; +import com.baeldung.dip.entities.Customer; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class SimpleCustomerDao implements CustomerDao { + + private Map customers = new HashMap<>(); + + public SimpleCustomerDao() { + + } + + public SimpleCustomerDao(Map customers) { + this.customers = customers; + } + + @Override + public Optional findById(int id) { + return Optional.ofNullable(customers.get(id)); + } + + @Override + public List findAll() { + return new ArrayList<>(customers.values()); + } +} diff --git a/patterns/dipmodular/com.baeldung.dip.daoimplementations/module-info.java b/patterns/dipmodular/com.baeldung.dip.daoimplementations/module-info.java new file mode 100644 index 0000000000..1df40ce3b8 --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.daoimplementations/module-info.java @@ -0,0 +1,6 @@ +module com.baeldung.dip.daoimplementations { + requires com.baeldung.dip.entities; + requires com.baeldung.dip.daos; + provides com.baeldung.dip.daos.CustomerDao with com.baeldung.dip.daoimplementations.SimpleCustomerDao; + exports com.baeldung.dip.daoimplementations; +} diff --git a/patterns/dipmodular/com.baeldung.dip.daos/com/baeldung/dip/daos/CustomerDao.java b/patterns/dipmodular/com.baeldung.dip.daos/com/baeldung/dip/daos/CustomerDao.java new file mode 100644 index 0000000000..b0080dd15e --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.daos/com/baeldung/dip/daos/CustomerDao.java @@ -0,0 +1,13 @@ +package com.baeldung.dip.daos; + +import com.baeldung.dip.entities.Customer; +import java.util.Map; +import java.util.Optional; + +public interface CustomerDao { + + Optional findById(int id); + + List findAll(); + +} diff --git a/patterns/dipmodular/com.baeldung.dip.daos/module-info.java b/patterns/dipmodular/com.baeldung.dip.daos/module-info.java new file mode 100644 index 0000000000..897c6168a1 --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.daos/module-info.java @@ -0,0 +1,4 @@ +module com.baeldung.dip.daos { + requires com.baeldung.dip.entities; + exports com.baeldung.dip.daos; +} diff --git a/patterns/dipmodular/com.baeldung.dip.entities/com/baeldung/dip/entities/Customer.java b/patterns/dipmodular/com.baeldung.dip.entities/com/baeldung/dip/entities/Customer.java new file mode 100644 index 0000000000..f8d5d82102 --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.entities/com/baeldung/dip/entities/Customer.java @@ -0,0 +1,19 @@ +package com.baeldung.dip.entities; + +public class Customer { + + private final String name; + + public Customer(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "Customer{" + "name=" + name + '}'; + } +} diff --git a/patterns/dipmodular/com.baeldung.dip.entities/module-info.java b/patterns/dipmodular/com.baeldung.dip.entities/module-info.java new file mode 100644 index 0000000000..da8c1ccaee --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.entities/module-info.java @@ -0,0 +1,3 @@ +module com.baeldung.dip.entities { + exports com.baeldung.dip.entities; +} diff --git a/patterns/dipmodular/com.baeldung.dip.mainapp/com/baeldung/dip/mainapp/MainApplication.java b/patterns/dipmodular/com.baeldung.dip.mainapp/com/baeldung/dip/mainapp/MainApplication.java new file mode 100644 index 0000000000..8972dc3994 --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.mainapp/com/baeldung/dip/mainapp/MainApplication.java @@ -0,0 +1,17 @@ +package com.baeldung.dip.mainapp; + +import com.baeldung.dip.daoimplementations.MapCustomerDao; +import com.baeldung.dip.entities.Customer; +import com.baeldung.dip.services.CustomerService; +import java.util.HashMap; + +public class MainApplication { + + public static void main(String args[]) { + var customers = new HashMap(); + customers.put(1, new Customer("John")); + customers.put(2, new Customer("Susan")); + CustomerService customerService = new CustomerService(new SimpleCustomerDao(customers)); + customerService.findAll().forEach(System.out::println); + } +} diff --git a/patterns/dipmodular/com.baeldung.dip.mainapp/module-info.java b/patterns/dipmodular/com.baeldung.dip.mainapp/module-info.java new file mode 100644 index 0000000000..466306334a --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.mainapp/module-info.java @@ -0,0 +1,7 @@ +module com.baeldung.dip.mainapp { + requires com.baeldung.dip.entities; + requires com.baeldung.dip.daos; + requires com.baeldung.dip.daoimplementations; + requires com.baeldung.dip.services; + exports com.baeldung.dip.mainapp; +} diff --git a/patterns/dipmodular/com.baeldung.dip.services/com/baeldung/dip/services/CustomerService.java b/patterns/dipmodular/com.baeldung.dip.services/com/baeldung/dip/services/CustomerService.java new file mode 100644 index 0000000000..39955abdaf --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.services/com/baeldung/dip/services/CustomerService.java @@ -0,0 +1,23 @@ +package com.baeldung.dip.services; + +import com.baeldung.dip.daos.CustomerDao; +import com.baeldung.dip.entities.Customer; +import java.util.Map; +import java.util.Optional; + +public class CustomerService { + + private final CustomerDao customerDao; + + public CustomerService(CustomerDao customerDao) { + this.customerDao = customerDao; + } + + public Optional findById(int id) { + return customerDao.findById(id); + } + + public List findAll() { + return customerDao.findAll(); + } +} diff --git a/patterns/dipmodular/com.baeldung.dip.services/module-info.java b/patterns/dipmodular/com.baeldung.dip.services/module-info.java new file mode 100644 index 0000000000..8e59cd7abe --- /dev/null +++ b/patterns/dipmodular/com.baeldung.dip.services/module-info.java @@ -0,0 +1,6 @@ +module com.baeldung.dip.services { + requires com.baeldung.dip.entities; + requires com.baeldung.dip.daos; + uses com.baeldung.dip.daos.CustomerDao; + exports com.baeldung.dip.services; +} diff --git a/patterns/pom.xml b/patterns/pom.xml index 3c3bb6d5ea..bf302a7a74 100644 --- a/patterns/pom.xml +++ b/patterns/pom.xml @@ -1,10 +1,10 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 patterns pom - patterns + patterns com.baeldung @@ -17,7 +17,9 @@ front-controller intercepting-filter design-patterns + design-patterns-2 solid + dip @@ -54,4 +56,4 @@ 9.4.0.v20161208 - \ No newline at end of file + diff --git a/patterns/solid/pom.xml b/patterns/solid/pom.xml index 2837504197..146a9903cf 100644 --- a/patterns/solid/pom.xml +++ b/patterns/solid/pom.xml @@ -5,6 +5,7 @@ 4.0.0 com.baeldung solid + solid 1.0-SNAPSHOT diff --git a/persistence-modules/core-java-persistence/README.md b/persistence-modules/core-java-persistence/README.md index ca0ce81eef..26bd4bf00f 100644 --- a/persistence-modules/core-java-persistence/README.md +++ b/persistence-modules/core-java-persistence/README.md @@ -7,3 +7,4 @@ - [Batch Processing in JDBC](http://www.baeldung.com/jdbc-batch-processing) - [Introduction to the JDBC RowSet Interface in Java](http://www.baeldung.com/java-jdbc-rowset) - [A Simple Guide to Connection Pooling in Java](https://www.baeldung.com/java-connection-pooling) +- [Guide to the JDBC ResultSet Interface](https://www.baeldung.com/jdbc-resultset) diff --git a/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/Employee.java b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/Employee.java index 749855ca3b..27aef8b82f 100644 --- a/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/Employee.java +++ b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/Employee.java @@ -1,5 +1,7 @@ package com.baeldung.jdbc; +import java.util.Objects; + public class Employee { private int id; private String name; @@ -48,4 +50,21 @@ public class Employee { this.position = position; } + @Override + public int hashCode() { + return Objects.hash(id, name, position, salary); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Employee other = (Employee) obj; + return id == other.id && Objects.equals(name, other.name) && Objects.equals(position, other.position) && Double.doubleToLongBits(salary) == Double.doubleToLongBits(other.salary); + } + } diff --git a/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/ResultSetLiveTest.java b/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/ResultSetLiveTest.java new file mode 100644 index 0000000000..4e10f8bd43 --- /dev/null +++ b/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/ResultSetLiveTest.java @@ -0,0 +1,359 @@ +package com.baeldung.jdbc; + +import static org.junit.Assert.assertEquals; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import junit.framework.Assert; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class ResultSetLiveTest { + + private static final Logger logger = Logger.getLogger(ResultSetLiveTest.class); + + private final Employee expectedEmployee1 = new Employee(1, "John", 1000.0, "Developer"); + + private final Employee updatedEmployee1 = new Employee(1, "John", 1100.0, "Developer"); + + private final Employee expectedEmployee2 = new Employee(2, "Chris", 925.0, "DBA"); + + private final int rowCount = 2; + + private static Connection dbConnection; + + @BeforeClass + public static void setup() throws ClassNotFoundException, SQLException { + Class.forName("com.mysql.cj.jdbc.Driver"); + dbConnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/myDB?noAccessToProcedureBodies=true", "user1", "pass"); + String tableSql = "CREATE TABLE IF NOT EXISTS employees (emp_id int PRIMARY KEY AUTO_INCREMENT, name varchar(30), position varchar(30), salary double)"; + try (Statement stmt = dbConnection.createStatement()) { + stmt.execute(tableSql); + try (PreparedStatement pstmt = dbConnection.prepareStatement("INSERT INTO employees(name, position, salary) values ('John', 'Developer', 1000.0)")) { + pstmt.executeUpdate(); + } + } + } + + @Test + public void givenDbConnectionA_whenRetreiveByColumnNames_thenCorrect() throws SQLException { + Employee employee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees"); ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + String name = rs.getString("name"); + Integer empId = rs.getInt("emp_id"); + Double salary = rs.getDouble("salary"); + String position = rs.getString("position"); + employee = new Employee(empId, name, salary, position); + } + } + + assertEquals("Employee information retreived by column names.", expectedEmployee1, employee); + } + + @Test + public void givenDbConnectionB_whenRetreiveByColumnIds_thenCorrect() throws SQLException { + Employee employee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees"); ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + Integer empId = rs.getInt(1); + String name = rs.getString(2); + String position = rs.getString(3); + Double salary = rs.getDouble(4); + employee = new Employee(empId, name, salary, position); + } + } + + assertEquals("Employee information retreived by column ids.", expectedEmployee1, employee); + } + + @Test + public void givenDbConnectionD_whenInsertRow_thenCorrect() throws SQLException { + int rowCount = 0; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.moveToInsertRow(); + rs.updateString("name", "Chris"); + rs.updateString("position", "DBA"); + rs.updateDouble("salary", 925.0); + rs.insertRow(); + rs.moveToCurrentRow(); + rs.last(); + rowCount = rs.getRow(); + } + + assertEquals("Row Count after inserting a row", 2, rowCount); + } + + private Employee populateResultSet(ResultSet rs) throws SQLException { + Employee employee; + String name = rs.getString("name"); + Integer empId = rs.getInt("emp_id"); + Double salary = rs.getDouble("salary"); + String position = rs.getString("position"); + employee = new Employee(empId, name, salary, position); + return employee; + } + + @Test + public void givenDbConnectionE_whenRowCount_thenCorrect() throws SQLException { + int numOfRows = 0; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.last(); + numOfRows = rs.getRow(); + } + + assertEquals("Num of rows", rowCount, numOfRows); + } + + @Test + public void givenDbConnectionG_whenAbsoluteNavigation_thenCorrect() throws SQLException { + Employee secondEmployee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.absolute(2); + secondEmployee = populateResultSet(rs); + } + + assertEquals("Absolute navigation", expectedEmployee2, secondEmployee); + } + + @Test + public void givenDbConnectionH_whenLastNavigation_thenCorrect() throws SQLException { + Employee secondEmployee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.last(); + secondEmployee = populateResultSet(rs); + } + + assertEquals("Using Last", expectedEmployee2, secondEmployee); + } + + @Test + public void givenDbConnectionI_whenNavigation_thenCorrect() throws SQLException { + Employee firstEmployee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + Employee employee = populateResultSet(rs); + } + rs.beforeFirst(); + while (rs.next()) { + Employee employee = populateResultSet(rs); + } + rs.first(); + while (rs.next()) { + Employee employee = populateResultSet(rs); + } + while (rs.previous()) { + Employee employee = populateResultSet(rs); + } + rs.afterLast(); + while (rs.previous()) { + Employee employee = populateResultSet(rs); + } + rs.last(); + while (rs.previous()) { + firstEmployee = populateResultSet(rs); + } + } + + assertEquals("Several Navigation Options", updatedEmployee1, firstEmployee); + } + + @Test + public void givenDbConnectionJ_whenClosedCursor_thenCorrect() throws SQLException { + Employee employee = null; + dbConnection.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT); + try (Statement pstmt = dbConnection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT)) { + dbConnection.setAutoCommit(false); + ResultSet rs = pstmt.executeQuery("select * from employees"); + while (rs.next()) { + if (rs.getString("name") + .equalsIgnoreCase("john")) { + rs.updateString("position", "Senior Engineer"); + rs.updateRow(); + dbConnection.commit(); + employee = populateResultSet(rs); + } + } + rs.last(); + } + + assertEquals("Update using closed cursor", "Senior Engineer", employee.getPosition()); + } + + @Test + public void givenDbConnectionK_whenUpdate_thenCorrect() throws SQLException { + Employee employee = null; + dbConnection.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT); + try (Statement pstmt = dbConnection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.HOLD_CURSORS_OVER_COMMIT)) { + dbConnection.setAutoCommit(false); + ResultSet rs = pstmt.executeQuery("select * from employees"); + while (rs.next()) { + if (rs.getString("name") + .equalsIgnoreCase("john")) { + rs.updateString("name", "John Doe"); + rs.updateRow(); + dbConnection.commit(); + employee = populateResultSet(rs); + } + } + rs.last(); + } + + assertEquals("Update using open cursor", "John Doe", employee.getName()); + } + + @Test + public void givenDbConnectionM_whenDelete_thenCorrect() throws SQLException { + int numOfRows = 0; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.absolute(2); + rs.deleteRow(); + } + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + rs.last(); + numOfRows = rs.getRow(); + } + assertEquals("Deleted row", 1, numOfRows); + } + + @Test + public void givenDbConnectionC_whenUpdate_thenCorrect() throws SQLException { + Employee employee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + + Assert.assertEquals(1100.0, rs.getDouble("salary")); + + rs.updateDouble("salary", 1200.0); + rs.updateRow(); + + Assert.assertEquals(1200.0, rs.getDouble("salary")); + + String name = rs.getString("name"); + Integer empId = rs.getInt("emp_id"); + Double salary = rs.getDouble("salary"); + String position = rs.getString("position"); + employee = new Employee(empId, name, salary, position); + } + } + } + + @Test + public void givenDbConnectionC_whenUpdateByIndex_thenCorrect() throws SQLException { + Employee employee = null; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + + Assert.assertEquals(1000.0, rs.getDouble(4)); + + rs.updateDouble(4, 1100.0); + rs.updateRow(); + Assert.assertEquals(1100.0, rs.getDouble(4)); + + String name = rs.getString("name"); + Integer empId = rs.getInt("emp_id"); + Double salary = rs.getDouble("salary"); + String position = rs.getString("position"); + employee = new Employee(empId, name, salary, position); + } + } + } + + @Test + public void givenDbConnectionE_whenDBMetaInfo_thenCorrect() throws SQLException { + DatabaseMetaData dbmd = dbConnection.getMetaData(); + boolean supportsTypeForward = dbmd.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY); + boolean supportsTypeScrollSensitive = dbmd.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE); + boolean supportsTypeScrollInSensitive = dbmd.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE); + boolean supportsCloseCursorsAtCommit = dbmd.supportsResultSetHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT); + boolean supportsHoldCursorsAtCommit = dbmd.supportsResultSetHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT); + boolean concurrency4TypeFwdNConcurReadOnly = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + boolean concurrency4TypeFwdNConcurUpdatable = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + boolean concurrency4TypeScrollInSensitiveNConcurUpdatable = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); + boolean concurrency4TypeScrollInSensitiveNConcurReadOnly = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + boolean concurrency4TypeScrollSensitiveNConcurUpdatable = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + boolean concurrency4TypeScrollSensitiveNConcurReadOnly = dbmd.supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + int rsHoldability = dbmd.getResultSetHoldability(); + + assertEquals("checking scroll sensitivity and concur updates : ", true, concurrency4TypeScrollInSensitiveNConcurUpdatable); + } + + @Test + public void givenDbConnectionF_whenRSMetaInfo_thenCorrect() throws SQLException { + int columnCount = 0; + try (PreparedStatement pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = pstmt.executeQuery()) { + ResultSetMetaData metaData = rs.getMetaData(); + columnCount = metaData.getColumnCount(); + for (int i = 1; i <= columnCount; i++) { + String catalogName = metaData.getCatalogName(i); + String className = metaData.getColumnClassName(i); + String label = metaData.getColumnLabel(i); + String name = metaData.getColumnName(i); + String typeName = metaData.getColumnTypeName(i); + Integer type = metaData.getColumnType(i); + String tableName = metaData.getTableName(i); + String schemaName = metaData.getSchemaName(i); + boolean isAutoIncrement = metaData.isAutoIncrement(i); + boolean isCaseSensitive = metaData.isCaseSensitive(i); + boolean isCurrency = metaData.isCurrency(i); + boolean isDefiniteWritable = metaData.isDefinitelyWritable(i); + boolean isReadOnly = metaData.isReadOnly(i); + boolean isSearchable = metaData.isSearchable(i); + boolean isReadable = metaData.isReadOnly(i); + boolean isSigned = metaData.isSigned(i); + boolean isWritable = metaData.isWritable(i); + int nullable = metaData.isNullable(i); + } + } + + assertEquals("column count", 4, columnCount); + } + + @Test + public void givenDbConnectionL_whenFetch_thenCorrect() throws SQLException { + PreparedStatement pstmt = null; + ResultSet rs = null; + List listOfEmployees = new ArrayList(); + try { + pstmt = dbConnection.prepareStatement("select * from employees", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + pstmt.setFetchSize(1); + rs = pstmt.executeQuery(); + rs.setFetchSize(1); + while (rs.next()) { + Employee employee = populateResultSet(rs); + listOfEmployees.add(employee); + } + } catch (Exception e) { + throw e; + } finally { + if (rs != null) + rs.close(); + if (pstmt != null) + pstmt.close(); + } + + assertEquals(2, listOfEmployees.size()); + } + + @AfterClass + public static void closeConnection() throws SQLException { + PreparedStatement deleteStmt = dbConnection.prepareStatement("drop table employees", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); + deleteStmt.execute(); + dbConnection.close(); + } +} \ No newline at end of file diff --git a/persistence-modules/hibernate-ogm/README.md b/persistence-modules/hibernate-ogm/README.md index f4a5bb6c3b..df99cce129 100644 --- a/persistence-modules/hibernate-ogm/README.md +++ b/persistence-modules/hibernate-ogm/README.md @@ -1,4 +1,4 @@ ## Relevant articles: -- [Guide to Hibernate OGM](http://www.baeldung.com/xxxx) +- [A Guide to Hibernate OGM](https://www.baeldung.com/hibernate-ogm) diff --git a/persistence-modules/hibernate5/README.md b/persistence-modules/hibernate5/README.md index a4e95a9062..a37720a428 100644 --- a/persistence-modules/hibernate5/README.md +++ b/persistence-modules/hibernate5/README.md @@ -18,7 +18,7 @@ - [@JoinColumn Annotation Explained](https://www.baeldung.com/jpa-join-column) - [Hibernate 5 Naming Strategy Configuration](https://www.baeldung.com/hibernate-naming-strategy) - [Proxy in Hibernate load() Method](https://www.baeldung.com/hibernate-proxy-load-method) -- [Custom Types in Hibernate](https://www.baeldung.com/hibernate-custom-types) +- [Custom Types in Hibernate and the @Type Annotation](https://www.baeldung.com/hibernate-custom-types) - [Criteria API – An Example of IN Expressions](https://www.baeldung.com/jpa-criteria-api-in-expressions) - [Difference Between @JoinColumn and mappedBy](https://www.baeldung.com/jpa-joincolumn-vs-mappedby) - [Hibernate 5 Bootstrapping API](https://www.baeldung.com/hibernate-5-bootstrapping-api) @@ -30,3 +30,5 @@ - [Using c3p0 with Hibernate](https://www.baeldung.com/hibernate-c3p0) - [Persist a JSON Object Using Hibernate](https://www.baeldung.com/hibernate-persist-json-object) - [Common Hibernate Exceptions](https://www.baeldung.com/hibernate-exceptions) +- [Hibernate Aggregate Functions](https://www.baeldung.com/hibernate-aggregate-functions) +- [Hibernate Query Plan Cache](https://www.baeldung.com/hibernate-query-plan-cache) diff --git a/persistence-modules/hibernate5/pom.xml b/persistence-modules/hibernate5/pom.xml index a09669c8b5..c7f08e50d5 100644 --- a/persistence-modules/hibernate5/pom.xml +++ b/persistence-modules/hibernate5/pom.xml @@ -83,13 +83,18 @@ jmh-generator-annprocess ${openjdk-jmh.version} + + javax.xml.bind + jaxb-api + 2.3.0 + hibernate5 - src/main/resources + src/test/resources true diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java index ea0af97d5a..48c9b9d5c2 100644 --- a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java @@ -113,6 +113,7 @@ public class HibernateUtil { metadataSources.addAnnotatedClass(OptimisticLockingCourse.class); metadataSources.addAnnotatedClass(OptimisticLockingStudent.class); metadataSources.addAnnotatedClass(OfficeEmployee.class); + metadataSources.addAnnotatedClass(Post.class); Metadata metadata = metadataSources.getMetadataBuilder() .applyBasicType(LocalDateStringType.INSTANCE) diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Post.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Post.java new file mode 100644 index 0000000000..25e51e35d0 --- /dev/null +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Post.java @@ -0,0 +1,59 @@ +package com.baeldung.hibernate.pojo; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "posts") +public class Post { + + @Id + @GeneratedValue + private int id; + + private String title; + + private String body; + + public Post() { } + + public Post(String title, String body) { + this.title = title; + this.body = body; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + @Override + public String toString() { + return "Post{" + + "id=" + id + + ", title='" + title + '\'' + + ", body='" + body + '\'' + + '}'; + } +} diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/transaction/PostService.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/transaction/PostService.java new file mode 100644 index 0000000000..5a4eb20079 --- /dev/null +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/transaction/PostService.java @@ -0,0 +1,29 @@ +package com.baeldung.hibernate.transaction; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.query.Query; + +public class PostService { + + + private Session session; + + public PostService(Session session) { + this.session = session; + } + + + public void updatePost(String title, String body, int id) { + Transaction txn = session.beginTransaction(); + Query updateQuery = session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3"); + updateQuery.setParameter(1, title); + updateQuery.setParameter(2, body); + updateQuery.setParameter(3, id); + updateQuery.executeUpdate(); + txn.commit(); + } + + + +} diff --git a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java index 29ae55b773..e64e836924 100644 --- a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java +++ b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java @@ -74,4 +74,6 @@ public class CustomClassIntegrationTest { assertEquals("John Smith", result.getEmployeeName()); assertEquals("Sales", result.getDepartmentName()); } + + } diff --git a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/transaction/TransactionIntegrationTest.java b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/transaction/TransactionIntegrationTest.java new file mode 100644 index 0000000000..246a7d59f9 --- /dev/null +++ b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/transaction/TransactionIntegrationTest.java @@ -0,0 +1,57 @@ +package com.baeldung.hibernate.transaction; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.pojo.Post; +import com.baeldung.hibernate.transaction.PostService; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import static org.junit.Assert.assertEquals; + +public class TransactionIntegrationTest { + + private static PostService postService; + private static Session session; + private static Logger logger = LoggerFactory.getLogger(TransactionIntegrationTest.class); + + @BeforeClass + public static void init() throws IOException { + Properties properties = new Properties(); + properties.setProperty("hibernate.connection.driver_class", "org.h2.Driver"); + properties.setProperty("hibernate.connection.url", "jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1"); + properties.setProperty("hibernate.connection.username", "sa"); + properties.setProperty("hibernate.show_sql", "true"); + properties.setProperty("jdbc.password", ""); + properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); + properties.setProperty("hibernate.hbm2ddl.auto", "create-drop"); + SessionFactory sessionFactory = HibernateUtil.getSessionFactoryByProperties(properties); + session = sessionFactory.openSession(); + postService = new PostService(session); + } + + @Test + public void givenTitleAndBody_whenRepositoryUpdatePost_thenUpdatePost() { + + Post post = new Post("This is a title", "This is a sample post"); + session.persist(post); + + String title = "[UPDATE] Java HowTos"; + String body = "This is an updated posts on Java how-tos"; + postService.updatePost(title, body, post.getId()); + + session.refresh(post); + + assertEquals(post.getTitle(), title); + assertEquals(post.getBody(), body); + } + + +} diff --git a/persistence-modules/java-jpa/README.md b/persistence-modules/java-jpa/README.md index 2c26581bab..2424999fb3 100644 --- a/persistence-modules/java-jpa/README.md +++ b/persistence-modules/java-jpa/README.md @@ -6,3 +6,4 @@ - [JPA Entity Graph](https://www.baeldung.com/jpa-entity-graph) - [JPA 2.2 Support for Java 8 Date/Time Types](https://www.baeldung.com/jpa-java-time) - [Converting Between LocalDate and SQL Date](https://www.baeldung.com/java-convert-localdate-sql-date) +- [Combining JPA And/Or Criteria Predicates](https://www.baeldung.com/jpa-and-or-criteria-predicates) diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/entity/Item.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/entity/Item.java new file mode 100644 index 0000000000..64ef46f265 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/entity/Item.java @@ -0,0 +1,49 @@ +package com.baeldung.jpa.criteria.entity; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Table(name = "item") +@Entity +public class Item { + + @Id + private Long id; + private String color; + private String grade; + private String name; + + public String getColor() { + return color; + } + + public String getGrade() { + return grade; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setColor(String color) { + this.color = color; + } + + public void setGrade(String grade) { + this.grade = grade; + } + + public void setId(Long id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/CustomItemRepository.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/CustomItemRepository.java new file mode 100644 index 0000000000..c55dc4a592 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/CustomItemRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.jpa.criteria.repository; + +import java.util.List; + +import com.baeldung.jpa.criteria.entity.Item; + +public interface CustomItemRepository { + + List findItemsByColorAndGrade(); + + List findItemByColorOrGrade(); +} diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryImpl.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryImpl.java new file mode 100644 index 0000000000..bf1d3eed0b --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryImpl.java @@ -0,0 +1,77 @@ +package com.baeldung.jpa.criteria.repository.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import com.baeldung.jpa.criteria.entity.Item; +import com.baeldung.jpa.criteria.repository.CustomItemRepository; + +public class CustomItemRepositoryImpl implements CustomItemRepository { + + private EntityManager entityManager; + + public CustomItemRepositoryImpl() { + super(); + EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa-h2-criteria"); + entityManager = factory.createEntityManager(); + } + + @Override + public List findItemsByColorAndGrade() { + + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Item.class); + Root itemRoot = criteriaQuery.from(Item.class); + + Predicate predicateForBlueColor = criteriaBuilder.equal(itemRoot.get("color"), "blue"); + Predicate predicateForRedColor = criteriaBuilder.equal(itemRoot.get("color"), "red"); + Predicate predicateForColor = criteriaBuilder.or(predicateForBlueColor, predicateForRedColor); + + Predicate predicateForGradeA = criteriaBuilder.equal(itemRoot.get("grade"), "A"); + Predicate predicateForGradeB = criteriaBuilder.equal(itemRoot.get("grade"), "B"); + Predicate predicateForGrade = criteriaBuilder.or(predicateForGradeA, predicateForGradeB); + + // final search filter + Predicate finalPredicate = criteriaBuilder.and(predicateForColor, predicateForGrade); + + criteriaQuery.where(finalPredicate); + + List items = entityManager.createQuery(criteriaQuery) + .getResultList(); + return items; + } + + @Override + public List findItemByColorOrGrade() { + + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Item.class); + Root itemRoot = criteriaQuery.from(Item.class); + + Predicate predicateForBlueColor = criteriaBuilder.equal(itemRoot.get("color"), "red"); + Predicate predicateForGradeA = criteriaBuilder.equal(itemRoot.get("grade"), "D"); + Predicate predicateForBlueColorAndGradeA = criteriaBuilder.and(predicateForBlueColor, predicateForGradeA); + + Predicate predicateForRedColor = criteriaBuilder.equal(itemRoot.get("color"), "blue"); + Predicate predicateForGradeB = criteriaBuilder.equal(itemRoot.get("grade"), "B"); + Predicate predicateForRedColorAndGradeB = criteriaBuilder.and(predicateForRedColor, predicateForGradeB); + + // final search filter + Predicate finalPredicate = criteriaBuilder.or(predicateForBlueColorAndGradeA, predicateForRedColorAndGradeB); + + criteriaQuery.where(finalPredicate); + + List items = entityManager.createQuery(criteriaQuery) + .getResultList(); + return items; + } +} diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/QueryTypesExamples.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/QueryTypesExamples.java new file mode 100644 index 0000000000..523fc348f9 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/QueryTypesExamples.java @@ -0,0 +1,69 @@ +package com.baeldung.jpa.querytypes; + +import java.util.HashMap; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.Query; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +/** + * JPA Query Types examples. All using the UserEntity class. + * + * @author Rodolfo Felipe + */ +public class QueryTypesExamples { + + EntityManagerFactory emf; + + public QueryTypesExamples() { + Map properties = new HashMap(); + properties.put("hibernate.show_sql", "true"); + properties.put("hibernate.format_sql", "true"); + emf = Persistence.createEntityManagerFactory("jpa-query-types", properties); + } + + private EntityManager getEntityManager() { + return emf.createEntityManager(); + } + + public UserEntity getUserByIdWithPlainQuery(Long id) { + Query jpqlQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id"); + jpqlQuery.setParameter("id", id); + return (UserEntity) jpqlQuery.getSingleResult(); + } + + public UserEntity getUserByIdWithTypedQuery(Long id) { + TypedQuery typedQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id", UserEntity.class); + typedQuery.setParameter("id", id); + return typedQuery.getSingleResult(); + } + + public UserEntity getUserByIdWithNamedQuery(Long id) { + Query namedQuery = getEntityManager().createNamedQuery("UserEntity.findByUserId"); + namedQuery.setParameter("userId", id); + return (UserEntity) namedQuery.getSingleResult(); + } + + public UserEntity getUserByIdWithNativeQuery(Long id) { + Query nativeQuery = getEntityManager().createNativeQuery("SELECT * FROM users WHERE id=:userId", UserEntity.class); + nativeQuery.setParameter("userId", id); + return (UserEntity) nativeQuery.getSingleResult(); + } + + public UserEntity getUserByIdWithCriteriaQuery(Long id) { + CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class); + Root userRoot = criteriaQuery.from(UserEntity.class); + UserEntity queryResult = getEntityManager().createQuery(criteriaQuery.select(userRoot) + .where(criteriaBuilder.equal(userRoot.get("id"), id))) + .getSingleResult(); + return queryResult; + } + +} diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/UserEntity.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/UserEntity.java new file mode 100644 index 0000000000..1d4a231b31 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/querytypes/UserEntity.java @@ -0,0 +1,38 @@ +package com.baeldung.jpa.querytypes; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedQuery; +import javax.persistence.Table; + +/** + * User entity class. Used as an asset for JPA Query Types examples. + * + * @author Rodolfo Felipe + */ +@Table(name = "users") +@Entity +@NamedQuery(name = "UserEntity.findByUserId", query = "SELECT u FROM UserEntity u WHERE u.id=:userId") +public class UserEntity { + + @Id + private Long id; + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml index 8592fce533..5422afa4a3 100644 --- a/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml @@ -1,91 +1,133 @@ - - - - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.sqlresultsetmapping.ScheduledDay - com.baeldung.sqlresultsetmapping.Employee - true - - - - - - - - - - - - - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.stringcast.Message - true - - - - - - - - - - - - - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.model.Car - true - - - - - - - - - - - - com.baeldung.jpa.entitygraph.model.Post - com.baeldung.jpa.entitygraph.model.User - com.baeldung.jpa.entitygraph.model.Comment - true - - - - - - - - - - - - - org.eclipse.persistence.jpa.PersistenceProvider - com.baeldung.jpa.datetime.JPA22DateTimeEntity - true - - - - - - - - - - - - - - + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.sqlresultsetmapping.ScheduledDay + com.baeldung.sqlresultsetmapping.Employee + true + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.stringcast.Message + true + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.model.Car + true + + + + + + + + + + + + com.baeldung.jpa.entitygraph.model.Post + com.baeldung.jpa.entitygraph.model.User + com.baeldung.jpa.entitygraph.model.Comment + true + + + + + + + + + + + + + org.eclipse.persistence.jpa.PersistenceProvider + com.baeldung.jpa.datetime.JPA22DateTimeEntity + true + + + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.criteria.entity.Item + true + + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.querytypes.UserEntity + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryIntegrationTest.java b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryIntegrationTest.java new file mode 100644 index 0000000000..169fb44618 --- /dev/null +++ b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/criteria/repository/impl/CustomItemRepositoryIntegrationTest.java @@ -0,0 +1,44 @@ +package com.baeldung.jpa.criteria.repository.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import java.util.List; + +import org.junit.Test; + +import com.baeldung.jpa.criteria.entity.Item; +import com.baeldung.jpa.criteria.repository.CustomItemRepository; + +public class CustomItemRepositoryIntegrationTest { + + CustomItemRepository customItemRepository = new CustomItemRepositoryImpl(); + + @Test + public void givenItems_whenFindItemsByColorAndGrade_thenReturnItems() { + + List items = customItemRepository.findItemsByColorAndGrade(); + + assertFalse("No items found", items.isEmpty()); + assertEquals("There should be only one item", 1, items.size()); + + Item item = items.get(0); + + assertEquals("this item do not have blue color", "blue", item.getColor()); + assertEquals("this item does not belong to A grade", "A", item.getGrade()); + } + + @Test + public void givenItems_whenFindItemByColorOrGrade_thenReturnItems() { + + List items = customItemRepository.findItemByColorOrGrade(); + + assertFalse("No items found", items.isEmpty()); + assertEquals("There should be only one item", 1, items.size()); + + Item item = items.get(0); + + assertEquals("this item do not have red color", "red", item.getColor()); + assertEquals("this item does not belong to D grade", "D", item.getGrade()); + } +} diff --git a/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/querytypes/QueryTypesExamplesIntegrationTest.java b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/querytypes/QueryTypesExamplesIntegrationTest.java new file mode 100644 index 0000000000..4e854a464a --- /dev/null +++ b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/querytypes/QueryTypesExamplesIntegrationTest.java @@ -0,0 +1,65 @@ +package com.baeldung.jpa.querytypes; + +import org.junit.Assert; +import org.junit.Test; + +/** + * QueryTypesExamples class integration tests. + * + * @author Rodolfo Felipe + */ +public class QueryTypesExamplesIntegrationTest { + + QueryTypesExamples userDao = new QueryTypesExamples(); + + @Test + public void givenUserId_whenCallingPlaingQueryMethod_thenReturnExpectedUser() { + UserEntity firstUser = userDao.getUserByIdWithPlainQuery(1L); + Assert.assertNotNull("User not found", firstUser); + Assert.assertEquals("User should be baeldung", "baeldung", firstUser.getName()); + UserEntity lastUser = userDao.getUserByIdWithPlainQuery(4L); + Assert.assertNotNull("User not found", lastUser); + Assert.assertEquals("User should be baeldung", "batman", lastUser.getName()); + } + + @Test + public void givenUserId_whenCallingTypedQueryMethod_thenReturnExpectedUser() { + UserEntity firstUser = userDao.getUserByIdWithTypedQuery(1L); + Assert.assertNotNull("User not found", firstUser); + Assert.assertEquals("User should be baeldung", "baeldung", firstUser.getName()); + UserEntity lastUser = userDao.getUserByIdWithTypedQuery(4L); + Assert.assertNotNull("User not found", lastUser); + Assert.assertEquals("User should be baeldung", "batman", lastUser.getName()); + } + + @Test + public void givenUserId_whenCallingNamedQueryMethod_thenReturnExpectedUser() { + UserEntity firstUser = userDao.getUserByIdWithNamedQuery(1L); + Assert.assertNotNull("User not found", firstUser); + Assert.assertEquals("User should be baeldung", "baeldung", firstUser.getName()); + UserEntity lastUser = userDao.getUserByIdWithNamedQuery(4L); + Assert.assertNotNull("User not found", lastUser); + Assert.assertEquals("User should be baeldung", "batman", lastUser.getName()); + } + + @Test + public void givenUserId_whenCallingNativeQueryMethod_thenReturnExpectedUser() { + UserEntity firstUser = userDao.getUserByIdWithNativeQuery(1L); + Assert.assertNotNull("User not found", firstUser); + Assert.assertEquals("User should be baeldung", "baeldung", firstUser.getName()); + UserEntity lastUser = userDao.getUserByIdWithNativeQuery(4L); + Assert.assertNotNull("User not found", lastUser); + Assert.assertEquals("User should be baeldung", "batman", lastUser.getName()); + } + + @Test + public void givenUserId_whenCallingCriteriaApiMethod_thenReturnExpectedUser() { + UserEntity firstUser = userDao.getUserByIdWithCriteriaQuery(1L); + Assert.assertNotNull("User not found", firstUser); + Assert.assertEquals("User should be baeldung", "baeldung", firstUser.getName()); + UserEntity lastUser = userDao.getUserByIdWithCriteriaQuery(4L); + Assert.assertNotNull("User not found", lastUser); + Assert.assertEquals("User should be baeldung", "batman", lastUser.getName()); + } + +} diff --git a/persistence-modules/java-jpa/src/test/resources/item.sql b/persistence-modules/java-jpa/src/test/resources/item.sql new file mode 100644 index 0000000000..faf50f6829 --- /dev/null +++ b/persistence-modules/java-jpa/src/test/resources/item.sql @@ -0,0 +1,4 @@ +insert into item(id,grade,color) values (10,'C','blue'); +insert into item(id,grade,color) values (11,'C','red'); +insert into item(id,grade,color) values (12,'A','blue'); +insert into item(id,grade,color) values (13,'D','red'); \ No newline at end of file diff --git a/persistence-modules/java-jpa/src/test/resources/users.sql b/persistence-modules/java-jpa/src/test/resources/users.sql new file mode 100644 index 0000000000..227022e5df --- /dev/null +++ b/persistence-modules/java-jpa/src/test/resources/users.sql @@ -0,0 +1,4 @@ +INSERT INTO users(id,name) VALUES(1,'baeldung'); +INSERT INTO users(id,name) VALUES(2,'john doe'); +INSERT INTO users(id,name) VALUES(3,'jane doe'); +INSERT INTO users(id,name) VALUES(4,'batman'); diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml new file mode 100644 index 0000000000..47c733d8a7 --- /dev/null +++ b/persistence-modules/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + persistence-modules + persistence-modules + pom + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + .. + + + + activejdbc + apache-cayenne + core-java-persistence + deltaspike + flyway + hbase + hibernate5 + hibernate-ogm + influxdb + java-cassandra + java-cockroachdb + java-jdbi + java-jpa + java-mongodb + jnosql + liquibase + orientdb + querydsl + redis + solr + spring-boot-h2/spring-boot-h2-database + spring-boot-persistence + spring-boot-persistence-mongodb + spring-data-cassandra + spring-data-cassandra-reactive + spring-data-couchbase-2 + spring-data-dynamodb + spring-data-eclipselink + spring-data-elasticsearch + spring-data-gemfire + spring-data-jpa + spring-data-keyvalue + spring-data-mongodb + spring-data-neo4j + spring-data-redis + spring-data-solr + spring-hibernate-3 + spring-hibernate-5 + spring-hibernate4 + spring-jpa + + diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/pom.xml b/persistence-modules/spring-boot-h2/spring-boot-h2-database/pom.xml index a181360e2b..882b88b535 100644 --- a/persistence-modules/spring-boot-h2/spring-boot-h2-database/pom.xml +++ b/persistence-modules/spring-boot-h2/spring-boot-h2-database/pom.xml @@ -11,10 +11,10 @@ Demo Spring Boot applications that starts H2 in memory database - org.springframework.boot - spring-boot-starter-parent - 2.0.4.RELEASE - + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../../../parent-boot-2 @@ -48,6 +48,7 @@ 1.8 com.baeldung.h2db.demo.server.SpringBootApp + 2.0.4.RELEASE diff --git a/persistence-modules/spring-boot-persistence-mongodb/README.md b/persistence-modules/spring-boot-persistence-mongodb/README.md index f093d4baf0..40f9f40749 100644 --- a/persistence-modules/spring-boot-persistence-mongodb/README.md +++ b/persistence-modules/spring-boot-persistence-mongodb/README.md @@ -1,3 +1,4 @@ # Relevant Articles - [Auto-Generated Field for MongoDB using Spring Boot](https://www.baeldung.com/spring-boot-mongodb-auto-generated-field) +- [Spring Boot Integration Testing with Embedded MongoDB](http://www.baeldung.com/spring-boot-embedded-mongodb) diff --git a/persistence-modules/spring-boot-persistence-mongodb/pom.xml b/persistence-modules/spring-boot-persistence-mongodb/pom.xml index 86b93c7826..585e54bf57 100644 --- a/persistence-modules/spring-boot-persistence-mongodb/pom.xml +++ b/persistence-modules/spring-boot-persistence-mongodb/pom.xml @@ -25,6 +25,11 @@ org.springframework.boot spring-boot-starter-data-mongodb + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + test + org.junit.jupiter @@ -102,4 +107,4 @@ - \ No newline at end of file + diff --git a/persistence-modules/spring-boot-persistence-mongodb/src/main/java/com/baeldung/mongodb/events/UserModelListener.java b/persistence-modules/spring-boot-persistence-mongodb/src/main/java/com/baeldung/mongodb/events/UserModelListener.java index 24b53f3d2d..2fe81f7ef4 100644 --- a/persistence-modules/spring-boot-persistence-mongodb/src/main/java/com/baeldung/mongodb/events/UserModelListener.java +++ b/persistence-modules/spring-boot-persistence-mongodb/src/main/java/com/baeldung/mongodb/events/UserModelListener.java @@ -21,7 +21,9 @@ public class UserModelListener extends AbstractMongoEventListener { @Override public void onBeforeConvert(BeforeConvertEvent event) { - event.getSource().setId(sequenceGenerator.generateSequence(User.SEQUENCE_NAME)); + if (event.getSource().getId() < 1) { + event.getSource().setId(sequenceGenerator.generateSequence(User.SEQUENCE_NAME)); + } } diff --git a/spring-boot/src/test/java/com/baeldung/mongodb/ManualEmbeddedMongoDbIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb/src/test/java/com/baeldung/mongodb/ManualEmbeddedMongoDbIntegrationTest.java similarity index 100% rename from spring-boot/src/test/java/com/baeldung/mongodb/ManualEmbeddedMongoDbIntegrationTest.java rename to persistence-modules/spring-boot-persistence-mongodb/src/test/java/com/baeldung/mongodb/ManualEmbeddedMongoDbIntegrationTest.java diff --git a/spring-boot/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java similarity index 90% rename from spring-boot/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java rename to persistence-modules/spring-boot-persistence-mongodb/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java index 39127f62e9..954bae3684 100644 --- a/spring-boot/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence-mongodb/src/test/java/com/baeldung/mongodb/MongoDbSpringIntegrationTest.java @@ -2,7 +2,6 @@ package com.baeldung.mongodb; import static org.assertj.core.api.Assertions.assertThat; -import org.baeldung.boot.Application; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -12,10 +11,11 @@ import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; +import com.baeldung.SpringBootPersistenceApplication; import com.mongodb.BasicDBObjectBuilder; import com.mongodb.DBObject; -@ContextConfiguration(classes = Application.class) +@ContextConfiguration(classes = SpringBootPersistenceApplication.class) @DataMongoTest @ExtendWith(SpringExtension.class) public class MongoDbSpringIntegrationTest { diff --git a/persistence-modules/spring-boot-persistence/README.MD b/persistence-modules/spring-boot-persistence/README.MD index 6fe5e6f05f..ee7c2e298e 100644 --- a/persistence-modules/spring-boot-persistence/README.MD +++ b/persistence-modules/spring-boot-persistence/README.MD @@ -2,8 +2,9 @@ - [Spring Boot with Multiple SQL Import Files](http://www.baeldung.com/spring-boot-sql-import-files) - [Configuring Separate Spring DataSource for Tests](http://www.baeldung.com/spring-testing-separate-data-source) -- [Quick Guide on data.sql and schema.sql Files in Spring Boot](http://www.baeldung.com/spring-boot-data-sql-and-schema-sql) +- [Quick Guide on Loading Initial Data with Spring Boot](http://www.baeldung.com/spring-boot-data-sql-and-schema-sql) - [Configuring a Tomcat Connection Pool in Spring Boot](https://www.baeldung.com/spring-boot-tomcat-connection-pool) - [Hibernate Field Naming with Spring Boot](https://www.baeldung.com/hibernate-field-naming-spring-boot) - [Integrating Spring Boot with HSQLDB](https://www.baeldung.com/spring-boot-hsqldb) - [Configuring a DataSource Programmatically in Spring Boot](https://www.baeldung.com/spring-boot-configure-data-source-programmatic) +- [Resolving “Failed to Configure a DataSource” Error](https://www.baeldung.com/spring-boot-failed-to-configure-data-source) diff --git a/persistence-modules/spring-boot-persistence/pom.xml b/persistence-modules/spring-boot-persistence/pom.xml index d9d3a9f9b7..ca7c7306e7 100644 --- a/persistence-modules/spring-boot-persistence/pom.xml +++ b/persistence-modules/spring-boot-persistence/pom.xml @@ -25,6 +25,12 @@ org.springframework.boot spring-boot-starter-data-jpa + + + com.zaxxer + HikariCP + + org.springframework.boot @@ -48,6 +54,11 @@ mysql mysql-connector-java + + javax.validation + validation-api + ${validation-api.version} + @@ -73,6 +84,7 @@ 9.0.10 1.4.197 2.23.0 + 2.0.1.Final diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/Application.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/Application.java similarity index 93% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/Application.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/Application.java index 43888c2d67..cb0d0c1532 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/Application.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/Application.java @@ -1,4 +1,4 @@ -package com.baeldung; +package com.baeldung.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Car.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Car.java new file mode 100644 index 0000000000..736c12fb07 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Car.java @@ -0,0 +1,48 @@ +package com.baeldung.boot.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author paullatzelsperger + * @since 2019-03-20 + */ +@Entity +public class Car { + + @Id + @GeneratedValue + private int id; + private Integer power; + private String model; + + public Car() { + + } + + public Car(int power, String model) { + this.power = power; + this.model = model; + } + + public Integer getPower() { + return power; + } + + public void setPower(Integer power) { + this.power = power; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public int getId() { + return id; + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/Country.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Country.java similarity index 94% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/Country.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Country.java index e6a88c7121..59227f6412 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/Country.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/Country.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import static javax.persistence.GenerationType.IDENTITY; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/User.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/User.java similarity index 96% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/User.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/User.java index 9d1fc4c8ad..bdbe75cd0c 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/domain/User.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/domain/User.java @@ -1,4 +1,4 @@ -package com.baeldung.domain; +package com.baeldung.boot.domain; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/HibernateConfig.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/HibernateConfig.java similarity index 95% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/HibernateConfig.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/HibernateConfig.java index 897e34d406..adde46e2b6 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/HibernateConfig.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/HibernateConfig.java @@ -1,4 +1,4 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; import org.hibernate.jpa.boot.spi.IntegratorProvider; import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/MetadataExtractorIntegrator.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/MetadataExtractorIntegrator.java similarity index 97% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/MetadataExtractorIntegrator.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/MetadataExtractorIntegrator.java index 24b5cdea64..8702624d3f 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/MetadataExtractorIntegrator.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/MetadataExtractorIntegrator.java @@ -1,4 +1,4 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.Database; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Account.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Account.java similarity index 90% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Account.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Account.java index 6145818c5b..00e90a5ec9 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Account.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Account.java @@ -1,4 +1,4 @@ -package com.baeldung.naming.entity; +package com.baeldung.boot.naming.entity; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Preference.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Preference.java similarity index 84% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Preference.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Preference.java index 928884a2c5..7711156864 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/naming/entity/Preference.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/naming/entity/Preference.java @@ -1,4 +1,4 @@ -package com.baeldung.naming.entity; +package com.baeldung.boot.naming.entity; import javax.persistence.Entity; import javax.persistence.Id; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/CarRepository.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/CarRepository.java new file mode 100644 index 0000000000..0176b14169 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/CarRepository.java @@ -0,0 +1,26 @@ +package com.baeldung.boot.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import com.baeldung.boot.domain.Car; + +/** + * @author paullatzelsperger + * @since 2019-03-20 + */ +@Repository +public interface CarRepository extends JpaRepository { + + boolean existsCarByPower(int power); + + boolean existsCarByModel(String model); + + @Query("select case when count(c)> 0 then true else false end from Car c where c.model = :model") + boolean existsCarExactCustomQuery(@Param("model") String model); + + @Query("select case when count(c)> 0 then true else false end from Car c where lower(c.model) like lower(:model)") + boolean existsCarLikeCustomQuery(@Param("model") String model); +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/repository/UserRepository.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/UserRepository.java similarity index 97% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/repository/UserRepository.java rename to persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/UserRepository.java index bdc1e0af33..eae80b2e92 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/repository/UserRepository.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/repository/UserRepository.java @@ -1,6 +1,5 @@ -package com.baeldung.repository; +package com.baeldung.boot.repository; -import com.baeldung.domain.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -11,6 +10,8 @@ import org.springframework.data.repository.query.Param; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Repository; +import com.baeldung.boot.domain.User; + import java.util.Collection; import java.util.List; import java.util.Optional; diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/disabledatasource/application/Application.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/disabledatasource/application/Application.java new file mode 100644 index 0000000000..79273ba141 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/disabledatasource/application/Application.java @@ -0,0 +1,13 @@ +package com.baeldung.disabledatasource.application; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +@SpringBootApplication(exclude=DataSourceAutoConfiguration.class) +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/ExampleApplication.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/ExampleApplication.java new file mode 100644 index 0000000000..4b6a93ab8b --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/ExampleApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.springboothibernate.application; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ExampleApplication { + + public static void main(String[] args) { + SpringApplication.run(ExampleApplication.class, args); + } + +} + diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/datasources/DataSourceBean.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/datasources/DataSourceBean.java new file mode 100644 index 0000000000..54a0c4f077 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/datasources/DataSourceBean.java @@ -0,0 +1,21 @@ +package com.baeldung.springboothibernate.application.datasources; + +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceBean { + + @Bean + public DataSource getDataSource() { + DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); + dataSourceBuilder.driverClassName("org.h2.Driver"); + dataSourceBuilder.url("jdbc:h2:mem:test"); + dataSourceBuilder.username("SA"); + dataSourceBuilder.password(""); + return dataSourceBuilder.build(); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/models/Book.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/models/Book.java new file mode 100644 index 0000000000..7562c072c7 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/models/Book.java @@ -0,0 +1,40 @@ +package com.baeldung.springboothibernate.application.models; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Book { + + @Id + @GeneratedValue + private Long id; + private String name; + + public Book() { + super(); + } + + public Book(Long id, String name) { + super(); + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/repositories/BookRepository.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/repositories/BookRepository.java new file mode 100644 index 0000000000..3d5789fb4d --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/repositories/BookRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.springboothibernate.application.repositories; + +import com.baeldung.springboothibernate.application.models.Book; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface BookRepository extends JpaRepository { +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/services/BookService.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/services/BookService.java new file mode 100644 index 0000000000..e495045bab --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothibernate/application/services/BookService.java @@ -0,0 +1,19 @@ +package com.baeldung.springboothibernate.application.services; + +import com.baeldung.springboothibernate.application.models.Book; +import com.baeldung.springboothibernate.application.repositories.BookRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class BookService { + + @Autowired + private BookRepository bookRepository; + + public List list() { + return bookRepository.findAll(); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/resources/application.properties b/persistence-modules/spring-boot-persistence/src/main/resources/application.properties index b0caf4a809..7b5a467a2b 100644 --- a/persistence-modules/spring-boot-persistence/src/main/resources/application.properties +++ b/persistence-modules/spring-boot-persistence/src/main/resources/application.properties @@ -3,3 +3,9 @@ spring.datasource.url = jdbc:hsqldb:mem:test;DB_CLOSE_DELAY=-1 spring.datasource.username = sa spring.datasource.password = spring.jpa.hibernate.ddl-auto = create + +# Enabling H2 Console +spring.h2.console.enabled=true + +# Uppercase Table Names +spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java index ecacf62285..01082cc6e2 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java @@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import com.baeldung.boot.Application; import com.baeldung.boot.config.H2JpaConfig; import com.baeldung.boot.domain.GenericEntity; import com.baeldung.boot.repository.GenericEntityRepository; diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootJPAIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootJPAIntegrationTest.java index 01fae2fb4d..f1ab442949 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootJPAIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootJPAIntegrationTest.java @@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +import com.baeldung.boot.Application; import com.baeldung.boot.domain.GenericEntity; import com.baeldung.boot.repository.GenericEntityRepository; diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java index 65a75d7bfe..0227458987 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java @@ -10,12 +10,13 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; +import com.baeldung.boot.Application; +import com.baeldung.boot.config.H2JpaConfig; import com.baeldung.boot.domain.GenericEntity; import com.baeldung.boot.repository.GenericEntityRepository; -import com.baeldung.config.H2TestProfileJPAConfig; @RunWith(SpringRunner.class) -@SpringBootTest(classes = { Application.class, H2TestProfileJPAConfig.class }) +@SpringBootTest(classes = { Application.class, H2JpaConfig.class }) @ActiveProfiles("test") public class SpringBootProfileIntegrationTest { @Autowired diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/LegacyJpaImplNamingIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/LegacyJpaImplNamingIntegrationTest.java similarity index 90% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/LegacyJpaImplNamingIntegrationTest.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/LegacyJpaImplNamingIntegrationTest.java index e68be3bed8..2feee10980 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/LegacyJpaImplNamingIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/LegacyJpaImplNamingIntegrationTest.java @@ -1,6 +1,5 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; -import com.baeldung.naming.entity.Account; import org.assertj.core.api.SoftAssertions; import org.hibernate.boot.Metadata; import org.hibernate.mapping.PersistentClass; @@ -8,15 +7,20 @@ import org.hibernate.mapping.Table; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; +import com.baeldung.boot.naming.NamingConfig.Config; +import com.baeldung.boot.naming.entity.Account; + @RunWith(SpringRunner.class) @DataJpaTest @TestPropertySource(properties = { "spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl", "spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl" }) +@Import(Config.class) public class LegacyJpaImplNamingIntegrationTest extends NamingConfig { @Test diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/NamingConfig.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/NamingConfig.java similarity index 92% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/NamingConfig.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/NamingConfig.java index c3ef37aeb4..9b6574b1d7 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/NamingConfig.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/NamingConfig.java @@ -1,4 +1,4 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; import org.springframework.boot.test.context.TestConfiguration; diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/SpringBootDefaultNamingIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/SpringBootDefaultNamingIntegrationTest.java similarity index 90% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/SpringBootDefaultNamingIntegrationTest.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/SpringBootDefaultNamingIntegrationTest.java index 089430aabb..c5c320f70c 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/SpringBootDefaultNamingIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/SpringBootDefaultNamingIntegrationTest.java @@ -1,6 +1,5 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; -import com.baeldung.naming.entity.Account; import org.assertj.core.api.SoftAssertions; import org.hibernate.boot.Metadata; import org.hibernate.mapping.PersistentClass; @@ -8,10 +7,12 @@ import org.hibernate.mapping.Table; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; -import static org.assertj.core.api.Assertions.assertThat; +import com.baeldung.boot.naming.NamingConfig.Config; +import com.baeldung.boot.naming.entity.Account; @RunWith(SpringRunner.class) @DataJpaTest @@ -19,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; "spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy", "spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy" }) +@Import(Config.class) public class SpringBootDefaultNamingIntegrationTest extends NamingConfig { @Test diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/StrategyLegacyHbmImplIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/StrategyLegacyHbmImplIntegrationTest.java similarity index 88% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/StrategyLegacyHbmImplIntegrationTest.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/StrategyLegacyHbmImplIntegrationTest.java index 046755d9bc..ef978e5a98 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/naming/StrategyLegacyHbmImplIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/naming/StrategyLegacyHbmImplIntegrationTest.java @@ -1,6 +1,9 @@ -package com.baeldung.naming; +package com.baeldung.boot.naming; + +import com.baeldung.boot.naming.MetadataExtractorIntegrator; +import com.baeldung.boot.naming.NamingConfig.Config; +import com.baeldung.boot.naming.entity.Preference; -import com.baeldung.naming.entity.Preference; import org.assertj.core.api.SoftAssertions; import org.hibernate.boot.Metadata; import org.hibernate.mapping.PersistentClass; @@ -8,6 +11,7 @@ import org.hibernate.mapping.Table; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; @@ -19,6 +23,7 @@ import java.util.Collection; "spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl", "spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl", }) +@Import(Config.class) public class StrategyLegacyHbmImplIntegrationTest extends NamingConfig { @Test diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/repository/UserRepositoryIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/test/UserRepositoryMultipleSqlFilesIntTest.java similarity index 66% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/repository/UserRepositoryIntegrationTest.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/test/UserRepositoryMultipleSqlFilesIntTest.java index af5abc22d7..f1f6e85d8c 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/repository/UserRepositoryIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/boot/test/UserRepositoryMultipleSqlFilesIntTest.java @@ -1,12 +1,15 @@ -package com.baeldung.repository; +package com.baeldung.boot.test; -import com.baeldung.domain.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; +import com.baeldung.boot.domain.User; +import com.baeldung.boot.repository.UserRepository; + import java.util.Collection; import static org.assertj.core.api.Assertions.assertThat; @@ -16,7 +19,8 @@ import static org.assertj.core.api.Assertions.assertThat; */ @RunWith(SpringRunner.class) @DataJpaTest -public class UserRepositoryIntegrationTest { +@ActiveProfiles("multiplesqlfiles") +public class UserRepositoryMultipleSqlFilesIntTest { @Autowired private UserRepository userRepository; @@ -24,7 +28,7 @@ public class UserRepositoryIntegrationTest { public void givenTwoImportFilesWhenFindAllShouldReturnSixUsers() { Collection users = userRepository.findAll(); - assertThat(users.size()).isEqualTo(9); + assertThat(users.size()).isEqualTo(6); } } diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java index bcbded95fb..e0678bcf47 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java @@ -41,7 +41,7 @@ public class H2TestProfileJPAConfig { public LocalContainerEntityManagerFactoryBean entityManagerFactory() { final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource()); - em.setPackagesToScan(new String[] { "com.baeldung.domain", "com.baeldung.boot.domain" }); + em.setPackagesToScan(new String[] { "com.baeldung.boot.domain" }); em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); em.setJpaProperties(additionalProperties()); return em; diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/exists/CarRepositoryIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/exists/CarRepositoryIntegrationTest.java new file mode 100644 index 0000000000..f9a48a7e66 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/exists/CarRepositoryIntegrationTest.java @@ -0,0 +1,90 @@ +package com.baeldung.exists; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.ignoreCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.Application; +import com.baeldung.boot.domain.Car; +import com.baeldung.boot.repository.CarRepository; + +import java.util.Arrays; +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {Application.class}) +public class CarRepositoryIntegrationTest { + + @Autowired + private CarRepository repository; + private int searchId; + + @Before + public void setup() { + List cars = repository.saveAll(Arrays.asList(new Car(200, "BMW"), new Car(300, "Audi"))); + searchId = cars.get(0).getId(); + } + + @After + public void teardown() { + repository.deleteAll(); + } + + @Test + public void whenIdIsCorrect_thenExistsShouldReturnTrue() { + assertThat(repository.existsById(searchId)).isTrue(); + } + + @Test + public void givenExample_whenExists_thenIsTrue() { + ExampleMatcher modelMatcher = ExampleMatcher.matching() + .withIgnorePaths("id") // must explicitly ignore -> PK + .withMatcher("model", ignoreCase()); + Car probe = new Car(); + probe.setModel("bmw"); + + Example example = Example.of(probe, modelMatcher); + + assertThat(repository.exists(example)).isTrue(); + } + + @Test + public void givenPower_whenExists_thenIsFalse() { + assertThat(repository.existsCarByPower(200)).isTrue(); + assertThat(repository.existsCarByPower(800)).isFalse(); + } + + @Test + public void existsByDerivedQuery_byModel() { + assertThat(repository.existsCarByModel("Audi")).isTrue(); + assertThat(repository.existsCarByModel("audi")).isFalse(); + assertThat(repository.existsCarByModel("AUDI")).isFalse(); + assertThat(repository.existsCarByModel("")).isFalse(); + } + + @Test + public void givenModelName_whenExistsExact_thenIsTrue() { + assertThat(repository.existsCarExactCustomQuery("BMW")).isTrue(); + assertThat(repository.existsCarExactCustomQuery("Bmw")).isFalse(); + assertThat(repository.existsCarExactCustomQuery("bmw")).isFalse(); + assertThat(repository.existsCarExactCustomQuery("")).isFalse(); + } + + @Test + public void givenModelName_whenExistsLike_thenIsTrue() { + assertThat(repository.existsCarLikeCustomQuery("BMW")).isTrue(); + assertThat(repository.existsCarLikeCustomQuery("Bmw")).isTrue(); + assertThat(repository.existsCarLikeCustomQuery("bmw")).isTrue(); + assertThat(repository.existsCarLikeCustomQuery("")).isFalse(); + } + +} diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/tests/UserRepositoryIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/application/tests/UserRepositoryIntegrationTest.java similarity index 79% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/tests/UserRepositoryIntegrationTest.java rename to persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/application/tests/UserRepositoryIntegrationTest.java index f27681021e..e9824fce44 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/tests/UserRepositoryIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springbootdatasourceconfig/application/tests/UserRepositoryIntegrationTest.java @@ -1,15 +1,17 @@ -package com.baeldung.springbootdatasourceconfig.tests; +package com.baeldung.springbootdatasourceconfig.application.tests; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.junit4.SpringRunner; import com.baeldung.springbootdatasourceconfig.application.entities.User; import com.baeldung.springbootdatasourceconfig.application.repositories.UserRepository; -import java.util.List; -import java.util.Optional; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; -import static org.assertj.core.api.Assertions.assertThat; -import org.junit.runner.RunWith; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @DataJpaTest @@ -23,6 +25,7 @@ public class UserRepositoryIntegrationTest { userRepository.save(new User("Bob", "bob@domain.com")); List users = (List) userRepository.findAll(); - assertThat(users.size()).isEqualTo(1); + // 2 additional users are saved in the CommandLineRunner bean + assertThat(users.size()).isEqualTo(3); } } diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springboothibernate/application/tests/BookServiceUnitTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springboothibernate/application/tests/BookServiceUnitTest.java new file mode 100644 index 0000000000..655a852001 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springboothibernate/application/tests/BookServiceUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.springboothibernate.application.tests; + +import com.baeldung.springboothibernate.application.models.Book; +import com.baeldung.springboothibernate.application.services.BookService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class BookServiceUnitTest { + + @Autowired + private BookService bookService; + + @Test + public void whenApplicationStarts_thenHibernateCreatesInitialRecords() { + List books = bookService.list(); + + Assert.assertEquals(books.size(), 3); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java index eb000bbc09..5400d76fbe 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java @@ -5,11 +5,14 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.tomcatconnectionpool.application.SpringBootConsoleApplication; + import static org.assertj.core.api.Assertions.*; import org.springframework.boot.test.context.SpringBootTest; @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(classes = {SpringBootConsoleApplication.class}) public class SpringBootTomcatConnectionPoolIntegrationTest { @Autowired diff --git a/persistence-modules/spring-boot-persistence/src/test/resources/application-multiplesqlfiles.properties b/persistence-modules/spring-boot-persistence/src/test/resources/application-multiplesqlfiles.properties new file mode 100644 index 0000000000..06efc25f38 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/test/resources/application-multiplesqlfiles.properties @@ -0,0 +1 @@ +spring.jpa.properties.hibernate.hbm2ddl.import_files=import_active_users.sql,import_inactive_users.sql \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence/src/test/resources/application.properties b/persistence-modules/spring-boot-persistence/src/test/resources/application.properties index a5c1d983cf..3a6470c8dc 100644 --- a/persistence-modules/spring-boot-persistence/src/test/resources/application.properties +++ b/persistence-modules/spring-boot-persistence/src/test/resources/application.properties @@ -12,5 +12,5 @@ hibernate.cache.use_second_level_cache=true hibernate.cache.use_query_cache=true hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory -spring.jpa.properties.hibernate.hbm2ddl.import_files=migrated_users.sql +spring.jpa.properties.hibernate.hbm2ddl.import_files=migrated_users.sql, import_books.sql spring.datasource.data=import_*_users.sql \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence/src/test/resources/import_books.sql b/persistence-modules/spring-boot-persistence/src/test/resources/import_books.sql new file mode 100644 index 0000000000..8eaf972a00 --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/test/resources/import_books.sql @@ -0,0 +1,3 @@ +insert into book values(1, 'The Tartar Steppe'); +insert into book values(2, 'Poem Strip'); +insert into book values(3, 'Restless Nights: Selected Stories of Dino Buzzati'); \ No newline at end of file diff --git a/persistence-modules/spring-data-couchbase-2/README.md b/persistence-modules/spring-data-couchbase-2/README.md index 2e56b25fef..2b6a1faddf 100644 --- a/persistence-modules/spring-data-couchbase-2/README.md +++ b/persistence-modules/spring-data-couchbase-2/README.md @@ -1,7 +1,7 @@ ## Spring Data Couchbase Tutorial Project ### Relevant Articles: -- [Spring Data Couchbase](http://www.baeldung.com/spring-data-couchbase) +- [Intro to Spring Data Couchbase](http://www.baeldung.com/spring-data-couchbase) - [Entity Validation, Query Consistency, and Optimistic Locking in Spring Data Couchbase](http://www.baeldung.com/entity-validation-locking-and-query-consistency-in-spring-data-couchbase) - [Multiple Buckets and Spatial View Queries in Spring Data Couchbase](http://www.baeldung.com/spring-data-couchbase-buckets-and-spatial-view-queries) diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/SpringContextLiveTest.java similarity index 95% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/SpringContextLiveTest.java index 9c9d58dd0b..af228735b8 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -12,7 +12,7 @@ import org.springframework.test.context.support.DependencyInjectionTestExecution @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { MultiBucketCouchbaseConfig.class, MultiBucketIntegrationTestConfig.class }) @TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class }) -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonRepositoryServiceIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonRepositoryServiceLiveTest.java similarity index 78% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonRepositoryServiceIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonRepositoryServiceLiveTest.java index d710e57def..899c21691d 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonRepositoryServiceIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonRepositoryServiceLiveTest.java @@ -3,7 +3,7 @@ package org.baeldung.spring.data.couchbase.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -public class PersonRepositoryServiceIntegrationTest extends PersonServiceIntegrationTest { +public class PersonRepositoryServiceLiveTest extends PersonServiceLiveTest { @Autowired @Qualifier("PersonRepositoryService") diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonServiceIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonServiceLiveTest.java similarity index 98% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonServiceIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonServiceLiveTest.java index 4044183849..08d641dc2c 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonServiceIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonServiceLiveTest.java @@ -20,7 +20,7 @@ import com.couchbase.client.java.CouchbaseCluster; import com.couchbase.client.java.document.JsonDocument; import com.couchbase.client.java.document.json.JsonObject; -public abstract class PersonServiceIntegrationTest extends IntegrationTest { +public abstract class PersonServiceLiveTest extends IntegrationTest { static final String typeField = "_class"; static final String john = "John"; diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonTemplateServiceIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonTemplateServiceLiveTest.java similarity index 79% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonTemplateServiceIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonTemplateServiceLiveTest.java index e19df8fc84..3bc99d28df 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonTemplateServiceIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/PersonTemplateServiceLiveTest.java @@ -3,7 +3,7 @@ package org.baeldung.spring.data.couchbase.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -public class PersonTemplateServiceIntegrationTest extends PersonServiceIntegrationTest { +public class PersonTemplateServiceLiveTest extends PersonServiceLiveTest { @Autowired @Qualifier("PersonTemplateService") diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentRepositoryServiceIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentRepositoryServiceLiveTest.java similarity index 78% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentRepositoryServiceIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentRepositoryServiceLiveTest.java index 3b3f2a531a..162619db3e 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentRepositoryServiceIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentRepositoryServiceLiveTest.java @@ -3,7 +3,7 @@ package org.baeldung.spring.data.couchbase.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -public class StudentRepositoryServiceIntegrationTest extends StudentServiceIntegrationTest { +public class StudentRepositoryServiceLiveTest extends StudentServiceLiveTest { @Autowired @Qualifier("StudentRepositoryService") diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentServiceIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentServiceLiveTest.java similarity index 98% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentServiceIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentServiceLiveTest.java index fba549a9e5..6a18922007 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentServiceIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentServiceLiveTest.java @@ -22,7 +22,7 @@ import com.couchbase.client.java.CouchbaseCluster; import com.couchbase.client.java.document.JsonDocument; import com.couchbase.client.java.document.json.JsonObject; -public abstract class StudentServiceIntegrationTest extends IntegrationTest { +public abstract class StudentServiceLiveTest extends IntegrationTest { static final String typeField = "_class"; static final String joe = "Joe"; diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentTemplateServiceIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentTemplateServiceLiveTest.java similarity index 79% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentTemplateServiceIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentTemplateServiceLiveTest.java index 29fd605bc6..c666e004af 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentTemplateServiceIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase/service/StudentTemplateServiceLiveTest.java @@ -3,7 +3,7 @@ package org.baeldung.spring.data.couchbase.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -public class StudentTemplateServiceIntegrationTest extends StudentServiceIntegrationTest { +public class StudentTemplateServiceLiveTest extends StudentServiceLiveTest { @Autowired @Qualifier("StudentTemplateService") diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/MultiBucketIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/MultiBucketLiveTest.java similarity index 92% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/MultiBucketIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/MultiBucketLiveTest.java index 05ba58d616..3b406a851e 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/MultiBucketIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/MultiBucketLiveTest.java @@ -9,6 +9,6 @@ import org.springframework.test.context.support.DependencyInjectionTestExecution @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { MultiBucketCouchbaseConfig.class, MultiBucketIntegrationTestConfig.class }) @TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class }) -public abstract class MultiBucketIntegrationTest { +public abstract class MultiBucketLiveTest { } diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/CampusServiceImplIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/CampusServiceImplLiveTest.java similarity index 96% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/CampusServiceImplIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/CampusServiceImplLiveTest.java index 0996b252f1..5e7a12f292 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/CampusServiceImplIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/CampusServiceImplLiveTest.java @@ -10,7 +10,7 @@ import java.util.Set; import javax.annotation.PostConstruct; import org.baeldung.spring.data.couchbase.model.Campus; -import org.baeldung.spring.data.couchbase2b.MultiBucketIntegrationTest; +import org.baeldung.spring.data.couchbase2b.MultiBucketLiveTest; import org.baeldung.spring.data.couchbase2b.repos.CampusRepository; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -18,7 +18,7 @@ import org.springframework.data.geo.Distance; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; -public class CampusServiceImplIntegrationTest extends MultiBucketIntegrationTest { +public class CampusServiceImplLiveTest extends MultiBucketLiveTest { @Autowired private CampusServiceImpl campusService; diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/PersonServiceImplIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/PersonServiceImplLiveTest.java similarity index 96% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/PersonServiceImplIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/PersonServiceImplLiveTest.java index 45475e50f6..9543d8fe12 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/PersonServiceImplIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/PersonServiceImplLiveTest.java @@ -9,7 +9,7 @@ import java.util.List; import org.baeldung.spring.data.couchbase.model.Person; import org.baeldung.spring.data.couchbase2b.MultiBucketCouchbaseConfig; -import org.baeldung.spring.data.couchbase2b.MultiBucketIntegrationTest; +import org.baeldung.spring.data.couchbase2b.MultiBucketLiveTest; import org.joda.time.DateTime; import org.junit.BeforeClass; import org.junit.Test; @@ -21,7 +21,7 @@ import com.couchbase.client.java.CouchbaseCluster; import com.couchbase.client.java.document.JsonDocument; import com.couchbase.client.java.document.json.JsonObject; -public class PersonServiceImplIntegrationTest extends MultiBucketIntegrationTest { +public class PersonServiceImplLiveTest extends MultiBucketLiveTest { static final String typeField = "_class"; static final String john = "John"; diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/StudentServiceImplIntegrationTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/StudentServiceImplLiveTest.java similarity index 97% rename from persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/StudentServiceImplIntegrationTest.java rename to persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/StudentServiceImplLiveTest.java index e7c1eab92a..52b9113e8f 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/StudentServiceImplIntegrationTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/spring/data/couchbase2b/service/StudentServiceImplLiveTest.java @@ -11,7 +11,7 @@ import javax.validation.ConstraintViolationException; import org.baeldung.spring.data.couchbase.model.Student; import org.baeldung.spring.data.couchbase2b.MultiBucketCouchbaseConfig; -import org.baeldung.spring.data.couchbase2b.MultiBucketIntegrationTest; +import org.baeldung.spring.data.couchbase2b.MultiBucketLiveTest; import org.joda.time.DateTime; import org.junit.BeforeClass; import org.junit.Test; @@ -23,7 +23,7 @@ import com.couchbase.client.java.CouchbaseCluster; import com.couchbase.client.java.document.JsonDocument; import com.couchbase.client.java.document.json.JsonObject; -public class StudentServiceImplIntegrationTest extends MultiBucketIntegrationTest { +public class StudentServiceImplLiveTest extends MultiBucketLiveTest { static final String typeField = "_class"; static final String joe = "Joe"; diff --git a/persistence-modules/spring-data-jpa-2/README.md b/persistence-modules/spring-data-jpa-2/README.md new file mode 100644 index 0000000000..295a434d17 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/README.md @@ -0,0 +1,5 @@ +========= + +## Spring Data JPA Example Project + +### Relevant Articles: diff --git a/persistence-modules/spring-data-jpa-2/pom.xml b/persistence-modules/spring-data-jpa-2/pom.xml new file mode 100644 index 0000000000..8e46112659 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + com.baeldung + spring-data-jpa-2 + spring-data-jpa + + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + + + + + \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/Application.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..3ea3d113da --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/Application.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Fruit.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Fruit.java new file mode 100644 index 0000000000..f82022e67e --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Fruit.java @@ -0,0 +1,38 @@ +package com.baeldung.entity; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Fruit { + + @Id + private long id; + private String name; + private String color; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Song.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Song.java new file mode 100644 index 0000000000..395527c1eb --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/entity/Song.java @@ -0,0 +1,75 @@ +package com.baeldung.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import java.time.LocalDateTime; + +@Entity +public class Song { + + @Id private long id; + private String name; + @Column(name = "length_in_seconds") + private int lengthInSeconds; + private String compositor; + private String singer; + private LocalDateTime released; + private String genre; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getLengthInSeconds() { + return lengthInSeconds; + } + + public void setLengthInSeconds(int lengthInSeconds) { + this.lengthInSeconds = lengthInSeconds; + } + + public String getCompositor() { + return compositor; + } + + public void setCompositor(String compositor) { + this.compositor = compositor; + } + + public String getSinger() { + return singer; + } + + public void setSinger(String singer) { + this.singer = singer; + } + + public LocalDateTime getReleased() { + return released; + } + + public void setReleased(LocalDateTime released) { + this.released = released; + } + + public String getGenre() { + return genre; + } + + public void setGenre(String genre) { + this.genre = genre; + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/FruitRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/FruitRepository.java new file mode 100644 index 0000000000..9f92909b66 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/FruitRepository.java @@ -0,0 +1,27 @@ +package com.baeldung.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import com.baeldung.entity.Fruit; + +@Repository +public interface FruitRepository extends JpaRepository { + + Long deleteByName(String name); + + List deleteByColor(String color); + + Long removeByName(String name); + + List removeByColor(String color); + + @Modifying + @Query("delete from Fruit f where f.name=:name or f.color=:color") + List deleteFruits(@Param("name") String name, @Param("color") String color); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/SongRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/SongRepository.java new file mode 100644 index 0000000000..ad887fe680 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/repository/SongRepository.java @@ -0,0 +1,21 @@ +package com.baeldung.repository; + +import com.baeldung.entity.Song; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface SongRepository extends JpaRepository { + + List findByNameLike(String name); + + List findByNameNotLike(String name); + + List findByNameStartingWith(String startingWith); + + List findByNameEndingWith(String endingWith); + + List findBySingerContaining(String singer); +} diff --git a/persistence-modules/spring-data-jpa-2/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-2/src/main/resources/application.properties new file mode 100644 index 0000000000..72fc330767 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.jpa.show-sql=true \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/FruitRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/FruitRepositoryIntegrationTest.java new file mode 100644 index 0000000000..866cf1157b --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/FruitRepositoryIntegrationTest.java @@ -0,0 +1,77 @@ +package com.baeldung.repository; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import com.baeldung.entity.Fruit; + +@RunWith(SpringRunner.class) +@SpringBootTest +class FruitRepositoryIntegrationTest { + + @Autowired + private FruitRepository fruitRepository; + + @Transactional + @Test + @Sql(scripts = { "/test-fruit-data.sql" }) + public void givenFruits_WhenDeletedByColor_ThenDeletedFruitsShouldReturn() { + + List fruits = fruitRepository.deleteByColor("green"); + + assertEquals("number of fruits are not matching", 2, fruits.size()); + fruits.forEach(fruit -> assertEquals("Its not a green fruit", "green", fruit.getColor())); + } + + @Transactional + @Test + @Sql(scripts = { "/test-fruit-data.sql" }) + public void givenFruits_WhenDeletedByName_ThenDeletedFruitCountShouldReturn() { + + Long deletedFruitCount = fruitRepository.deleteByName("apple"); + + assertEquals("deleted fruit count is not matching", 1, deletedFruitCount.intValue()); + } + + @Transactional + @Test + @Sql(scripts = { "/test-fruit-data.sql" }) + public void givenFruits_WhenRemovedByColor_ThenDeletedFruitsShouldReturn() { + + List fruits = fruitRepository.removeByColor("green"); + + assertEquals("number of fruits are not matching", 2, fruits.size()); + fruits.forEach(fruit -> assertEquals("Its not a green fruit", "green", fruit.getColor())); + } + + @Transactional + @Test + @Sql(scripts = { "/test-fruit-data.sql" }) + public void givenFruits_WhenRemovedByName_ThenDeletedFruitCountShouldReturn() { + + Long deletedFruitCount = fruitRepository.removeByName("apple"); + + assertEquals("deleted fruit count is not matching", 1, deletedFruitCount.intValue()); + } + + @Transactional + @Test + @Sql(scripts = { "/test-fruit-data.sql" }) + public void givenFruits_WhenDeletedByColorOrName_ThenDeletedFruitsShouldReturn() { + + List fruits = fruitRepository.deleteFruits("apple", "green"); + + assertEquals("number of fruits are not matching", 3, fruits.size()); + fruits.forEach(fruit -> assertTrue("Its not a green fruit or apple", ("green".equals(fruit.getColor())) || "apple".equals(fruit.getColor()))); + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/SongRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/SongRepositoryIntegrationTest.java new file mode 100644 index 0000000000..c3d0636881 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/repository/SongRepositoryIntegrationTest.java @@ -0,0 +1,57 @@ +package com.baeldung.repository; + +import com.baeldung.entity.Song; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest +@Sql(scripts = { "/test-song-data.sql" }) +public class SongRepositoryIntegrationTest { + + @Autowired private SongRepository songRepository; + + @Transactional + @Test + public void givenSong_WhenFindLikeByName_ThenShouldReturnOne() { + List songs = songRepository.findByNameLike("Despacito"); + assertEquals(1, songs.size()); + } + + @Transactional + @Test + public void givenSong_WhenFindByNameNotLike_thenShouldReturn3Songs() { + List songs = songRepository.findByNameNotLike("Despacito"); + assertEquals(5, songs.size()); + } + + @Transactional + @Test + public void givenSong_WhenFindByNameStartingWith_thenShouldReturn2Songs() { + List songs = songRepository.findByNameStartingWith("Co"); + assertEquals(2, songs.size()); + } + + @Transactional + @Test + public void givenSong_WhenFindByNameEndingWith_thenShouldReturn2Songs() { + List songs = songRepository.findByNameEndingWith("Life"); + assertEquals(2, songs.size()); + } + + @Transactional + @Test + public void givenSong_WhenFindBySingerContaining_thenShouldReturn2Songs() { + List songs = songRepository.findBySingerContaining("Luis"); + assertEquals(2, songs.size()); + } +} diff --git a/persistence-modules/spring-data-jpa-2/src/test/resources/test-fruit-data.sql b/persistence-modules/spring-data-jpa-2/src/test/resources/test-fruit-data.sql new file mode 100644 index 0000000000..ce2189121f --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/resources/test-fruit-data.sql @@ -0,0 +1,4 @@ +insert into fruit(id,name,color) values (1,'apple','red'); +insert into fruit(id,name,color) values (2,'custard apple','green'); +insert into fruit(id,name,color) values (3,'mango','yellow'); +insert into fruit(id,name,color) values (4,'guava','green'); \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-2/src/test/resources/test-song-data.sql b/persistence-modules/spring-data-jpa-2/src/test/resources/test-song-data.sql new file mode 100644 index 0000000000..5a2b1a5555 --- /dev/null +++ b/persistence-modules/spring-data-jpa-2/src/test/resources/test-song-data.sql @@ -0,0 +1,8 @@ +INSERT INTO song(id,name,length_in_seconds,compositor,singer,released,genre) +VALUES +(1,'Despacito',209,'Luis Fonsi','Luis Fonsi, Daddy Yankee','2017-01-12','Reggaeton'), +(2,'Con calma',188,'Daddy Yankee','Daddy Yankee','2019-01-24','Reggaeton'), +(3,'It''s My Life',205,'Bon Jovi','Jon Bon Jovi','2000-05-23','Pop'), +(4,'Live is Life',242,'Opus','Opus','1985-01-01','Reggae'), +(5,'Countdown to Extinction',249,'Megadeth','Megadeth','1992-07-14','Heavy Metal'), +(6, 'Si nos dejan',139,'Luis Miguel','Luis Miguel','1995-10-17','Bolero'); \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/README.md b/persistence-modules/spring-data-jpa/README.md index 739031ff5e..48c3180262 100644 --- a/persistence-modules/spring-data-jpa/README.md +++ b/persistence-modules/spring-data-jpa/README.md @@ -20,6 +20,9 @@ - [INSERT Statement in JPA](https://www.baeldung.com/jpa-insert) - [Pagination and Sorting using Spring Data JPA](https://www.baeldung.com/spring-data-jpa-pagination-sorting) - [Spring Data JPA Query by Example](https://www.baeldung.com/spring-data-query-by-example) +- [DB Integration Tests with Spring Boot and Testcontainers](https://www.baeldung.com/spring-boot-testcontainers-integration-test) +- [Spring Data JPA @Modifying Annotation](https://www.baeldung.com/spring-data-jpa-modifying-annotation) +- [Spring Data JPA Batch Inserts](https://www.baeldung.com/spring-data-jpa-batch-inserts) ### Eclipse Config After importing the project into Eclipse, you may see the following error: diff --git a/persistence-modules/spring-data-jpa/pom.xml b/persistence-modules/spring-data-jpa/pom.xml index 401f4877ac..c512994931 100644 --- a/persistence-modules/spring-data-jpa/pom.xml +++ b/persistence-modules/spring-data-jpa/pom.xml @@ -53,6 +53,15 @@ spring-security-test test + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + com.google.guava diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/batchinserts/CustomerController.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/batchinserts/CustomerController.java new file mode 100644 index 0000000000..7623d4d166 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/batchinserts/CustomerController.java @@ -0,0 +1,43 @@ +package com.baeldung.batchinserts; + +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.batchinserts.model.Customer; +import com.baeldung.batchinserts.repository.CustomerRepository; + +/** + * A simple controller to test the JPA CrudRepository operations + * controllers + * + * @author ysharma2512 + * + */ +@RestController +public class CustomerController { + + @Autowired + CustomerRepository customerRepository; + + public CustomerController(CustomerRepository customerRepository2) { + this.customerRepository = customerRepository2; + } + + @PostMapping("/customers") + public ResponseEntity> insertCustomers() throws URISyntaxException { + Customer c1 = new Customer("James", "Gosling"); + Customer c2 = new Customer("Doug", "Lea"); + Customer c3 = new Customer("Martin", "Fowler"); + Customer c4 = new Customer("Brian", "Goetz"); + List customers = Arrays.asList(c1, c2, c3, c4); + customerRepository.saveAll(customers); + return ResponseEntity.ok(customers); + } + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/batchinserts/model/Customer.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/batchinserts/model/Customer.java new file mode 100644 index 0000000000..4d82cf12a2 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/batchinserts/model/Customer.java @@ -0,0 +1,56 @@ +package com.baeldung.batchinserts.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +/** + * Customer Entity class + * @author ysharma2512 + * + */ +@Entity +public class Customer { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + private String firstName; + private String lastName; + + public Customer(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return String.format("Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName); + } + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/batchinserts/repository/CustomerRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/batchinserts/repository/CustomerRepository.java new file mode 100644 index 0000000000..ab0214bade --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/batchinserts/repository/CustomerRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.batchinserts.repository; + +import org.springframework.data.repository.CrudRepository; + +import com.baeldung.batchinserts.model.Customer; + +/** + * JPA CrudRepository interface + * + * @author ysharma2512 + * + */ +public interface CustomerRepository extends CrudRepository{ + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/CustomItemRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/CustomItemRepository.java index ba077ccf1f..f5b94e507c 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/CustomItemRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/CustomItemRepository.java @@ -12,4 +12,5 @@ public interface CustomItemRepository { Item findItemById(Long id); void findThenDelete(Long id); + } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/EmployeeRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/EmployeeRepository.java new file mode 100644 index 0000000000..6185185791 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/EmployeeRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.dao.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.baeldung.domain.Employee; + +public interface EmployeeRepository extends JpaRepository { + +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/CustomItemRepositoryImpl.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/CustomItemRepositoryImpl.java index 53def88af0..5538448c49 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/CustomItemRepositoryImpl.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/impl/CustomItemRepositoryImpl.java @@ -5,8 +5,8 @@ import javax.persistence.EntityManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; -import com.baeldung.domain.Item; import com.baeldung.dao.repositories.CustomItemRepository; +import com.baeldung.domain.Item; @Repository public class CustomItemRepositoryImpl implements CustomItemRepository { @@ -29,4 +29,5 @@ public class CustomItemRepositoryImpl implements CustomItemRepository { final Item item = entityManager.find(Item.class, id); entityManager.remove(item); } + } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java index 7d6b076517..1d05a17414 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java @@ -9,6 +9,7 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.time.LocalDate; import java.util.Collection; import java.util.List; import java.util.stream.Stream; @@ -17,6 +18,9 @@ public interface UserRepository extends JpaRepository , UserRepos Stream findAllByName(String name); + @Query("select u from User u where u.email like '%@gmail.com'") + List findUsersWithGmailAddress(); + @Query("SELECT u FROM User u WHERE u.status = 1") Collection findAllActiveUsers(); @@ -67,10 +71,29 @@ public interface UserRepository extends JpaRepository , UserRepos @Query(value = "UPDATE Users u SET u.status = ? WHERE u.name = ?", nativeQuery = true) int updateUserSetStatusForNameNative(Integer status, String name); + @Query(value = "INSERT INTO Users (name, age, email, status, active) VALUES (:name, :age, :email, :status, :active)", nativeQuery = true) + @Modifying + void insertUser(@Param("name") String name, @Param("age") Integer age, @Param("email") String email, @Param("status") Integer status, @Param("active") boolean active); + @Modifying @Query(value = "UPDATE Users u SET status = ? WHERE u.name = ?", nativeQuery = true) int updateUserSetStatusForNameNativePostgres(Integer status, String name); - + @Query(value = "SELECT u FROM User u WHERE u.name IN :names") List findUserByNameList(@Param("names") Collection names); + + void deleteAllByCreationDateAfter(LocalDate date); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query("update User u set u.active = false where u.lastLoginDate < :date") + void deactivateUsersNotLoggedInSince(@Param("date") LocalDate date); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query("delete from User u where u.active = false") + int deleteDeactivatedUsers(); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query(value = "alter table Users add column deleted int(1) not null default 0", nativeQuery = true) + void addDeletedColumn(); + } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java index 72c1fd5d00..0f29cd656e 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java @@ -1,10 +1,14 @@ package com.baeldung.dao.repositories.user; +import java.util.Collection; import java.util.List; import java.util.Set; +import java.util.function.Predicate; import com.baeldung.domain.user.User; public interface UserRepositoryCustom { List findUserByEmails(Set emails); + + List findAllUsersByPredicates(Collection> predicates); } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java index 9f841caf68..7b2a7ab123 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java @@ -1,8 +1,11 @@ package com.baeldung.dao.repositories.user; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; @@ -40,4 +43,15 @@ public class UserRepositoryCustomImpl implements UserRepositoryCustom { .getResultList(); } + @Override + public List findAllUsersByPredicates(Collection> predicates) { + List allUsers = entityManager.createQuery("select u from User u", User.class).getResultList(); + Stream allUsersStream = allUsers.stream(); + for (java.util.function.Predicate predicate : predicates) { + allUsersStream = allUsersStream.filter(predicate); + } + + return allUsersStream.collect(Collectors.toList()); + } + } diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Employee.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Employee.java new file mode 100644 index 0000000000..f2363cf746 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/Employee.java @@ -0,0 +1,36 @@ +package com.baeldung.domain; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Employee { + + @Id + private Long id; + private String name; + + public Employee() { + } + + public Employee(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/user/User.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/user/User.java index 28c52140c7..7109271eeb 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/user/User.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/domain/user/User.java @@ -1,7 +1,9 @@ package com.baeldung.domain.user; import javax.persistence.*; +import java.time.LocalDate; import java.util.List; +import java.util.Objects; @Entity @Table(name = "users") @@ -11,6 +13,9 @@ public class User { @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; + private LocalDate creationDate; + private LocalDate lastLoginDate; + private boolean active; private int age; @Column(unique = true, nullable = false) private String email; @@ -22,10 +27,12 @@ public class User { super(); } - public User(String name, String email, Integer status) { + public User(String name, LocalDate creationDate, String email, Integer status) { this.name = name; + this.creationDate = creationDate; this.email = email; this.status = status; + this.active = true; } public int getId() { @@ -44,6 +51,10 @@ public class User { this.name = name; } + public LocalDate getCreationDate() { + return creationDate; + } + public String getEmail() { return email; } @@ -83,4 +94,37 @@ public class User { return builder.toString(); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + User user = (User) o; + return id == user.id && + age == user.age && + Objects.equals(name, user.name) && + Objects.equals(creationDate, user.creationDate) && + Objects.equals(email, user.email) && + Objects.equals(status, user.status); + } + + @Override + public int hashCode() { + return Objects.hash(id, name, creationDate, age, email, status); + } + + public LocalDate getLastLoginDate() { + return lastLoginDate; + } + + public void setLastLoginDate(LocalDate lastLoginDate) { + this.lastLoginDate = lastLoginDate; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } } \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/PassengerRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/PassengerRepository.java index 6ae6afb403..b2d145899e 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/PassengerRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/PassengerRepository.java @@ -14,4 +14,7 @@ interface PassengerRepository extends JpaRepository, CustomPass List findByLastNameOrderBySeatNumberAsc(String lastName); List findByLastName(String lastName, Sort sort); + + List findByFirstNameIgnoreCase(String firstName); + } diff --git a/persistence-modules/spring-data-jpa/src/main/resources/application.properties b/persistence-modules/spring-data-jpa/src/main/resources/application.properties index 37fb9ca9c4..239f81db7b 100644 --- a/persistence-modules/spring-data-jpa/src/main/resources/application.properties +++ b/persistence-modules/spring-data-jpa/src/main/resources/application.properties @@ -14,4 +14,9 @@ hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFa spring.datasource.data=import_entities.sql -spring.main.allow-bean-definition-overriding=true \ No newline at end of file +spring.main.allow-bean-definition-overriding=true + +spring.jpa.properties.hibernate.jdbc.batch_size=4 +spring.jpa.properties.hibernate.order_inserts=true +spring.jpa.properties.hibernate.order_updates=true +spring.jpa.properties.hibernate.generate_statistics=true \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/batchinserts/BatchInsertIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/batchinserts/BatchInsertIntegrationTest.java new file mode 100644 index 0000000000..f60e0d21bf --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/batchinserts/BatchInsertIntegrationTest.java @@ -0,0 +1,44 @@ +package com.baeldung.batchinserts; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import com.baeldung.batchinserts.CustomerController; +import com.baeldung.batchinserts.repository.CustomerRepository; +import com.baeldung.config.PersistenceConfiguration; +import com.baeldung.config.PersistenceProductConfiguration; +import com.baeldung.config.PersistenceUserConfiguration; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +@ContextConfiguration(classes = { PersistenceConfiguration.class, PersistenceProductConfiguration.class, PersistenceUserConfiguration.class }) +public class BatchInsertIntegrationTest { + + @Autowired + private CustomerRepository customerRepository; + private MockMvc mockMvc; + @Before + public void setUp() throws Exception { + mockMvc = MockMvcBuilders.standaloneSetup( new CustomerController(customerRepository)) + .build(); + } + + @Test + public void whenInsertingCustomers_thenCustomersAreCreated() throws Exception { + this.mockMvc.perform(post("/customers")) + .andExpect(status().isOk()); + } + +} \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/EmployeeRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/EmployeeRepositoryIntegrationTest.java new file mode 100644 index 0000000000..13ceb702d2 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/EmployeeRepositoryIntegrationTest.java @@ -0,0 +1,39 @@ +package com.baeldung.dao.repositories; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.domain.Employee; + +@RunWith(SpringRunner.class) +@DataJpaTest +public class EmployeeRepositoryIntegrationTest { + + private static final Employee EMPLOYEE1 = new Employee(1L, "John"); + private static final Employee EMPLOYEE2 = new Employee(2L, "Alice"); + + @Autowired + private EmployeeRepository employeeRepository; + + @Test + public void givenEmployeeEntity_whenInsertWithSave_ThenEmployeeIsPersisted() { + employeeRepository.save(EMPLOYEE1); + assertEmployeePersisted(EMPLOYEE1); + } + + @Test + public void givenEmployeeEntity_whenInsertWithSaveAndFlush_ThenEmployeeIsPersisted() { + employeeRepository.saveAndFlush(EMPLOYEE2); + assertEmployeePersisted(EMPLOYEE2); + } + + private void assertEmployeePersisted(Employee input) { + Employee employee = employeeRepository.getOne(input.getId()); + assertThat(employee).isNotNull(); + } +} diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryCommon.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryCommon.java index 55a453e48f..abd758cec2 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryCommon.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryCommon.java @@ -12,14 +12,15 @@ import org.springframework.data.jpa.domain.JpaSort; import org.springframework.data.mapping.PropertyReferenceException; import org.springframework.transaction.annotation.Transactional; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import javax.persistence.EntityManager; +import javax.persistence.Query; +import java.time.LocalDate; +import java.util.*; +import java.util.function.Predicate; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.*; class UserRepositoryCommon { @@ -29,13 +30,15 @@ class UserRepositoryCommon { final String USER_EMAIL4 = "email4@example.com"; final Integer INACTIVE_STATUS = 0; final Integer ACTIVE_STATUS = 1; - private final String USER_EMAIL5 = "email5@example.com"; - private final String USER_EMAIL6 = "email6@example.com"; - private final String USER_NAME_ADAM = "Adam"; - private final String USER_NAME_PETER = "Peter"; + final String USER_EMAIL5 = "email5@example.com"; + final String USER_EMAIL6 = "email6@example.com"; + final String USER_NAME_ADAM = "Adam"; + final String USER_NAME_PETER = "Peter"; @Autowired protected UserRepository userRepository; + @Autowired + private EntityManager entityManager; @Test @Transactional @@ -258,9 +261,9 @@ class UserRepositoryCommon { @Test public void givenUsersInDB_WhenFindAllWithSortByName_ThenReturnUsersSorted() { - userRepository.save(new User(USER_NAME_ADAM, USER_EMAIL, ACTIVE_STATUS)); - userRepository.save(new User(USER_NAME_PETER, USER_EMAIL2, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE", USER_EMAIL3, INACTIVE_STATUS)); + userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); + userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, INACTIVE_STATUS)); List usersSortByName = userRepository.findAll(new Sort(Sort.Direction.ASC, "name")); @@ -270,9 +273,9 @@ class UserRepositoryCommon { @Test(expected = PropertyReferenceException.class) public void givenUsersInDB_WhenFindAllSortWithFunction_ThenThrowException() { - userRepository.save(new User(USER_NAME_ADAM, USER_EMAIL, ACTIVE_STATUS)); - userRepository.save(new User(USER_NAME_PETER, USER_EMAIL2, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE", USER_EMAIL3, INACTIVE_STATUS)); + userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); + userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, INACTIVE_STATUS)); userRepository.findAll(new Sort(Sort.Direction.ASC, "name")); @@ -284,9 +287,9 @@ class UserRepositoryCommon { @Test public void givenUsersInDB_WhenFindAllSortWithFunctionQueryAnnotationJPQL_ThenReturnUsersSorted() { - userRepository.save(new User(USER_NAME_ADAM, USER_EMAIL, ACTIVE_STATUS)); - userRepository.save(new User(USER_NAME_PETER, USER_EMAIL2, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE", USER_EMAIL3, INACTIVE_STATUS)); + userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); + userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, INACTIVE_STATUS)); userRepository.findAllUsers(new Sort("name")); @@ -298,12 +301,12 @@ class UserRepositoryCommon { @Test public void givenUsersInDB_WhenFindAllWithPageRequestQueryAnnotationJPQL_ThenReturnPageOfUsers() { - userRepository.save(new User(USER_NAME_ADAM, USER_EMAIL, ACTIVE_STATUS)); - userRepository.save(new User(USER_NAME_PETER, USER_EMAIL2, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE", USER_EMAIL3, INACTIVE_STATUS)); - userRepository.save(new User("SAMPLE1", USER_EMAIL4, INACTIVE_STATUS)); - userRepository.save(new User("SAMPLE2", USER_EMAIL5, INACTIVE_STATUS)); - userRepository.save(new User("SAMPLE3", USER_EMAIL6, INACTIVE_STATUS)); + userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); + userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, INACTIVE_STATUS)); + userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL4, INACTIVE_STATUS)); + userRepository.save(new User("SAMPLE2", LocalDate.now(), USER_EMAIL5, INACTIVE_STATUS)); + userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL6, INACTIVE_STATUS)); Page usersPage = userRepository.findAllUsersWithPagination(new PageRequest(1, 3)); @@ -314,27 +317,27 @@ class UserRepositoryCommon { @Test public void givenUsersInDB_WhenFindAllWithPageRequestQueryAnnotationNative_ThenReturnPageOfUsers() { - userRepository.save(new User(USER_NAME_ADAM, USER_EMAIL, ACTIVE_STATUS)); - userRepository.save(new User(USER_NAME_PETER, USER_EMAIL2, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE", USER_EMAIL3, INACTIVE_STATUS)); - userRepository.save(new User("SAMPLE1", USER_EMAIL4, INACTIVE_STATUS)); - userRepository.save(new User("SAMPLE2", USER_EMAIL5, INACTIVE_STATUS)); - userRepository.save(new User("SAMPLE3", USER_EMAIL6, INACTIVE_STATUS)); + userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); + userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, INACTIVE_STATUS)); + userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL4, INACTIVE_STATUS)); + userRepository.save(new User("SAMPLE2", LocalDate.now(), USER_EMAIL5, INACTIVE_STATUS)); + userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL6, INACTIVE_STATUS)); Page usersSortByNameLength = userRepository.findAllUsersWithPaginationNative(new PageRequest(1, 3)); assertThat(usersSortByNameLength.getContent() .get(0) - .getName()).isEqualTo("SAMPLE1"); + .getName()).isEqualTo(USER_NAME_PETER); } @Test @Transactional public void givenUsersInDB_WhenUpdateStatusForNameModifyingQueryAnnotationJPQL_ThenModifyMatchingUsers() { - userRepository.save(new User("SAMPLE", USER_EMAIL, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE1", USER_EMAIL2, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE", USER_EMAIL3, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE3", USER_EMAIL4, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL4, ACTIVE_STATUS)); int updatedUsersSize = userRepository.updateUserSetStatusForName(INACTIVE_STATUS, "SAMPLE"); @@ -384,7 +387,156 @@ class UserRepositoryCommon { assertThat(usersWithNames.size()).isEqualTo(2); } - + + + @Test + @Transactional + public void whenInsertedWithQuery_ThenUserIsPersisted() { + userRepository.insertUser(USER_NAME_ADAM, 1, USER_EMAIL, ACTIVE_STATUS, true); + userRepository.insertUser(USER_NAME_PETER, 1, USER_EMAIL2, ACTIVE_STATUS, true); + + User userAdam = userRepository.findUserByNameLike(USER_NAME_ADAM); + User userPeter = userRepository.findUserByNameLike(USER_NAME_PETER); + + assertThat(userAdam).isNotNull(); + assertThat(userAdam.getEmail()).isEqualTo(USER_EMAIL); + assertThat(userPeter).isNotNull(); + assertThat(userPeter.getEmail()).isEqualTo(USER_EMAIL2); + } + + + @Test + @Transactional + public void givenTwoUsers_whenFindByNameUsr01_ThenUserUsr01() { + User usr01 = new User("usr01", LocalDate.now(), "usr01@baeldung.com", 1); + User usr02 = new User("usr02", LocalDate.now(), "usr02@baeldung.com", 1); + + userRepository.save(usr01); + userRepository.save(usr02); + + try (Stream users = userRepository.findAllByName("usr01")) { + assertTrue(users.allMatch(usr -> usr.equals(usr01))); + } + } + + @Test + @Transactional + public void givenTwoUsers_whenFindByNameUsr00_ThenNoUsers() { + User usr01 = new User("usr01", LocalDate.now(), "usr01@baeldung.com", 1); + User usr02 = new User("usr02", LocalDate.now(), "usr02@baeldung.com", 1); + + userRepository.save(usr01); + userRepository.save(usr02); + + try (Stream users = userRepository.findAllByName("usr00")) { + assertEquals(0, users.count()); + } + } + + @Test + public void givenTwoUsers_whenFindUsersWithGmailAddress_ThenUserUsr02() { + User usr01 = new User("usr01", LocalDate.now(), "usr01@baeldung.com", 1); + User usr02 = new User("usr02", LocalDate.now(), "usr02@gmail.com", 1); + + userRepository.save(usr01); + userRepository.save(usr02); + + List users = userRepository.findUsersWithGmailAddress(); + assertEquals(1, users.size()); + assertEquals(usr02, users.get(0)); + } + + @Test + @Transactional + public void givenTwoUsers_whenDeleteAllByCreationDateAfter_ThenOneUserRemains() { + User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1); + User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.com", 1); + + userRepository.save(usr01); + userRepository.save(usr02); + + userRepository.deleteAllByCreationDateAfter(LocalDate.of(2018, 5, 1)); + + List users = userRepository.findAll(); + + assertEquals(1, users.size()); + assertEquals(usr01, users.get(0)); + } + + @Test + public void givenTwoUsers_whenFindAllUsersByPredicates_ThenUserUsr01() { + User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1); + User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.org", 1); + + userRepository.save(usr01); + userRepository.save(usr02); + + List> predicates = new ArrayList<>(); + predicates.add(usr -> usr.getCreationDate().isAfter(LocalDate.of(2017, 12, 31))); + predicates.add(usr -> usr.getEmail().endsWith(".com")); + + List users = userRepository.findAllUsersByPredicates(predicates); + + assertEquals(1, users.size()); + assertEquals(usr01, users.get(0)); + } + + @Test + @Transactional + public void givenTwoUsers_whenDeactivateUsersNotLoggedInSince_ThenUserUsr02Deactivated() { + User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1); + usr01.setLastLoginDate(LocalDate.now()); + User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.org", 1); + usr02.setLastLoginDate(LocalDate.of(2018, 7, 20)); + + userRepository.save(usr01); + userRepository.save(usr02); + + userRepository.deactivateUsersNotLoggedInSince(LocalDate.of(2018, 8, 1)); + + List users = userRepository.findAllUsers(Sort.by(Sort.Order.asc("name"))); + assertTrue(users.get(0).isActive()); + assertFalse(users.get(1).isActive()); + } + + @Test + @Transactional + public void givenTwoUsers_whenDeleteDeactivatedUsers_ThenUserUsr02Deleted() { + User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1); + usr01.setLastLoginDate(LocalDate.now()); + User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.com", 0); + usr02.setLastLoginDate(LocalDate.of(2018, 7, 20)); + usr02.setActive(false); + + userRepository.save(usr01); + userRepository.save(usr02); + + int deletedUsersCount = userRepository.deleteDeactivatedUsers(); + + List users = userRepository.findAll(); + assertEquals(1, users.size()); + assertEquals(usr01, users.get(0)); + assertEquals(1, deletedUsersCount); + } + + @Test + @Transactional + public void givenTwoUsers_whenAddDeletedColumn_ThenUsersHaveDeletedColumn() { + User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1); + usr01.setLastLoginDate(LocalDate.now()); + User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.org", 1); + usr02.setLastLoginDate(LocalDate.of(2018, 7, 20)); + usr02.setActive(false); + + userRepository.save(usr01); + userRepository.save(usr02); + + userRepository.addDeletedColumn(); + + Query nativeQuery = entityManager.createNativeQuery("select deleted from USERS where NAME = 'usr01'"); + assertEquals(0, nativeQuery.getResultList().get(0)); + } + @After public void cleanUp() { userRepository.deleteAll(); diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java index 6bcbb6dcaa..09f937c8f2 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java @@ -9,6 +9,8 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -22,10 +24,10 @@ public class UserRepositoryIntegrationTest extends UserRepositoryCommon { @Test @Transactional public void givenUsersInDBWhenUpdateStatusForNameModifyingQueryAnnotationNativeThenModifyMatchingUsers() { - userRepository.save(new User("SAMPLE", USER_EMAIL, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE1", USER_EMAIL2, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE", USER_EMAIL3, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE3", USER_EMAIL4, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL4, ACTIVE_STATUS)); userRepository.flush(); int updatedUsersSize = userRepository.updateUserSetStatusForNameNative(INACTIVE_STATUS, "SAMPLE"); diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCAutoIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCAutoIntegrationTest.java index 4b58be487c..6a851823e3 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCAutoIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCAutoIntegrationTest.java @@ -11,6 +11,8 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; import org.testcontainers.containers.PostgreSQLContainer; +import java.time.LocalDate; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -27,10 +29,10 @@ public class UserRepositoryTCAutoIntegrationTest extends UserRepositoryCommon { @Test @Transactional public void givenUsersInDB_WhenUpdateStatusForNameModifyingQueryAnnotationNativePostgres_ThenModifyMatchingUsers() { - userRepository.save(new User("SAMPLE", USER_EMAIL, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE1", USER_EMAIL2, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE", USER_EMAIL3, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE3", USER_EMAIL4, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL4, ACTIVE_STATUS)); userRepository.flush(); int updatedUsersSize = userRepository.updateUserSetStatusForNameNativePostgres(INACTIVE_STATUS, "SAMPLE"); diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCIntegrationTest.java index ccbc3b3fe2..c300a07ab9 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryTCIntegrationTest.java @@ -14,6 +14,8 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; import org.testcontainers.containers.PostgreSQLContainer; +import java.time.LocalDate; + import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) @@ -31,10 +33,10 @@ public class UserRepositoryTCIntegrationTest extends UserRepositoryCommon { @Test @Transactional public void givenUsersInDB_WhenUpdateStatusForNameModifyingQueryAnnotationNative_ThenModifyMatchingUsers() { - userRepository.save(new User("SAMPLE", USER_EMAIL, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE1", USER_EMAIL2, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE", USER_EMAIL3, ACTIVE_STATUS)); - userRepository.save(new User("SAMPLE3", USER_EMAIL4, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, ACTIVE_STATUS)); + userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL4, ACTIVE_STATUS)); userRepository.flush(); int updatedUsersSize = userRepository.updateUserSetStatusForNameNativePostgres(INACTIVE_STATUS, "SAMPLE"); diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java index 8cd19cec03..2b303604b6 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java @@ -1,17 +1,5 @@ package com.baeldung.passenger; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.core.IsNot.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.List; -import java.util.Optional; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -24,6 +12,17 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.test.context.junit4.SpringRunner; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.List; +import java.util.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + @DataJpaTest @RunWith(SpringRunner.class) public class PassengerRepositoryIntegrationTest { @@ -152,18 +151,36 @@ public class PassengerRepositoryIntegrationTest { Passenger fred = Passenger.from("Fred", "Bloggs", 22); Passenger siya = Passenger.from("Siya", "Kolisi", 85); Passenger ricki = Passenger.from("Ricki", "Bobbie", 36); - + ExampleMatcher ignoringExampleMatcher = ExampleMatcher.matchingAny().withMatcher("lastName", - ExampleMatcher.GenericPropertyMatchers.startsWith().ignoreCase()).withIgnorePaths("firstName", "seatNumber"); - + ExampleMatcher.GenericPropertyMatchers.startsWith().ignoreCase()).withIgnorePaths("firstName", "seatNumber"); + Example example = Example.of(Passenger.from(null, "b", null), - ignoringExampleMatcher); - + ignoringExampleMatcher); + List passengers = repository.findAll(example); - + assertThat(passengers, contains(fred, ricki)); assertThat(passengers, not(contains(jill))); assertThat(passengers, not(contains(eve))); assertThat(passengers, not(contains(siya))); } + + @Test + public void givenPassengers_whenMatchingIgnoreCase_thenExpectedReturned() { + Passenger jill = Passenger.from("Jill", "Smith", 50); + Passenger eve = Passenger.from("Eve", "Jackson", 95); + Passenger fred = Passenger.from("Fred", "Bloggs", 22); + Passenger siya = Passenger.from("Siya", "Kolisi", 85); + Passenger ricki = Passenger.from("Ricki", "Bobbie", 36); + + List passengers = repository.findByFirstNameIgnoreCase("FRED"); + + assertThat(passengers, contains(fred)); + assertThat(passengers, not(contains(eve))); + assertThat(passengers, not(contains(siya))); + assertThat(passengers, not(contains(jill))); + assertThat(passengers, not(contains(ricki))); + + } } diff --git a/persistence-modules/spring-hibernate-5/README.md b/persistence-modules/spring-hibernate-5/README.md index 5e287919f1..c48e58fcca 100644 --- a/persistence-modules/spring-hibernate-5/README.md +++ b/persistence-modules/spring-hibernate-5/README.md @@ -2,4 +2,4 @@ - [Hibernate Many to Many Annotation Tutorial](http://www.baeldung.com/hibernate-many-to-many) - [Programmatic Transactions in the Spring TestContext Framework](http://www.baeldung.com/spring-test-programmatic-transactions) -- [Hibernate Criteria Queries](http://www.baeldung.com/hibernate-criteria-queries) +- [JPA Criteria Queries](http://www.baeldung.com/hibernate-criteria-queries) diff --git a/persistence-modules/spring-hibernate4/README.md b/persistence-modules/spring-hibernate4/README.md index 57a341ed45..f2553ad229 100644 --- a/persistence-modules/spring-hibernate4/README.md +++ b/persistence-modules/spring-hibernate4/README.md @@ -3,8 +3,8 @@ ## Spring with Hibernate 4 Example Project ### Relevant Articles: -- [Hibernate 4 with Spring](http://www.baeldung.com/hibernate-4-spring) -- [The DAO with Spring 3 and Hibernate](http://www.baeldung.com/persistence-layer-with-spring-and-hibernate) +- [Guide to Hibernate 4 with Spring](http://www.baeldung.com/hibernate-4-spring) +- [The DAO with Spring and Hibernate](http://www.baeldung.com/persistence-layer-with-spring-and-hibernate) - [Hibernate Pagination](http://www.baeldung.com/hibernate-pagination) - [Sorting with Hibernate](http://www.baeldung.com/hibernate-sort) - [Stored Procedures with Hibernate](http://www.baeldung.com/stored-procedures-with-hibernate-tutorial) diff --git a/persistence-modules/spring-jpa/README.md b/persistence-modules/spring-jpa/README.md index 23c03d3bef..2f2a27e4ac 100644 --- a/persistence-modules/spring-jpa/README.md +++ b/persistence-modules/spring-jpa/README.md @@ -15,7 +15,6 @@ - [Self-Contained Testing Using an In-Memory Database](http://www.baeldung.com/spring-jpa-test-in-memory-database) - [A Guide to Spring AbstractRoutingDatasource](http://www.baeldung.com/spring-abstract-routing-data-source) - [A Guide to Hibernate with Spring 4](http://www.baeldung.com/the-persistence-layer-with-spring-and-jpa) -- [Testing REST with multiple MIME types](http://www.baeldung.com/testing-rest-api-with-multiple-media-types) - [Obtaining Auto-generated Keys in Spring JDBC](http://www.baeldung.com/spring-jdbc-autogenerated-keys) - [Transactions with Spring 4 and JPA](http://www.baeldung.com/transaction-configuration-with-jpa-and-spring) - [Use Criteria Queries in a Spring Data Application](https://www.baeldung.com/spring-data-criteria-queries) diff --git a/persistence-modules/spring-jpa/pom.xml b/persistence-modules/spring-jpa/pom.xml index 29a6996791..3daba6cd55 100644 --- a/persistence-modules/spring-jpa/pom.xml +++ b/persistence-modules/spring-jpa/pom.xml @@ -156,13 +156,13 @@ - 4.3.8.RELEASE + 5.1.5.RELEASE 3.21.0-GA - 5.2.10.Final + 5.2.17.Final 6.0.6 - 1.11.3.RELEASE + 2.1.5.RELEASE 1.4.195 @@ -170,7 +170,7 @@ 2.5 - 5.4.1.Final + 6.0.15.Final 1.4.01 2.2.5 diff --git a/persistence-modules/spring-jpa/src/test/java/com/baeldung/SpringContextIntegrationTest.java b/persistence-modules/spring-jpa/src/test/java/com/baeldung/SpringContextIntegrationTest.java index aa85128628..822cbb8ed5 100644 --- a/persistence-modules/spring-jpa/src/test/java/com/baeldung/SpringContextIntegrationTest.java +++ b/persistence-modules/spring-jpa/src/test/java/com/baeldung/SpringContextIntegrationTest.java @@ -3,6 +3,7 @@ package com.baeldung; import org.baeldung.config.PersistenceJPAConfigL2Cache; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; @@ -11,6 +12,7 @@ import org.springframework.test.context.web.WebAppConfiguration; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { PersistenceJPAConfigL2Cache.class }, loader = AnnotationConfigContextLoader.class) @WebAppConfiguration +@DirtiesContext public class SpringContextIntegrationTest { @Test diff --git a/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java b/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java index 9ddc48460a..4d1bcbe1b2 100644 --- a/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java +++ b/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java @@ -35,7 +35,7 @@ public class InMemoryDBIntegrationTest { Student student = new Student(ID, NAME); studentRepository.save(student); - Student student2 = studentRepository.findOne(ID); + Student student2 = studentRepository.findById(ID).get(); assertEquals("name incorrect", NAME, student2.getName()); } diff --git a/pom.xml b/pom.xml index 1c016a2ea9..a832d6156f 100644 --- a/pom.xml +++ b/pom.xml @@ -371,15 +371,16 @@ bootique - cas/cas-secured-app - cas/cas-server + cas cdi checker-plugin core-groovy + core-java-8 + core-java-arrays core-java-collections core-java-collections-list @@ -393,7 +394,8 @@ core-java-networking core-java-perf core-java-sun - core-java + core-java + core-java-jvm core-scala couchbase custom-pmd @@ -412,7 +414,7 @@ feign flyway-cdi-extension - + geotools google-cloud google-web-toolkit @@ -422,9 +424,7 @@ gson guava guava-collections - guava-modules/guava-18 - guava-modules/guava-19 - guava-modules/guava-21 + guava-modules guice @@ -437,9 +437,11 @@ immutables jackson + jackson-2 java-collections-conversions java-collections-maps + java-lite java-numbers @@ -459,6 +461,8 @@ jersey JGit jgroups + jhipster + jhipster-5 jib jjwt jmeter @@ -475,15 +479,13 @@ kotlin-libraries + libraries libraries-data libraries-apache-commons libraries-security libraries-server linkrest - logging-modules/log4j - logging-modules/log4j2 - logging-modules/logback - logging-modules/log-mdc + logging-modules lombok lucene @@ -502,7 +504,6 @@ mustache mybatis - noexception optaplanner orika @@ -514,45 +515,7 @@ protobuffer - persistence-modules/activejdbc - persistence-modules/apache-cayenne - persistence-modules/core-java-persistence - persistence-modules/deltaspike - persistence-modules/flyway - persistence-modules/hbase - persistence-modules/hibernate5 - persistence-modules/hibernate-ogm - persistence-modules/influxdb - persistence-modules/java-cassandra - persistence-modules/java-cockroachdb - persistence-modules/java-jdbi - persistence-modules/java-jpa - persistence-modules/jnosql - persistence-modules/liquibase - persistence-modules/orientdb - persistence-modules/querydsl - persistence-modules/redis - persistence-modules/solr - persistence-modules/spring-boot-h2/spring-boot-h2-database - persistence-modules/spring-boot-persistence - persistence-modules/spring-boot-persistence-mongodb - persistence-modules/spring-data-cassandra - persistence-modules/spring-data-cassandra-reactive - persistence-modules/spring-data-couchbase-2 - persistence-modules/spring-data-dynamodb - persistence-modules/spring-data-eclipselink - - persistence-modules/spring-data-gemfire - persistence-modules/spring-data-jpa - persistence-modules/spring-data-keyvalue - persistence-modules/spring-data-mongodb - persistence-modules/spring-data-neo4j - persistence-modules/spring-data-redis - persistence-modules/spring-data-solr - persistence-modules/spring-hibernate-3 - persistence-modules/spring-hibernate-5 - persistence-modules/spring-hibernate4 - persistence-modules/spring-jpa + persistence-modules rabbitmq @@ -560,16 +523,16 @@ reactor-core rest-with-spark-java resteasy - + restx - rule-engines/easy-rules - rule-engines/openl-tablets - rule-engines/rulebook + rule-engines rsocket rxjava rxjava-2 software-security/sql-injection-samples - + + tensorflow-java + @@ -614,6 +577,7 @@ spring-4 spring-5 + spring-5-webflux spring-5-mvc spring-5-reactive spring-5-reactive-client @@ -633,6 +597,7 @@ spring-boot spring-boot-admin + spring-boot-angular spring-boot-angular-ecommerce spring-boot-autoconfiguration spring-boot-bootstrap @@ -721,13 +686,7 @@ spring-security-angular/server spring-security-cache-control - spring-security-client/spring-security-jsp-authentication - spring-security-client/spring-security-jsp-authorize - spring-security-client/spring-security-jsp-config - spring-security-client/spring-security-mvc - spring-security-client/spring-security-thymeleaf-authentication - spring-security-client/spring-security-thymeleaf-authorize - spring-security-client/spring-security-thymeleaf-config + spring-security-client spring-security-core spring-security-mvc-boot @@ -773,24 +732,7 @@ structurizr struts-2 - testing-modules/gatling - testing-modules/groovy-spock - testing-modules/junit-5 - testing-modules/junit5-migration - testing-modules/load-testing-comparison - testing-modules/mockito - testing-modules/mockito-2 - testing-modules/mocks - testing-modules/mockserver - testing-modules/parallel-tests-junit - testing-modules/rest-assured - testing-modules/rest-testing - - testing-modules/selenium-junit-testng - testing-modules/spring-testing - testing-modules/test-containers - testing-modules/testing - testing-modules/testng + testing-modules twilio Twitter4J @@ -808,6 +750,8 @@ xml xmlunit-2 xstream + + tensorflow-java @@ -849,8 +793,7 @@ spring-apache-camel spring-batch spring-bom - spring-boot-admin/spring-boot-admin-client - spring-boot-admin/spring-boot-admin-server + spring-boot-admin spring-boot-bootstrap spring-boot-bootstrap spring-boot-camel @@ -862,22 +805,18 @@ spring-boot-jasypt spring-boot-keycloak spring-boot-mvc - spring-boot-property-exp/property-exp-custom-config - spring-boot-property-exp/property-exp-default-config + spring-boot-property-exp spring-boot-vue spring-cloud spring-cloud/spring-cloud-archaius/basic-config spring-cloud/spring-cloud-archaius/extra-configs spring-cloud/spring-cloud-bootstrap/config - spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer - spring-cloud/spring-cloud-contract/spring-cloud-contract-producer + spring-cloud/spring-cloud-contract spring-cloud/spring-cloud-gateway spring-cloud/spring-cloud-kubernetes/demo-backend spring-cloud/spring-cloud-rest/spring-cloud-rest-config-server spring-cloud/spring-cloud-ribbon-client - spring-cloud/spring-cloud-security/auth-client - spring-cloud/spring-cloud-security/auth-resource - spring-cloud/spring-cloud-security/auth-server + spring-cloud/spring-cloud-security spring-cloud/spring-cloud-stream/spring-cloud-stream-rabbit spring-cloud/spring-cloud-task/springcloudtasksink spring-cloud/spring-cloud-zookeeper @@ -925,13 +864,7 @@ spring-security-acl spring-security-angular spring-security-cache-control - spring-security-client/spring-security-jsp-authentication - spring-security-client/spring-security-jsp-authorize - spring-security-client/spring-security-jsp-config - spring-security-client/spring-security-mvc - spring-security-client/spring-security-thymeleaf-authentication - spring-security-client/spring-security-thymeleaf-authorize - spring-security-client/spring-security-thymeleaf-config + spring-security-client spring-security-core spring-security-mvc-boot spring-security-mvc-custom @@ -941,14 +874,11 @@ spring-security-mvc-session spring-security-mvc-socket spring-security-rest - spring-security-sso/spring-security-sso-auth-server - spring-security-sso/spring-security-sso-ui - spring-security-sso/spring-security-sso-ui-2 + spring-security-sso spring-security-thymeleaf/spring-security-thymeleaf-authentication spring-security-thymeleaf/spring-security-thymeleaf-authorize spring-security-thymeleaf/spring-security-thymeleaf-config - spring-security-x509/spring-security-x509-basic-auth - spring-security-x509/spring-security-x509-client-auth + spring-security-x509 spring-session/spring-session-jdbc spring-sleuth spring-social-login @@ -1007,7 +937,6 @@ core-kotlin-2 jenkins/hello-world - jhipster jws libraries @@ -1090,8 +1019,7 @@ bootique - cas/cas-secured-app - cas/cas-server + cas cdi checker-plugin core-groovy @@ -1099,6 +1027,7 @@ core-java-8 + core-java-arrays core-java-collections core-java-collections-list @@ -1130,7 +1059,7 @@ feign flyway-cdi-extension - + geotools google-cloud google-web-toolkit @@ -1140,9 +1069,7 @@ gson guava guava-collections - guava-modules/guava-18 - guava-modules/guava-19 - guava-modules/guava-21 + guava-modules guice @@ -1155,6 +1082,7 @@ immutables jackson + jackson-2 java-collections-conversions java-collections-maps @@ -1177,6 +1105,8 @@ jersey JGit jgroups + jhipster + jhipster-5 jib jjwt jmeter @@ -1193,15 +1123,13 @@ kotlin-libraries + libraries libraries-data libraries-apache-commons libraries-security libraries-server linkrest - logging-modules/log4j - logging-modules/log4j2 - logging-modules/logback - logging-modules/log-mdc + logging-modules lombok lucene @@ -1220,7 +1148,6 @@ mustache mybatis - noexception optaplanner orika @@ -1232,57 +1159,17 @@ protobuffer - persistence-modules/activejdbc - persistence-modules/apache-cayenne - persistence-modules/core-java-persistence - persistence-modules/deltaspike - persistence-modules/flyway - persistence-modules/hbase - persistence-modules/hibernate5 - persistence-modules/hibernate-ogm - persistence-modules/influxdb - persistence-modules/java-cassandra - persistence-modules/java-cockroachdb - persistence-modules/java-jdbi - persistence-modules/java-jpa - persistence-modules/jnosql - persistence-modules/liquibase - persistence-modules/orientdb - persistence-modules/querydsl - persistence-modules/redis - persistence-modules/solr - persistence-modules/spring-boot-h2/spring-boot-h2-database - persistence-modules/spring-boot-persistence - persistence-modules/spring-boot-persistence-mongodb - persistence-modules/spring-data-cassandra - persistence-modules/spring-data-cassandra-reactive - persistence-modules/spring-data-couchbase-2 - persistence-modules/spring-data-dynamodb - persistence-modules/spring-data-eclipselink - - persistence-modules/spring-data-gemfire - persistence-modules/spring-data-jpa - persistence-modules/spring-data-keyvalue - persistence-modules/spring-data-mongodb - persistence-modules/spring-data-neo4j - persistence-modules/spring-data-redis - persistence-modules/spring-data-solr - persistence-modules/spring-hibernate-3 - persistence-modules/spring-hibernate-5 - persistence-modules/spring-hibernate4 - persistence-modules/spring-jpa - + persistence-modules + rabbitmq ratpack reactor-core rest-with-spark-java resteasy - + restx - rule-engines/easy-rules - rule-engines/openl-tablets - rule-engines/rulebook + rule-engines rsocket rxjava rxjava-2 @@ -1346,6 +1233,7 @@ spring-boot spring-boot-admin + spring-boot-angular spring-boot-angular-ecommerce spring-boot-autoconfiguration spring-boot-bootstrap @@ -1433,13 +1321,7 @@ spring-security-angular/server spring-security-cache-control - spring-security-client/spring-security-jsp-authentication - spring-security-client/spring-security-jsp-authorize - spring-security-client/spring-security-jsp-config - spring-security-client/spring-security-mvc - spring-security-client/spring-security-thymeleaf-authentication - spring-security-client/spring-security-thymeleaf-authorize - spring-security-client/spring-security-thymeleaf-config + spring-security-client spring-security-core spring-security-mvc-boot @@ -1484,24 +1366,7 @@ structurizr struts-2 - testing-modules/gatling - testing-modules/groovy-spock - testing-modules/junit-5 - testing-modules/junit5-migration - testing-modules/load-testing-comparison - testing-modules/mockito - testing-modules/mockito-2 - testing-modules/mocks - testing-modules/mockserver - testing-modules/parallel-tests-junit - testing-modules/rest-assured - testing-modules/rest-testing - - testing-modules/selenium-junit-testng - testing-modules/spring-testing - testing-modules/test-containers - testing-modules/testing - testing-modules/testng + testing-modules twilio Twitter4J @@ -1560,7 +1425,6 @@ core-kotlin-2 jenkins/hello-world - jhipster jws libraries @@ -1594,7 +1458,7 @@ UTF-8 UTF-8 - refs/heads/master + refs/remotes/origin/master true false false @@ -1629,7 +1493,7 @@ 2.3.1 1.9.13 1.2 - 2.9.7 + 2.9.8 1.3 1.2.0 5.2.0 @@ -1640,5 +1504,6 @@ 2.3 3.8 + 1.16.12 diff --git a/ratpack/README.md b/ratpack/README.md index dded42fab6..14bc3f6c74 100644 --- a/ratpack/README.md +++ b/ratpack/README.md @@ -5,3 +5,4 @@ - [Ratpack Integration with Spring Boot](http://www.baeldung.com/ratpack-spring-boot) - [Ratpack with Hystrix](http://www.baeldung.com/ratpack-hystrix) - [Ratpack HTTP Client](https://www.baeldung.com/ratpack-http-client) +- [Ratpack with RxJava](https://www.baeldung.com/ratpack-rxjava) diff --git a/ratpack/src/main/java/com/baeldung/model/Movie.java b/ratpack/src/main/java/com/baeldung/model/Movie.java new file mode 100644 index 0000000000..6618e9bbb7 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/model/Movie.java @@ -0,0 +1,47 @@ +package com.baeldung.model; +/** + * + *POJO class for Movie object + */ +public class Movie { + + private String name; + + private String year; + + private String director; + + private Double rating; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getYear() { + return year; + } + + public void setYear(String year) { + this.year = year; + } + + public String getDirector() { + return director; + } + + public void setDirector(String director) { + this.director = director; + } + + public Double getRating() { + return rating; + } + + public void setRating(Double rating) { + this.rating = rating; + } +} diff --git a/ratpack/src/main/java/com/baeldung/rxjava/RatpackErrorHandlingApp.java b/ratpack/src/main/java/com/baeldung/rxjava/RatpackErrorHandlingApp.java new file mode 100644 index 0000000000..7d2eba56fb --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/rxjava/RatpackErrorHandlingApp.java @@ -0,0 +1,27 @@ +package com.baeldung.rxjava; + +import ratpack.error.ServerErrorHandler; +import ratpack.rx.RxRatpack; +import ratpack.server.RatpackServer; +import rx.Observable; + +public class RatpackErrorHandlingApp { + + /** + * Try hitting http://localhost:5050/error to see the error handler in action + * @param args + * @throws Exception + */ + + public static void main(String[] args) throws Exception { + RxRatpack.initialize(); + RatpackServer.start(def -> def.registryOf(regSpec -> regSpec.add(ServerErrorHandler.class, (ctx, throwable) -> { + ctx.render("Error caught by handler : " + throwable.getMessage()); + })) + .handlers(chain -> chain.get("error", ctx -> { + Observable. error(new Exception("Error from observable")) + .subscribe(s -> { + }); + }))); + } +} diff --git a/ratpack/src/main/java/com/baeldung/rxjava/RatpackObserveApp.java b/ratpack/src/main/java/com/baeldung/rxjava/RatpackObserveApp.java new file mode 100644 index 0000000000..d5ef105207 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/rxjava/RatpackObserveApp.java @@ -0,0 +1,44 @@ +package com.baeldung.rxjava; + +import java.util.List; + +import com.baeldung.model.Movie; +import com.baeldung.rxjava.service.MoviePromiseService; +import com.baeldung.rxjava.service.impl.MoviePromiseServiceImpl; + +import ratpack.exec.Promise; +import ratpack.handling.Handler; +import ratpack.jackson.Jackson; +import ratpack.rx.RxRatpack; +import ratpack.server.RatpackServer; + +public class RatpackObserveApp { + /** + * Try hitting http://localhost:5050/movies or http://localhost:5050/movie to see the application in action. + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + RxRatpack.initialize(); + + Handler moviePromiseHandler = ctx -> { + MoviePromiseService promiseSvc = ctx.get(MoviePromiseService.class); + Promise moviePromise = promiseSvc.getMovie(); + RxRatpack.observe(moviePromise) + .subscribe(movie -> ctx.render(Jackson.json(movie))); + }; + + Handler moviesPromiseHandler = ctx -> { + MoviePromiseService promiseSvc = ctx.get(MoviePromiseService.class); + Promise> moviePromises = promiseSvc.getMovies(); + RxRatpack.observeEach(moviePromises) + .toList() + .subscribe(movie -> ctx.render(Jackson.json(movie))); + }; + + RatpackServer.start(def -> def.registryOf(regSpec -> regSpec.add(MoviePromiseService.class, new MoviePromiseServiceImpl())) + .handlers(chain -> chain.get("movie", moviePromiseHandler) + .get("movies", moviesPromiseHandler))); + } +} diff --git a/ratpack/src/main/java/com/baeldung/rxjava/RatpackParallelismApp.java b/ratpack/src/main/java/com/baeldung/rxjava/RatpackParallelismApp.java new file mode 100644 index 0000000000..033c3e73b5 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/rxjava/RatpackParallelismApp.java @@ -0,0 +1,36 @@ +package com.baeldung.rxjava; + +import com.baeldung.model.Movie; +import com.baeldung.rxjava.service.MovieObservableService; +import com.baeldung.rxjava.service.impl.MovieObservableServiceImpl; + +import ratpack.jackson.Jackson; +import ratpack.rx.RxRatpack; +import ratpack.server.RatpackServer; +import rx.Observable; + +public class RatpackParallelismApp { + + /** + * Try hitting http://localhost:5050/movies to see the application in action. + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + RxRatpack.initialize(); + RatpackServer.start(def -> def.registryOf(regSpec -> regSpec.add(MovieObservableService.class, new MovieObservableServiceImpl())) + .handlers(chain -> chain.get("movies", ctx -> { + MovieObservableService movieSvc = ctx.get(MovieObservableService.class); + Observable movieObs = movieSvc.getMovies(); + Observable upperCasedNames = movieObs.compose(RxRatpack::forkEach) + .map(movie -> movie.getName() + .toUpperCase()) + .serialize(); + RxRatpack.promise(upperCasedNames) + .then(movie -> { + ctx.render(Jackson.json(movie)); + }); + }))); + } +} diff --git a/ratpack/src/main/java/com/baeldung/rxjava/RatpackPromiseApp.java b/ratpack/src/main/java/com/baeldung/rxjava/RatpackPromiseApp.java new file mode 100644 index 0000000000..8a9c00b788 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/rxjava/RatpackPromiseApp.java @@ -0,0 +1,43 @@ +package com.baeldung.rxjava; + +import com.baeldung.model.Movie; +import com.baeldung.rxjava.service.MovieObservableService; +import com.baeldung.rxjava.service.impl.MovieObservableServiceImpl; + +import ratpack.handling.Handler; +import ratpack.jackson.Jackson; +import ratpack.rx.RxRatpack; +import ratpack.server.RatpackServer; +import rx.Observable; + +public class RatpackPromiseApp { + + /** + * Try hitting http://localhost:5050/movies or http://localhost:5050/movie to see the application in action. + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + RxRatpack.initialize(); + + Handler movieHandler = (ctx) -> { + MovieObservableService movieSvc = ctx.get(MovieObservableService.class); + Observable movieObs = movieSvc.getMovie(); + RxRatpack.promiseSingle(movieObs) + .then(movie -> ctx.render(Jackson.json(movie))); + }; + + Handler moviesHandler = (ctx) -> { + MovieObservableService movieSvc = ctx.get(MovieObservableService.class); + Observable movieObs = movieSvc.getMovies(); + RxRatpack.promise(movieObs) + .then(movie -> ctx.render(Jackson.json(movie))); + }; + + RatpackServer.start(def -> def.registryOf(rSpec -> rSpec.add(MovieObservableService.class, new MovieObservableServiceImpl())) + .handlers(chain -> chain.get("movie", movieHandler) + .get("movies", moviesHandler))); + } + +} diff --git a/ratpack/src/main/java/com/baeldung/rxjava/service/MovieObservableService.java b/ratpack/src/main/java/com/baeldung/rxjava/service/MovieObservableService.java new file mode 100644 index 0000000000..75a90faa44 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/rxjava/service/MovieObservableService.java @@ -0,0 +1,13 @@ +package com.baeldung.rxjava.service; + +import com.baeldung.model.Movie; + +import rx.Observable; + +public interface MovieObservableService { + + Observable getMovies(); + + Observable getMovie(); + +} diff --git a/ratpack/src/main/java/com/baeldung/rxjava/service/MoviePromiseService.java b/ratpack/src/main/java/com/baeldung/rxjava/service/MoviePromiseService.java new file mode 100644 index 0000000000..fc58993d73 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/rxjava/service/MoviePromiseService.java @@ -0,0 +1,15 @@ +package com.baeldung.rxjava.service; + +import java.util.List; + +import com.baeldung.model.Movie; + +import ratpack.exec.Promise; + +public interface MoviePromiseService { + + Promise> getMovies(); + + Promise getMovie(); + +} diff --git a/ratpack/src/main/java/com/baeldung/rxjava/service/impl/MovieObservableServiceImpl.java b/ratpack/src/main/java/com/baeldung/rxjava/service/impl/MovieObservableServiceImpl.java new file mode 100644 index 0000000000..817a33d857 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/rxjava/service/impl/MovieObservableServiceImpl.java @@ -0,0 +1,35 @@ +package com.baeldung.rxjava.service.impl; + +import com.baeldung.model.Movie; +import com.baeldung.rxjava.service.MovieObservableService; + +import rx.Observable; + +public class MovieObservableServiceImpl implements MovieObservableService { + + @Override + public Observable getMovie() { + Movie movie = new Movie(); + movie.setName("The Godfather"); + movie.setYear("1972"); + movie.setDirector("Coppola"); + movie.setRating(9.2); + return Observable.just(movie); + } + + @Override + public Observable getMovies() { + Movie movie = new Movie(); + movie.setName("The Godfather"); + movie.setYear("1972"); + movie.setDirector("Coppola"); + movie.setRating(9.2); + Movie movie2 = new Movie(); + movie2.setName("The Godfather Part 2"); + movie2.setYear("1974"); + movie2.setDirector("Coppola"); + movie2.setRating(9.0); + return Observable.just(movie, movie2); + + } +} diff --git a/ratpack/src/main/java/com/baeldung/rxjava/service/impl/MoviePromiseServiceImpl.java b/ratpack/src/main/java/com/baeldung/rxjava/service/impl/MoviePromiseServiceImpl.java new file mode 100644 index 0000000000..a66b1e79d6 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/rxjava/service/impl/MoviePromiseServiceImpl.java @@ -0,0 +1,41 @@ +package com.baeldung.rxjava.service.impl; + +import java.util.ArrayList; +import java.util.List; + +import com.baeldung.model.Movie; +import com.baeldung.rxjava.service.MoviePromiseService; + +import ratpack.exec.Promise; + +public class MoviePromiseServiceImpl implements MoviePromiseService { + + @Override + public Promise getMovie() { + Movie movie = new Movie(); + movie.setName("The Godfather"); + movie.setYear("1972"); + movie.setDirector("Coppola"); + movie.setRating(9.2); + return Promise.value(movie); + } + + @Override + public Promise> getMovies() { + Movie movie = new Movie(); + movie.setName("The Godfather"); + movie.setYear("1972"); + movie.setDirector("Coppola"); + movie.setRating(9.2); + Movie movie2 = new Movie(); + movie2.setName("The Godfather Part 2"); + movie2.setYear("1974"); + movie2.setDirector("Coppola"); + movie2.setRating(9.0); + List movies = new ArrayList<>(); + movies.add(movie); + movies.add(movie2); + return Promise.value(movies); + } + +} diff --git a/reactor-core/README.md b/reactor-core/README.md index 6f90e59894..5f9d2d1bc2 100644 --- a/reactor-core/README.md +++ b/reactor-core/README.md @@ -2,3 +2,4 @@ - [Intro To Reactor Core](http://www.baeldung.com/reactor-core) - [Combining Publishers in Project Reactor](http://www.baeldung.com/reactor-combine-streams) +- [Programmatically Creating Sequences with Project Reactor](https://www.baeldung.com/flux-sequences-reactor) diff --git a/reactor-core/pom.xml b/reactor-core/pom.xml index db9550df7b..66c634e113 100644 --- a/reactor-core/pom.xml +++ b/reactor-core/pom.xml @@ -16,7 +16,13 @@ io.projectreactor reactor-core - ${reactor-core.version} + ${reactor.version} + + + io.projectreactor + reactor-test + ${reactor.version} + test org.assertj @@ -24,16 +30,10 @@ ${assertj.version} test - - io.projectreactor - reactor-test - ${reactor-core.version} - test - - 3.1.3.RELEASE + 3.2.6.RELEASE 3.6.1 diff --git a/reactor-core/src/main/java/com/baeldung/reactor/creation/FibonacciState.java b/reactor-core/src/main/java/com/baeldung/reactor/creation/FibonacciState.java new file mode 100644 index 0000000000..291002e1f9 --- /dev/null +++ b/reactor-core/src/main/java/com/baeldung/reactor/creation/FibonacciState.java @@ -0,0 +1,27 @@ +package com.baeldung.reactor.creation; + +public class FibonacciState { + private int former; + private int latter; + + public FibonacciState(int former, int latter) { + this.former = former; + this.latter = latter; + } + + public int getFormer() { + return former; + } + + public void setFormer(int former) { + this.former = former; + } + + public int getLatter() { + return latter; + } + + public void setLatter(int latter) { + this.latter = latter; + } +} diff --git a/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceCreator.java b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceCreator.java new file mode 100644 index 0000000000..fb53b1cab1 --- /dev/null +++ b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceCreator.java @@ -0,0 +1,14 @@ +package com.baeldung.reactor.creation; + +import reactor.core.publisher.Flux; + +import java.util.List; +import java.util.function.Consumer; + +public class SequenceCreator { + public Consumer> consumer; + + public Flux createNumberSequence() { + return Flux.create(sink -> SequenceCreator.this.consumer = items -> items.forEach(sink::next)); + } +} diff --git a/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceGenerator.java b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceGenerator.java new file mode 100644 index 0000000000..44d83d06bf --- /dev/null +++ b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceGenerator.java @@ -0,0 +1,31 @@ +package com.baeldung.reactor.creation; + +import reactor.core.publisher.Flux; +import reactor.util.function.Tuples; + +public class SequenceGenerator { + public Flux generateFibonacciWithTuples() { + return Flux.generate( + () -> Tuples.of(0, 1), + (state, sink) -> { + sink.next(state.getT1()); + return Tuples.of(state.getT2(), state.getT1() + state.getT2()); + } + ); + } + + public Flux generateFibonacciWithCustomClass(int limit) { + return Flux.generate( + () -> new FibonacciState(0, 1), + (state, sink) -> { + sink.next(state.getFormer()); + if (state.getLatter() > limit) { + sink.complete(); + } + int temp = state.getFormer(); + state.setFormer(state.getLatter()); + state.setLatter(temp + state.getLatter()); + return state; + }); + } +} diff --git a/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceHandler.java b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceHandler.java new file mode 100644 index 0000000000..a9611c63e2 --- /dev/null +++ b/reactor-core/src/main/java/com/baeldung/reactor/creation/SequenceHandler.java @@ -0,0 +1,13 @@ +package com.baeldung.reactor.creation; + +import reactor.core.publisher.Flux; + +public class SequenceHandler { + public Flux handleIntegerSequence(Flux sequence) { + return sequence.handle((number, sink) -> { + if (number % 2 == 0) { + sink.next(number / 2); + } + }); + } +} diff --git a/reactor-core/src/test/java/com/baeldung/reactor/creation/SequenceUnitTest.java b/reactor-core/src/test/java/com/baeldung/reactor/creation/SequenceUnitTest.java new file mode 100644 index 0000000000..78af1d2478 --- /dev/null +++ b/reactor-core/src/test/java/com/baeldung/reactor/creation/SequenceUnitTest.java @@ -0,0 +1,70 @@ +package com.baeldung.reactor.creation; + +import org.junit.Test; +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SequenceUnitTest { + @Test + public void whenGeneratingNumbersWithTuplesState_thenFibonacciSequenceIsProduced() { + SequenceGenerator sequenceGenerator = new SequenceGenerator(); + Flux fibonacciFlux = sequenceGenerator.generateFibonacciWithTuples().take(5); + + StepVerifier.create(fibonacciFlux) + .expectNext(0, 1, 1, 2, 3) + .expectComplete() + .verify(); + } + + @Test + public void whenGeneratingNumbersWithCustomClass_thenFibonacciSequenceIsProduced() { + SequenceGenerator sequenceGenerator = new SequenceGenerator(); + + StepVerifier.create(sequenceGenerator.generateFibonacciWithCustomClass(10)) + .expectNext(0, 1, 1, 2, 3, 5, 8) + .expectComplete() + .verify(); + } + + @Test + public void whenCreatingNumbers_thenSequenceIsProducedAsynchronously() throws InterruptedException { + SequenceGenerator sequenceGenerator = new SequenceGenerator(); + List sequence1 = sequenceGenerator.generateFibonacciWithTuples().take(3).collectList().block(); + List sequence2 = sequenceGenerator.generateFibonacciWithTuples().take(4).collectList().block(); + + SequenceCreator sequenceCreator = new SequenceCreator(); + Thread producingThread1 = new Thread( + () -> sequenceCreator.consumer.accept(sequence1) + ); + Thread producingThread2 = new Thread( + () -> sequenceCreator.consumer.accept(sequence2) + ); + + List consolidated = new ArrayList<>(); + sequenceCreator.createNumberSequence().subscribe(consolidated::add); + + producingThread1.start(); + producingThread2.start(); + producingThread1.join(); + producingThread2.join(); + + assertThat(consolidated).containsExactlyInAnyOrder(0, 1, 1, 0, 1, 1, 2); + } + + @Test + public void whenHandlingNumbers_thenSequenceIsMappedAndFiltered() { + SequenceHandler sequenceHandler = new SequenceHandler(); + SequenceGenerator sequenceGenerator = new SequenceGenerator(); + Flux sequence = sequenceGenerator.generateFibonacciWithTuples().take(10); + + StepVerifier.create(sequenceHandler.handleIntegerSequence(sequence)) + .expectNext(0, 1, 4, 17) + .expectComplete() + .verify(); + } +} diff --git a/rest-with-spark-java/pom.xml b/rest-with-spark-java/pom.xml index f7c91f8827..fc78ac6b86 100644 --- a/rest-with-spark-java/pom.xml +++ b/rest-with-spark-java/pom.xml @@ -23,19 +23,17 @@ com.fasterxml.jackson.core jackson-core - ${jackson-core.version} + ${jackson.version} com.fasterxml.jackson.core jackson-databind - ${jackson-databind.version} + ${jackson.version} 2.5.4 - 2.9.7 - 2.9.7 diff --git a/restx/pom.xml b/restx/pom.xml index cc503f89b6..10c843a208 100644 --- a/restx/pom.xml +++ b/restx/pom.xml @@ -5,7 +5,7 @@ 4.0.0 restx 0.1-SNAPSHOT - restx-demo + restx war @@ -151,6 +151,6 @@ 1.8 1.8 0.35-rc4 - 1.0.13 + 1.2.3 diff --git a/restx/src/main/java/restx/demo/rest/HelloResource.java b/restx/src/main/java/restx/demo/rest/HelloResource.java index 5cb2c2a5e6..115212ddf9 100644 --- a/restx/src/main/java/restx/demo/rest/HelloResource.java +++ b/restx/src/main/java/restx/demo/rest/HelloResource.java @@ -3,6 +3,8 @@ package restx.demo.rest; import restx.demo.domain.Message; import restx.demo.Roles; import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; + import restx.annotations.GET; import restx.annotations.POST; import restx.annotations.RestxResource; @@ -29,7 +31,7 @@ public class HelloResource { return new Message().setMessage(String.format( "hello %s, it's %s", RestxSession.current().getPrincipal().get().getName(), - DateTime.now().toString("HH:mm:ss"))); + DateTime.now(DateTimeZone.UTC).toString("HH:mm:ss"))); } /** @@ -44,7 +46,7 @@ public class HelloResource { public Message helloPublic(String who) { return new Message().setMessage(String.format( "hello %s, it's %s", - who, DateTime.now().toString("HH:mm:ss"))); + who, DateTime.now(DateTimeZone.UTC).toString("HH:mm:ss"))); } public static class MyPOJO { diff --git a/restx/src/test/resources/specs/hello/should_admin_say_hello.spec.yaml b/restx/src/test/resources/specs/hello/should_admin_say_hello.spec.yaml index 1b7b8f0f90..7a8bd9119f 100644 --- a/restx/src/test/resources/specs/hello/should_admin_say_hello.spec.yaml +++ b/restx/src/test/resources/specs/hello/should_admin_say_hello.spec.yaml @@ -7,4 +7,4 @@ wts: GET message $RestxSession: {"_expires":"2013-09-27T01:18:00.822+02:00","principal":"admin","sessionKey":"e2b4430f-9541-4602-9a3a-413d17c56a6b"} then: | - {"message":"hello admin, it's 01:18:00"} + {"message":"hello admin, it's 23:18:00"} diff --git a/restx/src/test/resources/specs/hello/should_anyone_say_hello.spec.yaml b/restx/src/test/resources/specs/hello/should_anyone_say_hello.spec.yaml index 29b6faca34..d23e5ae6bf 100644 --- a/restx/src/test/resources/specs/hello/should_anyone_say_hello.spec.yaml +++ b/restx/src/test/resources/specs/hello/should_anyone_say_hello.spec.yaml @@ -5,4 +5,4 @@ wts: - when: | GET hello?who=xavier then: | - {"message":"hello xavier, it's 01:18:00"} + {"message":"hello xavier, it's 23:18:00"} diff --git a/restx/src/test/resources/specs/hello/should_user1_say_hello.spec.yaml b/restx/src/test/resources/specs/hello/should_user1_say_hello.spec.yaml index 791a3a2776..2db8a01003 100644 --- a/restx/src/test/resources/specs/hello/should_user1_say_hello.spec.yaml +++ b/restx/src/test/resources/specs/hello/should_user1_say_hello.spec.yaml @@ -7,4 +7,4 @@ wts: GET message $RestxSession: {"_expires":"2013-09-27T01:18:00.822+02:00","principal":"user1","sessionKey":"e2b4430f-9541-4602-9a3a-413d17c56a6b"} then: | - {"message":"hello user1, it's 01:18:00"} + {"message":"hello user1, it's 23:18:00"} diff --git a/rule-engines/pom.xml b/rule-engines/pom.xml new file mode 100644 index 0000000000..2ce82ed22b --- /dev/null +++ b/rule-engines/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + rule-engines + rule-engines + pom + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + .. + + + + easy-rules + openl-tablets + rulebook + + + diff --git a/rxjava-2/pom.xml b/rxjava-2/pom.xml index 2519516f45..47d16ec8dd 100644 --- a/rxjava-2/pom.xml +++ b/rxjava-2/pom.xml @@ -4,6 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 rxjava-2 + rxjava-2 1.0-SNAPSHOT diff --git a/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksManualTest.java b/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksManualTest.java new file mode 100644 index 0000000000..b79fa9af22 --- /dev/null +++ b/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksManualTest.java @@ -0,0 +1,84 @@ +package com.baeldung.rxjava; + +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Test; + +import io.reactivex.Observable; +import io.reactivex.plugins.RxJavaPlugins; +import io.reactivex.schedulers.Schedulers; + +public class RxJavaHooksManualTest { + + private boolean initHookCalled = false; + private boolean hookCalled = false; + + @Test + public void givenIOScheduler_whenCalled_shouldExecuteTheHooks() { + + RxJavaPlugins.setInitIoSchedulerHandler((scheduler) -> { + initHookCalled = true; + return scheduler.call(); + }); + + RxJavaPlugins.setIoSchedulerHandler((scheduler) -> { + hookCalled = true; + return scheduler; + }); + + Observable.range(1, 10) + .map(v -> v * 2) + .subscribeOn(Schedulers.io()) + .test(); + assertTrue(hookCalled && initHookCalled); + } + + @Test + public void givenNewThreadScheduler_whenCalled_shouldExecuteTheHook() { + + RxJavaPlugins.setInitNewThreadSchedulerHandler((scheduler) -> { + initHookCalled = true; + return scheduler.call(); + }); + + RxJavaPlugins.setNewThreadSchedulerHandler((scheduler) -> { + hookCalled = true; + return scheduler; + }); + + Observable.range(1, 15) + .map(v -> v * 2) + .subscribeOn(Schedulers.newThread()) + .test(); + assertTrue(hookCalled && initHookCalled); + } + + @Test + public void givenSingleScheduler_whenCalled_shouldExecuteTheHooks() { + + RxJavaPlugins.setInitSingleSchedulerHandler((scheduler) -> { + initHookCalled = true; + return scheduler.call(); + }); + + RxJavaPlugins.setSingleSchedulerHandler((scheduler) -> { + hookCalled = true; + return scheduler; + }); + + Observable.range(1, 10) + .map(v -> v * 2) + .subscribeOn(Schedulers.single()) + .test(); + assertTrue(hookCalled && initHookCalled); + + } + + @After + public void reset() { + hookCalled = false; + initHookCalled = false; + RxJavaPlugins.reset(); + } +} diff --git a/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksUnitTest.java b/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksUnitTest.java new file mode 100644 index 0000000000..dd4287a4a9 --- /dev/null +++ b/rxjava-2/src/test/java/com/baeldung/rxjava/RxJavaHooksUnitTest.java @@ -0,0 +1,244 @@ +package com.baeldung.rxjava; + +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Test; + +import io.reactivex.Completable; +import io.reactivex.Flowable; +import io.reactivex.Maybe; +import io.reactivex.Observable; +import io.reactivex.Single; +import io.reactivex.flowables.ConnectableFlowable; +import io.reactivex.observables.ConnectableObservable; +import io.reactivex.plugins.RxJavaPlugins; +import io.reactivex.schedulers.Schedulers; + +public class RxJavaHooksUnitTest { + + private boolean initHookCalled = false; + private boolean hookCalled = false; + + @Test + public void givenObservable_whenError_shouldExecuteTheHook() { + RxJavaPlugins.setErrorHandler(throwable -> { + hookCalled = true; + }); + + Observable.error(new IllegalStateException()) + .subscribe(); + assertTrue(hookCalled); + } + + @Test + public void givenCompletable_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnCompletableAssembly(completable -> { + hookCalled = true; + return completable; + }); + Completable.fromSingle(Single.just(1)); + assertTrue(hookCalled); + } + + @Test + public void givenCompletable_whenSubscribed_shouldExecuteTheHook() { + + RxJavaPlugins.setOnCompletableSubscribe((completable, observer) -> { + hookCalled = true; + return observer; + }); + + Completable.fromSingle(Single.just(1)) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenObservable_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnObservableAssembly(observable -> { + hookCalled = true; + return observable; + }); + + Observable.range(1, 10); + assertTrue(hookCalled); + } + + @Test + public void givenObservable_whenSubscribed_shouldExecuteTheHook() { + + RxJavaPlugins.setOnObservableSubscribe((observable, observer) -> { + hookCalled = true; + return observer; + }); + + Observable.range(1, 10) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenConnectableObservable_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnConnectableObservableAssembly(connectableObservable -> { + hookCalled = true; + return connectableObservable; + }); + + ConnectableObservable.range(1, 10) + .publish() + .connect(); + assertTrue(hookCalled); + } + + @Test + public void givenFlowable_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnFlowableAssembly(flowable -> { + hookCalled = true; + return flowable; + }); + + Flowable.range(1, 10); + assertTrue(hookCalled); + } + + @Test + public void givenFlowable_whenSubscribed_shouldExecuteTheHook() { + + RxJavaPlugins.setOnFlowableSubscribe((flowable, observer) -> { + hookCalled = true; + return observer; + }); + + Flowable.range(1, 10) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenConnectableFlowable_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnConnectableFlowableAssembly(connectableFlowable -> { + hookCalled = true; + return connectableFlowable; + }); + + ConnectableFlowable.range(1, 10) + .publish() + .connect(); + assertTrue(hookCalled); + } + + @Test + public void givenParallel_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnParallelAssembly(parallelFlowable -> { + hookCalled = true; + return parallelFlowable; + }); + + Flowable.range(1, 10) + .parallel(); + assertTrue(hookCalled); + } + + @Test + public void givenMaybe_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnMaybeAssembly(maybe -> { + hookCalled = true; + return maybe; + }); + + Maybe.just(1); + assertTrue(hookCalled); + } + + @Test + public void givenMaybe_whenSubscribed_shouldExecuteTheHook() { + + RxJavaPlugins.setOnMaybeSubscribe((maybe, observer) -> { + hookCalled = true; + return observer; + }); + + Maybe.just(1) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenSingle_whenAssembled_shouldExecuteTheHook() { + + RxJavaPlugins.setOnSingleAssembly(single -> { + hookCalled = true; + return single; + }); + + Single.just(1); + assertTrue(hookCalled); + } + + @Test + public void givenSingle_whenSubscribed_shouldExecuteTheHook() { + + RxJavaPlugins.setOnSingleSubscribe((single, observer) -> { + hookCalled = true; + return observer; + }); + + Single.just(1) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenAnyScheduler_whenCalled_shouldExecuteTheHook() { + + RxJavaPlugins.setScheduleHandler((runnable) -> { + hookCalled = true; + return runnable; + }); + + Observable.range(1, 10) + .map(v -> v * 2) + .subscribeOn(Schedulers.single()) + .test(); + hookCalled = false; + Observable.range(1, 10) + .map(v -> v * 2) + .subscribeOn(Schedulers.computation()) + .test(); + assertTrue(hookCalled); + } + + @Test + public void givenComputationScheduler_whenCalled_shouldExecuteTheHooks() { + + RxJavaPlugins.setInitComputationSchedulerHandler((scheduler) -> { + initHookCalled = true; + return scheduler.call(); + }); + RxJavaPlugins.setComputationSchedulerHandler((scheduler) -> { + hookCalled = true; + return scheduler; + }); + + Observable.range(1, 10) + .map(v -> v * 2) + .subscribeOn(Schedulers.computation()) + .test(); + assertTrue(hookCalled && initHookCalled); + } + + @After + public void reset() { + initHookCalled = false; + hookCalled = false; + RxJavaPlugins.reset(); + } +} diff --git a/software-security/sql-injection-samples/README.md b/software-security/sql-injection-samples/README.md new file mode 100644 index 0000000000..7a077074ac --- /dev/null +++ b/software-security/sql-injection-samples/README.md @@ -0,0 +1,3 @@ +## Relevant articles: + +- [SQL Injection and How to Prevent It?](https://www.baeldung.com/sql-injection) diff --git a/spark-java/README.md b/spark-java/README.md index 711607bd4e..5abe78263c 100644 --- a/spark-java/README.md +++ b/spark-java/README.md @@ -3,4 +3,4 @@ ## Spark Java Framework Tutorial Sample Project ### Relevant Articles -- [Intro to Spark Java Framework](http://www.baeldung.com/spark-framework-rest-api) +- [Building an API With the Spark Java Framework](http://www.baeldung.com/spark-framework-rest-api) diff --git a/spring-5-mvc/README.md b/spring-5-mvc/README.md index fa9d48ab72..7e83077f54 100644 --- a/spring-5-mvc/README.md +++ b/spring-5-mvc/README.md @@ -2,4 +2,3 @@ - [Spring Boot and Kotlin](http://www.baeldung.com/spring-boot-kotlin) - [Spring MVC Streaming and SSE Request Processing](https://www.baeldung.com/spring-mvc-sse-streams) - [Overview and Need for DelegatingFilterProxy in Spring](https://www.baeldung.com/spring-delegating-filter-proxy) -- [A Controller, Service and DAO Example with Spring Boot and JSF](https://www.baeldung.com/jsf-spring-boot-controller-service-dao) diff --git a/spring-5-reactive-oauth/pom.xml b/spring-5-reactive-oauth/pom.xml index 86a5233ad4..ff076985e4 100644 --- a/spring-5-reactive-oauth/pom.xml +++ b/spring-5-reactive-oauth/pom.xml @@ -10,11 +10,11 @@ WebFluc and Spring Security OAuth - org.springframework.boot - spring-boot-starter-parent - 2.1.0.RELEASE - - + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 + @@ -70,6 +70,7 @@ UTF-8 UTF-8 1.8 + 2.1.0.RELEASE diff --git a/spring-5-reactive/README.md b/spring-5-reactive/README.md index c39bb616f8..538a15c879 100644 --- a/spring-5-reactive/README.md +++ b/spring-5-reactive/README.md @@ -7,7 +7,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Introduction to the Functional Web Framework in Spring 5](http://www.baeldung.com/spring-5-functional-web) - [Spring 5 WebClient](http://www.baeldung.com/spring-5-webclient) -- [Exploring the Spring 5 MVC URL Matching Improvements](http://www.baeldung.com/spring-5-mvc-url-matching) +- [Exploring the Spring 5 WebFlux URL Matching](http://www.baeldung.com/spring-5-mvc-url-matching) - [Reactive WebSockets with Spring 5](http://www.baeldung.com/spring-5-reactive-websockets) - [Spring Webflux Filters](http://www.baeldung.com/spring-webflux-filters) - [How to Set a Header on a Response with Spring 5](http://www.baeldung.com/spring-response-header) @@ -19,3 +19,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Logging a Reactive Sequence](https://www.baeldung.com/spring-reactive-sequence-logging) - [Testing Reactive Streams Using StepVerifier and TestPublisher](https://www.baeldung.com/reactive-streams-step-verifier-test-publisher) - [Debugging Reactive Streams in Spring 5](https://www.baeldung.com/spring-debugging-reactive-streams) +- [Static Content in Spring WebFlux](https://www.baeldung.com/spring-webflux-static-content) diff --git a/spring-5-reactive/pom.xml b/spring-5-reactive/pom.xml index a1eb6f4c8a..8d5324a673 100644 --- a/spring-5-reactive/pom.xml +++ b/spring-5-reactive/pom.xml @@ -124,6 +124,28 @@ + + maven-resources-plugin + 3.0.1 + + + copy-resources + validate + + copy-resources + + + + + src/main/assets + true + + + ${basedir}/target/classes/assets + + + + org.springframework.boot spring-boot-maven-plugin diff --git a/spring-5-reactive/src/main/assets/index.html b/spring-5-reactive/src/main/assets/index.html new file mode 100644 index 0000000000..047514df1c --- /dev/null +++ b/spring-5-reactive/src/main/assets/index.html @@ -0,0 +1,10 @@ + + + + + Baeldung: Static Content in Spring WebFlux + + +Example Spring Web Flux and web resources configuration + + \ No newline at end of file diff --git a/spring-5-reactive/src/main/java/com/baeldung/staticcontent/StaticContentApplication.java b/spring-5-reactive/src/main/java/com/baeldung/staticcontent/StaticContentApplication.java new file mode 100644 index 0000000000..31a3de4927 --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/staticcontent/StaticContentApplication.java @@ -0,0 +1,28 @@ +package com.baeldung.staticcontent; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +import java.util.Collections; + +@SpringBootApplication +public class StaticContentApplication { + + public static void main(String[] args) { + SpringApplication app = new SpringApplication(StaticContentApplication.class); + app.setDefaultProperties(Collections.singletonMap("server.port", "8084")); + app.run(args); + } + + @Bean + public SecurityWebFilterChain staticContentSpringSecurityFilterChain(ServerHttpSecurity http) { + http.authorizeExchange() + .anyExchange() + .permitAll(); + return http.build(); + } + +} diff --git a/spring-5-reactive/src/main/java/com/baeldung/staticcontent/StaticContentConfig.java b/spring-5-reactive/src/main/java/com/baeldung/staticcontent/StaticContentConfig.java new file mode 100644 index 0000000000..1fbb9958e7 --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/staticcontent/StaticContentConfig.java @@ -0,0 +1,35 @@ +package com.baeldung.staticcontent; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; + +import static org.springframework.web.reactive.function.server.RequestPredicates.GET; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; +import static org.springframework.web.reactive.function.server.ServerResponse.ok; + +@Configuration +public class StaticContentConfig { + + @Bean + public RouterFunction htmlRouter(@Value("classpath:/public/index.html") Resource html) { + return route( + GET("/"), + request -> ok() + .contentType(MediaType.TEXT_HTML) + .syncBody(html) + ); + } + + @Bean + public RouterFunction imgRouter() { + return RouterFunctions.resources("/img/**", new ClassPathResource("img/")); + } + +} diff --git a/spring-5-reactive/src/main/resources/application-assets-custom-location.properties b/spring-5-reactive/src/main/resources/application-assets-custom-location.properties new file mode 100644 index 0000000000..9a2dbb04d9 --- /dev/null +++ b/spring-5-reactive/src/main/resources/application-assets-custom-location.properties @@ -0,0 +1,3 @@ +# Use in Static content Example +spring.webflux.static-path-pattern = /assets/** +spring.resources.static-locations = classpath:/assets/ \ No newline at end of file diff --git a/spring-5-reactive/src/main/resources/img/example-image.png b/spring-5-reactive/src/main/resources/img/example-image.png new file mode 100644 index 0000000000..2fa6c7b8c5 Binary files /dev/null and b/spring-5-reactive/src/main/resources/img/example-image.png differ diff --git a/spring-5-reactive/src/main/resources/public/index.html b/spring-5-reactive/src/main/resources/public/index.html new file mode 100644 index 0000000000..7a3b9413cd --- /dev/null +++ b/spring-5-reactive/src/main/resources/public/index.html @@ -0,0 +1,10 @@ + + + + + Baeldung: Static Content in Spring WebFlux + + +Example HTML file + + \ No newline at end of file diff --git a/spring-5-reactive/src/test/java/com/baeldung/staticcontent/StaticContentCustomLocationIntegrationTest.java b/spring-5-reactive/src/test/java/com/baeldung/staticcontent/StaticContentCustomLocationIntegrationTest.java new file mode 100644 index 0000000000..f40ff83738 --- /dev/null +++ b/spring-5-reactive/src/test/java/com/baeldung/staticcontent/StaticContentCustomLocationIntegrationTest.java @@ -0,0 +1,39 @@ +package com.baeldung.staticcontent; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; + + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("assets-custom-location") +public class StaticContentCustomLocationIntegrationTest { + + @Autowired + private WebTestClient client; + + @Test + public void whenRequestingHtmlFileFromCustomLocation_thenReturnThisFileAndTextHtmlContentType() throws Exception { + client.get() + .uri("/assets/index.html") + .exchange() + .expectStatus().isOk() + .expectHeader().valueEquals(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML_VALUE); + } + + @Test + public void whenRequestingMissingStaticResource_thenReturnNotFoundStatus() throws Exception { + client.get() + .uri("/assets/unknown.png") + .exchange() + .expectStatus().isNotFound(); + } + +} \ No newline at end of file diff --git a/spring-5-reactive/src/test/java/com/baeldung/staticcontent/StaticContentDefaultLocationIntegrationTest.java b/spring-5-reactive/src/test/java/com/baeldung/staticcontent/StaticContentDefaultLocationIntegrationTest.java new file mode 100644 index 0000000000..820d6e13ef --- /dev/null +++ b/spring-5-reactive/src/test/java/com/baeldung/staticcontent/StaticContentDefaultLocationIntegrationTest.java @@ -0,0 +1,46 @@ +package com.baeldung.staticcontent; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; + + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class StaticContentDefaultLocationIntegrationTest { + + @Autowired + private WebTestClient client; + + @Test + public void whenRequestingHtmlFileFromDefaultLocation_thenReturnThisFileAndTextHtmlContentType() throws Exception { + client.get() + .uri("/index.html") + .exchange() + .expectStatus().isOk() + .expectHeader().valueEquals(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML_VALUE); + } + + @Test + public void whenRequestingPngImageFromImgLocation_thenReturnThisFileAndImagePngContentType() throws Exception { + client.get() + .uri("/img/example-image.png") + .exchange() + .expectStatus().isOk() + .expectHeader().valueEquals(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE); + } + + @Test + public void whenRequestingMissingStaticResource_thenReturnNotFoundStatus() throws Exception { + client.get() + .uri("/unknown.png") + .exchange() + .expectStatus().isNotFound(); + } + +} \ No newline at end of file diff --git a/spring-5-webflux/.gitignore b/spring-5-webflux/.gitignore new file mode 100644 index 0000000000..aa4871eeea --- /dev/null +++ b/spring-5-webflux/.gitignore @@ -0,0 +1,2 @@ +# Files # +*.log \ No newline at end of file diff --git a/spring-5-webflux/pom.xml b/spring-5-webflux/pom.xml new file mode 100644 index 0000000000..3306fd1729 --- /dev/null +++ b/spring-5-webflux/pom.xml @@ -0,0 +1,63 @@ + + + + 4.0.0 + com.baeldung + spring-5-webflux + 1.0-SNAPSHOT + spring-5-webflux + http://www.baeldung.com + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.projectlombok + lombok + + + + org.springframework.boot + spring-boot-starter-test + test + + + + junit + junit + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/ResponseStatusController.java b/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/ResponseStatusController.java new file mode 100644 index 0000000000..bc4f628ab1 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/ResponseStatusController.java @@ -0,0 +1,64 @@ +package com.baeldung.spring.responsestatus; + +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import static org.springframework.web.reactive.function.server.RequestPredicates.GET; + +@RequestMapping("/statuses") +@RestController +public class ResponseStatusController { + + @GetMapping(value = "/ok", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public Flux ok() { + return Flux.just("ok"); + } + + @GetMapping(value = "/no-content", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @ResponseStatus(HttpStatus.NO_CONTENT) + public Flux noContent() { + return Flux.empty(); + } + + @GetMapping(value = "/accepted", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public Flux accepted(ServerHttpResponse response) { + response.setStatusCode(HttpStatus.ACCEPTED); + return Flux.just("accepted"); + } + + @GetMapping(value = "/bad-request") + public Mono badRequest() { + return Mono.error(new IllegalArgumentException()); + } + + @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "Illegal arguments") + @ExceptionHandler(IllegalArgumentException.class) + public void illegalArgument() { + + } + + @GetMapping(value = "/unauthorized") + public ResponseEntity> unathorized() { + return ResponseEntity + .status(HttpStatus.UNAUTHORIZED) + .header("X-Reason", "user-invalid") + .body(Mono.just("unauthorized")); + } + + @Bean + public RouterFunction notFound() { + return RouterFunctions.route(GET("/statuses/not-found"), request -> ServerResponse + .notFound() + .build()); + } + +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/SpringResponseStatusApp.java b/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/SpringResponseStatusApp.java new file mode 100644 index 0000000000..1d90511d9d --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/responsestatus/SpringResponseStatusApp.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.responsestatus; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringResponseStatusApp { + + public static void main(String[] args) { + SpringApplication.run(SpringResponseStatusApp.class, args); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java new file mode 100644 index 0000000000..f9de3b4006 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java @@ -0,0 +1,36 @@ +package com.baeldung.spring.serverconfig; + +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.netty.NettyServerCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import reactor.netty.http.server.HttpServer; + +@Configuration +@Profile("skipAutoConfig") +public class CustomNettyWebServerFactory { + + @Bean + public NettyReactiveWebServerFactory nettyReactiveWebServerFactory() { + NettyReactiveWebServerFactory webServerFactory = new NettyReactiveWebServerFactory(); + webServerFactory.addServerCustomizers(new EventLoopNettyCustomizer()); + return webServerFactory; + } + + private static class EventLoopNettyCustomizer implements NettyServerCustomizer { + + @Override + public HttpServer apply(HttpServer httpServer) { + EventLoopGroup parentGroup = new NioEventLoopGroup(); + EventLoopGroup childGroup = new NioEventLoopGroup(); + return httpServer + .tcpConfiguration(tcpServer -> tcpServer.bootstrap( + serverBootstrap -> serverBootstrap.group(parentGroup, childGroup).channel(NioServerSocketChannel.class) + )); + } + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingController.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingController.java new file mode 100644 index 0000000000..990ea5cf83 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingController.java @@ -0,0 +1,23 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +@RestController +@RequestMapping("/greet") +public class GreetingController { + + private final GreetingService greetingService; + + public GreetingController(GreetingService greetingService) { + this.greetingService = greetingService; + } + + @GetMapping("/{name}") + private Mono greet(@PathVariable String name) { + return greetingService.greet(name); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingService.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingService.java new file mode 100644 index 0000000000..a6243b2bd0 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingService.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +public class GreetingService { + + public Mono greet(String name) { + return Mono.just("Greeting " + name); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactoryPortCustomizer.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactoryPortCustomizer.java new file mode 100644 index 0000000000..fdde130286 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactoryPortCustomizer.java @@ -0,0 +1,30 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.netty.NettyServerCustomizer; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.stereotype.Component; +import reactor.netty.http.server.HttpServer; + +@Component +public class NettyWebServerFactoryPortCustomizer implements WebServerFactoryCustomizer { + + @Override + public void customize(NettyReactiveWebServerFactory serverFactory) { + serverFactory.addServerCustomizers(new PortCustomizer(8443)); + } + + private static class PortCustomizer implements NettyServerCustomizer { + + private final int port; + + private PortCustomizer(int port) { + this.port = port; + } + + @Override + public HttpServer apply(HttpServer httpServer) { + return httpServer.port(port); + } + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactorySslCustomizer.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactorySslCustomizer.java new file mode 100644 index 0000000000..cf4e5ac8ea --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactorySslCustomizer.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.netty.SslServerCustomizer; +import org.springframework.boot.web.server.Http2; +import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.stereotype.Component; + +@Component +public class NettyWebServerFactorySslCustomizer implements WebServerFactoryCustomizer { + + @Override + public void customize(NettyReactiveWebServerFactory serverFactory) { + Ssl ssl = new Ssl(); + ssl.setEnabled(true); + ssl.setKeyStore("classpath:sample.jks"); + ssl.setKeyAlias("alias"); + ssl.setKeyPassword("password"); + ssl.setKeyStorePassword("secret"); + Http2 http2 = new Http2(); + http2.setEnabled(false); + serverFactory.addServerCustomizers(new SslServerCustomizer(ssl, http2, null)); + serverFactory.setPort(8443); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/ServerConfigApplication.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/ServerConfigApplication.java new file mode 100644 index 0000000000..b4f6006be3 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/ServerConfigApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ServerConfigApplication { + + public static void main(String[] args) { + SpringApplication.run(ServerConfigApplication.class, args); + } +} diff --git a/spring-5-webflux/src/main/resources/logback.xml b/spring-5-webflux/src/main/resources/logback.xml new file mode 100644 index 0000000000..48b68c6bf1 --- /dev/null +++ b/spring-5-webflux/src/main/resources/logback.xml @@ -0,0 +1,31 @@ + + + + + + %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable + + + + + + netty-access.log + + %msg%n + + + + + + + + + + + + + + + + diff --git a/spring-5-webflux/src/main/resources/sample.jks b/spring-5-webflux/src/main/resources/sample.jks new file mode 100644 index 0000000000..6aa9a28053 Binary files /dev/null and b/spring-5-webflux/src/main/resources/sample.jks differ diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerLiveTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerLiveTest.java new file mode 100644 index 0000000000..4c6708e423 --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerLiveTest.java @@ -0,0 +1,70 @@ +package com.baeldung.spring.responsestatus; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class ResponseStatusControllerLiveTest { + + @Autowired + private WebTestClient testClient; + + @Test + public void whenCallRest_thenStatusIsOk() { + testClient.get() + .uri("/statuses/ok") + .exchange() + .expectStatus() + .isOk(); + } + + @Test + public void whenCallRest_thenStatusIsNoContent() { + testClient.get() + .uri("/statuses/no-content") + .exchange() + .expectStatus() + .isNoContent(); + } + + @Test + public void whenCallRest_thenStatusIsAccepted() { + testClient.get() + .uri("/statuses/accepted") + .exchange() + .expectStatus() + .isAccepted(); + } + + @Test + public void whenCallRest_thenStatusIsBadRequest() { + testClient.get() + .uri("/statuses/bad-request") + .exchange() + .expectStatus() + .isBadRequest(); + } + + @Test + public void whenCallRest_thenStatusIsUnauthorized() { + testClient.get() + .uri("/statuses/unauthorized") + .exchange() + .expectStatus() + .isUnauthorized(); + } + + @Test + public void whenCallRest_thenStatusIsNotFound() { + testClient.get() + .uri("/statuses/not-found") + .exchange() + .expectStatus() + .isNotFound(); + } +} diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingControllerIntegrationTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingControllerIntegrationTest.java new file mode 100644 index 0000000000..ce156beb3f --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingControllerIntegrationTest.java @@ -0,0 +1,41 @@ +package com.baeldung.spring.serverconfig; + +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import reactor.core.publisher.Mono; + +@RunWith(SpringRunner.class) +@WebFluxTest +public class GreetingControllerIntegrationTest { + + @Autowired + private WebTestClient webClient; + + @MockBean + private GreetingService greetingService; + + private final String name = "Baeldung"; + + @Before + public void setUp() { + when(greetingService.greet(name)).thenReturn(Mono.just("Greeting Baeldung")); + } + + @Test + public void shouldGreet() { + webClient.get().uri("/greet/{name}", name) + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Greeting Baeldung"); + } +} diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingLiveTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingLiveTest.java new file mode 100644 index 0000000000..2400272c6e --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingLiveTest.java @@ -0,0 +1,57 @@ +package com.baeldung.spring.serverconfig; + +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import javax.net.ssl.SSLException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; +import reactor.netty.http.client.HttpClient; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) +@DirtiesContext +public class GreetingLiveTest { + + private static final String BASE_URL = "https://localhost:8443"; + + private WebTestClient webTestClient; + + @Before + public void setup() throws SSLException { + webTestClient = WebTestClient.bindToServer(getConnector()) + .baseUrl(BASE_URL) + .build(); + } + + @Test + public void shouldGreet() { + final String name = "Baeldung"; + + ResponseSpec response = webTestClient.get() + .uri("/greet/{name}", name) + .exchange(); + + response.expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Greeting Baeldung"); + } + + private ReactorClientHttpConnector getConnector() throws SSLException { + SslContext sslContext = SslContextBuilder + .forClient() + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .build(); + HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext)); + return new ReactorClientHttpConnector(httpClient); + } +} diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingSkipAutoConfigLiveTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingSkipAutoConfigLiveTest.java new file mode 100644 index 0000000000..45918dfd70 --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingSkipAutoConfigLiveTest.java @@ -0,0 +1,8 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.test.context.ActiveProfiles; + +@ActiveProfiles("skipAutoConfig") +public class GreetingSkipAutoConfigLiveTest extends GreetingLiveTest { + +} diff --git a/spring-5-webflux/src/test/resources/logback-test.xml b/spring-5-webflux/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..12cedf5952 --- /dev/null +++ b/spring-5-webflux/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + + %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable + + + + + + + diff --git a/spring-5/pom.xml b/spring-5/pom.xml index 701aa3831d..6e4162fbcc 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -89,12 +89,6 @@ org.junit.jupiter junit-jupiter-api - - org.awaitility - awaitility - ${awaitility.version} - test - org.springframework.restdocs @@ -162,7 +156,6 @@ 4.1 ${project.build.directory}/generated-snippets 2.21.0 - 3.1.6 diff --git a/spring-all/README.md b/spring-all/README.md index 0d78efdcf2..a111d2e542 100644 --- a/spring-all/README.md +++ b/spring-all/README.md @@ -11,26 +11,26 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant articles: - [Guide to Spring @Autowired](http://www.baeldung.com/spring-autowire) -- [Properties with Spring](http://www.baeldung.com/properties-with-spring) - checkout the `org.baeldung.properties` package for all scenarios of properties injection and usage +- [Properties with Spring and Spring Boot](http://www.baeldung.com/properties-with-spring) - checkout the `org.baeldung.properties` package for all scenarios of properties injection and usage - [Spring Profiles](http://www.baeldung.com/spring-profiles) - [A Spring Custom Annotation for a Better DAO](http://www.baeldung.com/spring-annotation-bean-pre-processor) - [What's New in Spring 4.3?](http://www.baeldung.com/whats-new-in-spring-4-3) -- [Guide To Running Logic on Startup in Spring](http://www.baeldung.com/running-setup-logic-on-startup-in-spring) +- [Running Setup Data on Startup in Spring](http://www.baeldung.com/running-setup-logic-on-startup-in-spring) - [Quick Guide to Spring Controllers](http://www.baeldung.com/spring-controllers) - [Quick Guide to Spring Bean Scopes](http://www.baeldung.com/spring-bean-scopes) - [Introduction To Ehcache](http://www.baeldung.com/ehcache) - [A Guide to the Spring Task Scheduler](http://www.baeldung.com/spring-task-scheduler) - [Guide to Spring Retry](http://www.baeldung.com/spring-retry) - [Custom Scope in Spring](http://www.baeldung.com/spring-custom-scope) -- [New in Guava 21 common.util.concurrent](http://www.baeldung.com/guava-21-util-concurrent) - [A CLI with Spring Shell](http://www.baeldung.com/spring-shell-cli) - [JasperReports with Spring](http://www.baeldung.com/spring-jasper) - [Model, ModelMap, and ModelView in Spring MVC](http://www.baeldung.com/spring-mvc-model-model-map-model-view) - [A Guide To Caching in Spring](http://www.baeldung.com/spring-cache-tutorial) - [How To Do @Async in Spring](http://www.baeldung.com/spring-async) -- [Quick Guide to the Spring @Order Annotation](http://www.baeldung.com/spring-order) +- [@Order in Spring](http://www.baeldung.com/spring-order) - [Spring Web Contexts](http://www.baeldung.com/spring-web-contexts) - [Spring Cache – Creating a Custom KeyGenerator](http://www.baeldung.com/spring-cache-custom-keygenerator) - [Spring @Primary Annotation](http://www.baeldung.com/spring-primary) - [Spring Events](https://www.baeldung.com/spring-events) - [Spring Null-Safety Annotations](https://www.baeldung.com/spring-null-safety-annotations) +- [Spring JDBC](https://www.baeldung.com/spring-jdbc-jdbctemplate) diff --git a/spring-all/pom.xml b/spring-all/pom.xml index 5872fbdac5..8c88efb970 100644 --- a/spring-all/pom.xml +++ b/spring-all/pom.xml @@ -1,5 +1,5 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-all 0.1-SNAPSHOT @@ -47,12 +47,16 @@ org.springframework spring-websocket - - + + org.springframework spring-messaging - - + + + javax.annotation + javax.annotation-api + ${annotation-api.version} + org.springframework @@ -227,13 +231,13 @@ - + org.baeldung.sample.App 5.0.6.RELEASE 1.2.0.RELEASE - + 1.3.2 5.2.5.Final diff --git a/spring-all/src/main/java/org/baeldung/properties/spring/PropertiesWithJavaConfig.java b/spring-all/src/main/java/org/baeldung/properties/spring/PropertiesWithJavaConfig.java index 08626bb4d2..6589143a94 100644 --- a/spring-all/src/main/java/org/baeldung/properties/spring/PropertiesWithJavaConfig.java +++ b/spring-all/src/main/java/org/baeldung/properties/spring/PropertiesWithJavaConfig.java @@ -7,6 +7,7 @@ import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; @Configuration @PropertySource("classpath:foo.properties") +@PropertySource("classpath:bar.properties") public class PropertiesWithJavaConfig { public PropertiesWithJavaConfig() { diff --git a/spring-all/src/main/java/org/baeldung/sampleabstract/BallService.java b/spring-all/src/main/java/org/baeldung/sampleabstract/BallService.java new file mode 100644 index 0000000000..9a75de7fa1 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sampleabstract/BallService.java @@ -0,0 +1,28 @@ +package org.baeldung.sampleabstract; + +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.PostConstruct; + +public abstract class BallService { + + private RuleRepository ruleRepository; + + private LogRepository logRepository; + + public BallService(RuleRepository ruleRepository) { + this.ruleRepository = ruleRepository; + } + + @Autowired + public final void setLogRepository(LogRepository logRepository) { + this.logRepository = logRepository; + } + + @PostConstruct + public void afterInitialize() { + + System.out.println(ruleRepository.toString()); + System.out.println(logRepository.toString()); + } +} diff --git a/spring-all/src/main/java/org/baeldung/sampleabstract/BasketballService.java b/spring-all/src/main/java/org/baeldung/sampleabstract/BasketballService.java new file mode 100644 index 0000000000..c117231d3c --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sampleabstract/BasketballService.java @@ -0,0 +1,13 @@ +package org.baeldung.sampleabstract; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class BasketballService extends BallService { + + @Autowired + public BasketballService(RuleRepository ruleRepository) { + super(ruleRepository); + } +} diff --git a/spring-all/src/main/java/org/baeldung/sampleabstract/DemoApp.java b/spring-all/src/main/java/org/baeldung/sampleabstract/DemoApp.java new file mode 100644 index 0000000000..615d354ecf --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sampleabstract/DemoApp.java @@ -0,0 +1,18 @@ +package org.baeldung.sampleabstract; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackages = "org.baeldung.sampleabstract") +public class DemoApp { + + + public static void main(String[] args) { + + ApplicationContext applicationContext = new AnnotationConfigApplicationContext(DemoApp.class); + } + +} diff --git a/spring-all/src/main/java/org/baeldung/sampleabstract/LogRepository.java b/spring-all/src/main/java/org/baeldung/sampleabstract/LogRepository.java new file mode 100644 index 0000000000..3a65671493 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sampleabstract/LogRepository.java @@ -0,0 +1,12 @@ +package org.baeldung.sampleabstract; + +import org.springframework.stereotype.Component; + +@Component +public class LogRepository { + + @Override + public String toString() { + return "logRepository"; + } +} diff --git a/spring-all/src/main/java/org/baeldung/sampleabstract/RuleRepository.java b/spring-all/src/main/java/org/baeldung/sampleabstract/RuleRepository.java new file mode 100644 index 0000000000..fd42178ab6 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sampleabstract/RuleRepository.java @@ -0,0 +1,12 @@ +package org.baeldung.sampleabstract; + +import org.springframework.stereotype.Component; + +@Component +public class RuleRepository { + + @Override + public String toString() { + return "ruleRepository"; + } +} diff --git a/spring-all/src/main/resources/configForProperties.xml b/spring-all/src/main/resources/configForProperties.xml index 0f766665eb..459aea3ec6 100644 --- a/spring-all/src/main/resources/configForProperties.xml +++ b/spring-all/src/main/resources/configForProperties.xml @@ -7,7 +7,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd" > - + diff --git a/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesJavaConfigIntegrationTest.java b/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesJavaConfigIntegrationTest.java new file mode 100644 index 0000000000..9cb41c20f7 --- /dev/null +++ b/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesJavaConfigIntegrationTest.java @@ -0,0 +1,25 @@ +package org.baeldung.properties.multiple; + +import org.baeldung.properties.spring.PropertiesWithJavaConfig; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringJUnitConfig(PropertiesWithJavaConfig.class) +public class MultiplePropertiesJavaConfigIntegrationTest { + + @Value("${key.something}") + private String something; + + @Value("${key.something2}") + private String something2; + + + @Test + public void whenReadInjectedValues_thenGetCorrectValues() { + assertThat(something).isEqualTo("val"); + assertThat(something2).isEqualTo("val2"); + } +} diff --git a/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesXmlConfigIntegrationTest.java b/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesXmlConfigIntegrationTest.java new file mode 100644 index 0000000000..b4f81f3541 --- /dev/null +++ b/spring-all/src/test/java/org/baeldung/properties/multiple/MultiplePropertiesXmlConfigIntegrationTest.java @@ -0,0 +1,21 @@ +package org.baeldung.properties.multiple; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringJUnitConfig(locations = "classpath:configForProperties.xml") +public class MultiplePropertiesXmlConfigIntegrationTest { + + @Value("${key.something}") private String something; + + @Value("${key.something2}") private String something2; + + @Test + public void whenReadInjectedValues_thenGetCorrectValues() { + assertThat(something).isEqualTo("val"); + assertThat(something2).isEqualTo("val2"); + } +} diff --git a/spring-boot-angular-ecommerce/src/main/frontend/package.json b/spring-boot-angular-ecommerce/src/main/frontend/package.json index 958e9f1023..17363ef961 100644 --- a/spring-boot-angular-ecommerce/src/main/frontend/package.json +++ b/spring-boot-angular-ecommerce/src/main/frontend/package.json @@ -7,7 +7,7 @@ "build": "ng build", "postbuild": "npm run deploy", "predeploy": "rimraf ../resources/static/ && mkdirp ../resources/static", - "deploy": "copyfiles -f dist/** ../resources/static", + "deploy": "copyfiles -f dist/frontend/** ../resources/static", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" diff --git a/spring-boot-angular/README.md b/spring-boot-angular/README.md new file mode 100644 index 0000000000..cfc1ea69f4 --- /dev/null +++ b/spring-boot-angular/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: +- [Building a Web Application with Spring Boot and Angular](https://www.baeldung.com/spring-boot-angular-web) + diff --git a/spring-boot-angular/angularclient/.angular-cli.json b/spring-boot-angular/angularclient/.angular-cli.json new file mode 100644 index 0000000000..3de2a62f41 --- /dev/null +++ b/spring-boot-angular/angularclient/.angular-cli.json @@ -0,0 +1,60 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "project": { + "name": "sampleapp" + }, + "apps": [ + { + "root": "src", + "outDir": "dist", + "assets": [ + "assets", + "favicon.ico" + ], + "index": "index.html", + "main": "main.ts", + "polyfills": "polyfills.ts", + "test": "test.ts", + "tsconfig": "tsconfig.app.json", + "testTsconfig": "tsconfig.spec.json", + "prefix": "app", + "styles": [ + "styles.css" + ], + "scripts": [], + "environmentSource": "environments/environment.ts", + "environments": { + "dev": "environments/environment.ts", + "prod": "environments/environment.prod.ts" + } + } + ], + "e2e": { + "protractor": { + "config": "./protractor.conf.js" + } + }, + "lint": [ + { + "project": "src/tsconfig.app.json", + "exclude": "**/node_modules/**" + }, + { + "project": "src/tsconfig.spec.json", + "exclude": "**/node_modules/**" + }, + { + "project": "e2e/tsconfig.e2e.json", + "exclude": "**/node_modules/**" + } + ], + "test": { + "karma": { + "config": "./karma.conf.js" + } + }, + "defaults": { + "styleExt": "css", + "component": {} + } +} diff --git a/spring-boot-angular/angularclient/.editorconfig b/spring-boot-angular/angularclient/.editorconfig new file mode 100644 index 0000000000..6e87a003da --- /dev/null +++ b/spring-boot-angular/angularclient/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/spring-boot-angular/angularclient/.gitignore b/spring-boot-angular/angularclient/.gitignore new file mode 100644 index 0000000000..eabf65e51a --- /dev/null +++ b/spring-boot-angular/angularclient/.gitignore @@ -0,0 +1,44 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/dist-server +/tmp +/out-tsc + +# dependencies +/node_modules + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# e2e +/e2e/*.js +/e2e/*.map + +# System Files +.DS_Store +Thumbs.db diff --git a/spring-boot-angular/angularclient/README.md b/spring-boot-angular/angularclient/README.md new file mode 100644 index 0000000000..6fec59bc13 --- /dev/null +++ b/spring-boot-angular/angularclient/README.md @@ -0,0 +1,27 @@ +# Sampleapp + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.7.4. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/spring-boot-angular/angularclient/e2e/app.e2e-spec.ts b/spring-boot-angular/angularclient/e2e/app.e2e-spec.ts new file mode 100644 index 0000000000..d72f8a4e91 --- /dev/null +++ b/spring-boot-angular/angularclient/e2e/app.e2e-spec.ts @@ -0,0 +1,14 @@ +import { AppPage } from './app.po'; + +describe('sampleapp App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getParagraphText()).toEqual('Welcome to app!'); + }); +}); diff --git a/spring-boot-angular/angularclient/e2e/app.po.ts b/spring-boot-angular/angularclient/e2e/app.po.ts new file mode 100644 index 0000000000..82ea75ba50 --- /dev/null +++ b/spring-boot-angular/angularclient/e2e/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get('/'); + } + + getParagraphText() { + return element(by.css('app-root h1')).getText(); + } +} diff --git a/spring-boot-angular/angularclient/e2e/tsconfig.e2e.json b/spring-boot-angular/angularclient/e2e/tsconfig.e2e.json new file mode 100644 index 0000000000..1d9e5edf09 --- /dev/null +++ b/spring-boot-angular/angularclient/e2e/tsconfig.e2e.json @@ -0,0 +1,14 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/e2e", + "baseUrl": "./", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "jasminewd2", + "node" + ] + } +} diff --git a/spring-boot-angular/angularclient/karma.conf.js b/spring-boot-angular/angularclient/karma.conf.js new file mode 100644 index 0000000000..af139fada3 --- /dev/null +++ b/spring-boot-angular/angularclient/karma.conf.js @@ -0,0 +1,33 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular/cli'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular/cli/plugins/karma') + ], + client:{ + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + reports: [ 'html', 'lcovonly' ], + fixWebpackSourcePaths: true + }, + angularCli: { + environment: 'dev' + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; diff --git a/spring-boot-angular/angularclient/package-lock.json b/spring-boot-angular/angularclient/package-lock.json new file mode 100644 index 0000000000..9ddc0a9ae0 --- /dev/null +++ b/spring-boot-angular/angularclient/package-lock.json @@ -0,0 +1,12627 @@ +{ + "name": "sampleapp", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@angular-devkit/build-optimizer": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.3.2.tgz", + "integrity": "sha512-U0BCZtThq5rUfY08shHXpxe8ZhSsiYB/cJjUvAWRTs/ORrs8pbngS6xwseQws8d/vHoVrtqGD9GU9h8AmFRERQ==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "source-map": "^0.5.6", + "typescript": "~2.6.2", + "webpack-sources": "^1.0.1" + }, + "dependencies": { + "typescript": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", + "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", + "dev": true + } + } + }, + "@angular-devkit/core": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.3.2.tgz", + "integrity": "sha512-zABk/iP7YX5SVbmK4e+IX7j2d0D37MQJQiKgWdV3JzfvVJhNJzddiirtT980pIafoq+KyvTgVwXtc+vnux0oeQ==", + "dev": true, + "requires": { + "ajv": "~5.5.1", + "chokidar": "^1.7.0", + "rxjs": "^5.5.6", + "source-map": "^0.5.6" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + } + } + }, + "@angular-devkit/schematics": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.3.2.tgz", + "integrity": "sha512-B6zZoqvHaTJy+vVdA6EtlxnCdGMa5elCa4j9lQLC3JI8DLvMXUWkCIPVbPzJ/GSRR9nsKWpvYMYaJyfBDUqfhw==", + "dev": true, + "requires": { + "@ngtools/json-schema": "^1.1.0", + "rxjs": "^5.5.6" + } + }, + "@angular/animations": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-5.2.11.tgz", + "integrity": "sha512-J7wKHkFn3wV28/Y1Qm4yjGXVCwXzj1JR5DRjGDTFnxTRacUFx7Nj0ApGhN0b2+V0NOvgxQOvEW415Y22kGoblw==", + "requires": { + "tslib": "^1.7.1" + } + }, + "@angular/cli": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.7.4.tgz", + "integrity": "sha512-URdb1QtnQf+Ievy93wjq7gE81s25BkWUwJFPey+YkphBA3G1lbCAQPiEh2pntBwaIKavgEuCw+Sf2YZdgTVhDA==", + "dev": true, + "requires": { + "@angular-devkit/build-optimizer": "0.3.2", + "@angular-devkit/core": "0.3.2", + "@angular-devkit/schematics": "0.3.2", + "@ngtools/json-schema": "1.2.0", + "@ngtools/webpack": "1.10.2", + "@schematics/angular": "0.3.2", + "@schematics/package-update": "0.3.2", + "ajv": "^6.1.1", + "autoprefixer": "^7.2.3", + "cache-loader": "^1.2.0", + "chalk": "~2.2.0", + "circular-dependency-plugin": "^4.2.1", + "clean-css": "^4.1.11", + "common-tags": "^1.3.1", + "copy-webpack-plugin": "~4.4.1", + "core-object": "^3.1.0", + "denodeify": "^1.2.1", + "ember-cli-string-utils": "^1.0.0", + "extract-text-webpack-plugin": "^3.0.2", + "file-loader": "^1.1.5", + "fs-extra": "^4.0.0", + "glob": "^7.0.3", + "html-webpack-plugin": "^2.29.0", + "istanbul-instrumenter-loader": "^3.0.0", + "karma-source-map-support": "^1.2.0", + "less": "^2.7.2", + "less-loader": "^4.0.5", + "license-webpack-plugin": "^1.0.0", + "loader-utils": "1.1.0", + "lodash": "^4.11.1", + "memory-fs": "^0.4.1", + "minimatch": "^3.0.4", + "node-modules-path": "^1.0.0", + "node-sass": "^4.7.2", + "nopt": "^4.0.1", + "opn": "~5.1.0", + "portfinder": "~1.0.12", + "postcss": "^6.0.16", + "postcss-import": "^11.0.0", + "postcss-loader": "^2.0.10", + "postcss-url": "^7.1.2", + "raw-loader": "^0.5.1", + "resolve": "^1.1.7", + "rxjs": "^5.5.6", + "sass-loader": "^6.0.6", + "semver": "^5.1.0", + "silent-error": "^1.0.0", + "source-map-support": "^0.4.1", + "style-loader": "^0.19.1", + "stylus": "^0.54.5", + "stylus-loader": "^3.0.1", + "uglifyjs-webpack-plugin": "^1.1.8", + "url-loader": "^0.6.2", + "webpack": "~3.11.0", + "webpack-dev-middleware": "~1.12.0", + "webpack-dev-server": "~2.11.0", + "webpack-merge": "^4.1.0", + "webpack-sources": "^1.0.0", + "webpack-subresource-integrity": "^1.0.1" + } + }, + "@angular/common": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-5.2.11.tgz", + "integrity": "sha512-LniJjGAeftUJDJh+2+LEjltcGen08C/VMxQ/eUYmesytKy1sN+MWzh3GbpKfEWtWmyUsYTG9lAAJNo3L3jPwsw==", + "requires": { + "tslib": "^1.7.1" + } + }, + "@angular/compiler": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-5.2.11.tgz", + "integrity": "sha512-ICvB1ud1mxaXUYLb8vhJqiLhGBVocAZGxoHTglv6hMkbrRYcnlB3FZJFOzBvtj+krkd1jamoYLI43UAmesqQ6Q==", + "requires": { + "tslib": "^1.7.1" + } + }, + "@angular/compiler-cli": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-5.2.11.tgz", + "integrity": "sha512-dwrQ0yxoCM/XzKzlm7pTsyg4/6ECjT9emZufGj8t12bLMO8NDn1IJOsqXJA1+onEgQKhlr0Ziwi+96TvDTb1Cg==", + "dev": true, + "requires": { + "chokidar": "^1.4.2", + "minimist": "^1.2.0", + "reflect-metadata": "^0.1.2", + "tsickle": "^0.27.2" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "@angular/core": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-5.2.11.tgz", + "integrity": "sha512-h2vpvXNAdOqKzbVaZcHnHGMT5A8uDnizk6FgGq6SPyw9s3d+/VxZ9LJaPjUk3g2lICA7og1tUel+2YfF971MlQ==", + "requires": { + "tslib": "^1.7.1" + } + }, + "@angular/forms": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-5.2.11.tgz", + "integrity": "sha512-wBllFlIubPclAFRXUc84Kc7TMeKOftzrQraVZ7ooTNeFLLa/FZLN2K8HGyRde8X/XDsMu1XAmjNfkz++spwTzA==", + "requires": { + "tslib": "^1.7.1" + } + }, + "@angular/http": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-5.2.11.tgz", + "integrity": "sha512-eR7wNXh1+6MpcQNb3sq4bJVX03dx50Wl3kpPG+Q7N1VSL0oPQSobaTrR17ac3oFCEfSJn6kkUCqtUXha6wcNHg==", + "requires": { + "tslib": "^1.7.1" + } + }, + "@angular/language-service": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-5.2.11.tgz", + "integrity": "sha512-tgnFAhwBmUs1W0dmcmlBmUlMaOgkoyuSdrcF23lz8W5+nSLb+LnbH5a3blU2NVqA4ESvLKQkPW5dpKa/LuhrPQ==", + "dev": true + }, + "@angular/platform-browser": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-5.2.11.tgz", + "integrity": "sha512-6YZ4IpBFqXx88vEzBZG2WWnaSYXbFWDgG0iT+bZPHAfwsbmqbcMcs7Ogu+XZ4VmK02dTqbrFh7U4P2W+sqrzow==", + "requires": { + "tslib": "^1.7.1" + } + }, + "@angular/platform-browser-dynamic": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-5.2.11.tgz", + "integrity": "sha512-5kKPNULcXNwkyBjpHfF+pq+Yxi8Zl866YSOK9t8txoiQ9Ctw97kMkEJcTetk6MJgBp/NP3YyjtoTAm8oXLerug==", + "requires": { + "tslib": "^1.7.1" + } + }, + "@angular/router": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-5.2.11.tgz", + "integrity": "sha512-NT8xYl7Vr3qPygisek3PlXqNROEjg48GXOEsDEc7c8lDBo3EB9Tf328fWJD0GbLtXZNhmmNNxwIe+qqPFFhFAA==", + "requires": { + "tslib": "^1.7.1" + } + }, + "@ngtools/json-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.2.0.tgz", + "integrity": "sha512-pMh+HDc6mOjUO3agRfB1tInimo7hf67u+0Cska2bfXFe6oU7rSMnr5PLVtiZVgwMoBHpx/6XjBymvcnWPo2Uzg==", + "dev": true + }, + "@ngtools/webpack": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.10.2.tgz", + "integrity": "sha512-3u2zg2rarG3qNLSukBClGADWuq/iNn5SQtlSeAbfKzwBeyLGbF0gN1z1tVx1Bcr8YwFzR6NdRePQmJGcoqq1fg==", + "dev": true, + "requires": { + "chalk": "~2.2.0", + "enhanced-resolve": "^3.1.0", + "loader-utils": "^1.0.2", + "magic-string": "^0.22.3", + "semver": "^5.3.0", + "source-map": "^0.5.6", + "tree-kill": "^1.0.0", + "webpack-sources": "^1.1.0" + } + }, + "@schematics/angular": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.3.2.tgz", + "integrity": "sha512-Elrk0BA951s0ScFZU0AWrpUeJBYVR52DZ1QTIO5R0AhwEd1PW4olI8szPLGQlVW5Sd6H0FA/fyFLIvn2r9v6Rw==", + "dev": true, + "requires": { + "typescript": "~2.6.2" + }, + "dependencies": { + "typescript": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", + "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", + "dev": true + } + } + }, + "@schematics/package-update": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@schematics/package-update/-/package-update-0.3.2.tgz", + "integrity": "sha512-7aVP4994Hu8vRdTTohXkfGWEwLhrdNP3EZnWyBootm5zshWqlQojUGweZe5zwewsKcixeVOiy2YtW+aI4aGSLA==", + "dev": true, + "requires": { + "rxjs": "^5.5.6", + "semver": "^5.3.0", + "semver-intersect": "^1.1.2" + } + }, + "@types/jasmine": { + "version": "2.8.16", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.16.tgz", + "integrity": "sha512-056oRlBBp7MDzr+HoU5su099s/s7wjZ3KcHxLfv+Byqb9MwdLUvsfLgw1VS97hsh3ddxSPyQu+olHMnoVTUY6g==", + "dev": true + }, + "@types/jasminewd2": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.6.tgz", + "integrity": "sha512-2ZOKrxb8bKRmP/po5ObYnRDgFE4i+lQiEB27bAMmtMWLgJSqlIDqlLx6S0IRorpOmOPRQ6O80NujTmQAtBkeNw==", + "dev": true, + "requires": { + "@types/jasmine": "*" + } + }, + "@types/node": { + "version": "6.0.118", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.118.tgz", + "integrity": "sha512-N33cKXGSqhOYaPiT4xUGsYlPPDwFtQM/6QxJxuMXA/7BcySW+lkn2yigWP7vfs4daiL/7NJNU6DMCqg5N4B+xQ==", + "dev": true + }, + "@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "2.53.43", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz", + "integrity": "sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg==", + "dev": true + }, + "@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", + "dev": true + }, + "@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", + "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", + "dev": true, + "requires": { + "acorn": "^4.0.3" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "addressparser": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-1.0.1.tgz", + "integrity": "sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y=", + "dev": true, + "optional": true + }, + "adm-zip": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.13.tgz", + "integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ajv": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz", + "integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==", + "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" + }, + "dependencies": { + "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 + }, + "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 + } + } + }, + "ajv-keywords": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.3.0.tgz", + "integrity": "sha512-CMzN9S62ZOO4sA/mJZIO4S++ZM7KFWzH3PPWkveLhy4OZ9i1/VatgwWMD46w/XbGCBy7Ye0gCk+Za6mmyfKK7g==", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "amqplib": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.3.tgz", + "integrity": "sha512-ZOdUhMxcF+u62rPI+hMtU1NBXSDFQ3eCJJrenamtdQ7YYwh7RZJHOIM1gonVbZ5PyVdYH4xqBPje9OYqk7fnqw==", + "dev": true, + "optional": true, + "requires": { + "bitsyntax": "~0.1.0", + "bluebird": "^3.5.2", + "buffer-more-ints": "~1.0.0", + "readable-stream": "1.x >=1.1.9", + "safe-buffer": "~5.1.2", + "url-parse": "~1.4.3" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true, + "optional": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true, + "optional": true + } + } + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "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": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "app-root-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.1.0.tgz", + "integrity": "sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo=", + "dev": true + }, + "append-transform": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "dev": true, + "requires": { + "default-require-extensions": "^1.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "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": "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" + } + }, + "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-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true, + "optional": 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": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true, + "optional": 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 + }, + "ast-types": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.7.tgz", + "integrity": "sha512-2mP3TwtkY/aTv5X3ZsMpNAbOnyoC/aMJwJSoaELPkHId0nSQgFcnU4dRW3isxiz7+zBexk0ym3WNVjMiQBnJSw==", + "dev": true, + "optional": true + }, + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "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-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "dev": true, + "optional": 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 + }, + "autoprefixer": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", + "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==", + "dev": true, + "requires": { + "browserslist": "^2.11.3", + "caniuse-lite": "^1.0.30000805", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^6.0.17", + "postcss-value-parser": "^3.2.3" + } + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "axios": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.15.3.tgz", + "integrity": "sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=", + "dev": true, + "optional": true, + "requires": { + "follow-redirects": "1.0.0" + }, + "dependencies": { + "follow-redirects": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", + "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", + "dev": true, + "optional": true, + "requires": { + "debug": "^2.2.0" + } + } + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "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": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "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" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "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" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "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 + } + } + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "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 + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "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" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "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 + }, + "bitsyntax": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.1.0.tgz", + "integrity": "sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==", + "dev": true, + "optional": true, + "requires": { + "buffer-more-ints": "~1.0.0", + "debug": "~2.6.9", + "safe-buffer": "~5.1.2" + } + }, + "bl": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", + "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", + "dev": true, + "optional": true, + "requires": { + "readable-stream": "~2.0.5" + }, + "dependencies": { + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true, + "optional": true + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true, + "optional": true + } + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "optional": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "blocking-proxy": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-0.0.5.tgz", + "integrity": "sha1-RikF4Nz76pcPQao3Ij3anAexkSs=", + "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 + } + } + }, + "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 + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "dependencies": { + "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 + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.x.x" + } + }, + "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": "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" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://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": "https://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": "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" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://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-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "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-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-more-ints": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", + "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==", + "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 + }, + "buildmail": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/buildmail/-/buildmail-4.0.1.tgz", + "integrity": "sha1-h393OLeHKYccmhBeO4N9K+EaenI=", + "dev": true, + "optional": true, + "requires": { + "addressparser": "1.0.1", + "libbase64": "0.1.0", + "libmime": "3.0.0", + "libqp": "1.1.0", + "nodemailer-fetch": "1.6.0", + "nodemailer-shared": "1.1.0", + "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, + "optional": 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 + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "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" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "cache-loader": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-1.2.5.tgz", + "integrity": "sha512-enWKEQ4kO3YreDFd7AtVRjtJBmNiqh/X9hVDReu0C4qm8gsGmySkwuWtdc+N5O+vq5FzxL1mIZc30NyXCB7o/Q==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "mkdirp": "^0.5.1", + "neo-async": "^2.5.0", + "schema-utils": "^0.4.2" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + } + }, + "caniuse-lite": { + "version": "1.0.30000932", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000932.tgz", + "integrity": "sha512-4bghJFItvzz8m0T3lLZbacmEY9X1Z2AtIzTr7s7byqZIOumASfr4ynDx7rtm0J85nDmx8vsgR6vnaSoeU8Oh0A==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "chalk": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.2.tgz", + "integrity": "sha512-LvixLAQ4MYhbf7hgL4o5PeK32gJKvVzDRiSNIApDofQvyhl8adgG2lJVXn4+ekQoK7HL9RF8lqxwerpe0x2pCw==", + "dev": true, + "requires": { + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "dev": true + }, + "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-dependency-plugin": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-4.4.0.tgz", + "integrity": "sha512-yEFtUNUYT4jBykEX5ZOHw+5goA3glGZr9wAXIQqoyakjz5H5TeUmScnWRc52douAhb9eYzK3s7V6bXfNnjFdzg==", + "dev": true + }, + "circular-json": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", + "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==", + "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" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "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 + } + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-deep": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", + "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.0", + "shallow-clone": "^1.0.0" + }, + "dependencies": { + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "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 + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "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 + }, + "codelyzer": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.5.0.tgz", + "integrity": "sha512-oO6vCkjqsVrEsmh58oNlnJkRXuA30hF8cdNAQV9DytEalDwyOFRvHMnlKFzmOStNerOmPGZU9GAHnBo4tGvtiQ==", + "dev": true, + "requires": { + "app-root-path": "^2.1.0", + "css-selector-tokenizer": "^0.7.0", + "cssauron": "^1.4.0", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.1" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "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.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combine-lists": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", + "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", + "dev": true, + "requires": { + "lodash": "^4.5.0" + } + }, + "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.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "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 + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.15.tgz", + "integrity": "sha512-4aE67DL33dSW9gw4CI2H/yTxqHLNcxp0yS6jB+4h+wr3e43+1z7vm0HU9qXOH8j+qjKuL8+UtkOxYQSMq60Ylw==", + "dev": true, + "requires": { + "mime-db": ">= 1.36.0 < 2" + } + }, + "compression": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz", + "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.14", + "debug": "2.6.9", + "on-headers": "~1.0.1", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + } + }, + "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" + } + }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "dependencies": { + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + } + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "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" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "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 + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "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" + } + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "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 + }, + "copy-webpack-plugin": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.4.3.tgz", + "integrity": "sha512-v4THQ24Tks2NkyOvZuFDgZVfDD9YaA9rwYLZTrWg2GHIA8lrH5DboEyeoorh5Skki+PUbgSmnsCwhMWqYrQZrA==", + "dev": true, + "requires": { + "cacache": "^10.0.1", + "find-cache-dir": "^1.0.0", + "globby": "^7.1.1", + "is-glob": "^4.0.0", + "loader-utils": "^1.1.0", + "minimatch": "^3.0.4", + "p-limit": "^1.0.0", + "serialize-javascript": "^1.4.0" + }, + "dependencies": { + "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-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" + } + } + } + }, + "core-js": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.3.tgz", + "integrity": "sha512-l00tmFFZOBHtYhN4Cz7k32VM7vTn3rE2ANjQDxdEN6zmXZ/xq1jQuutnmHvMG1ZJ7xd72+TA5YpUK8wz3rWsfQ==" + }, + "core-object": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz", + "integrity": "sha512-sA2/4+/PZ/KV6CKgjrVrrUVBKCkdDO02CUlQ0YKTQoYUwPYNOtOAcWlbYhd5v/1JqYaA6oZ4sDlOU4ppVw6Wbg==", + "dev": true, + "requires": { + "chalk": "^2.0.0" + } + }, + "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 + }, + "cosmiconfig": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz", + "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0", + "require-from-string": "^2.0.1" + }, + "dependencies": { + "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" + } + } + } + }, + "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": "https://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": "https://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-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "optional": true, + "requires": { + "boom": "2.x.x" + } + }, + "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" + } + }, + "css-parse": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", + "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=", + "dev": true + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-selector-tokenizer": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", + "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", + "dev": true, + "requires": { + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" + } + }, + "css-what": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.2.tgz", + "integrity": "sha512-wan8dMWQ0GUeF7DGEPVjhHemVW/vy6xUYmFzRY8RYqgA0JtXC9rJmbScBjqSu6dg9q0lwPQy6ZAmJVr3PPTvqQ==", + "dev": true + }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "requires": { + "through": "X.X.X" + } + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "cyclist": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "^0.10.9" + } + }, + "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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "data-uri-to-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.0.tgz", + "integrity": "sha512-YbKCNLPPP4inc0E5If4OaalBc7gpaM2MRv77Pv2VThVComLKfbGYtJcdDCViDyp1Wd4SebhHLz94vp91zbK6bw==", + "dev": true, + "optional": true, + "requires": { + "@types/node": "^8.0.7" + }, + "dependencies": { + "@types/node": { + "version": "8.10.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.39.tgz", + "integrity": "sha512-rE7fktr02J8ybFf6eysife+WF+L4sAHWzw09DgdCebEu+qDwMvv4zl6Bc+825ttGZP73kCKxa3dhJOoGJ8+5mA==", + "dev": true, + "optional": true + } + } + }, + "date-format": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", + "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=", + "dev": true + }, + "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": "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" + } + }, + "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-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "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, + "optional": true + }, + "default-require-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "dev": true, + "requires": { + "strip-bom": "^2.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" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "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 + } + } + }, + "degenerator": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", + "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "dev": true, + "optional": true, + "requires": { + "ast-types": "0.x.x", + "escodegen": "1.x.x", + "esprima": "3.x.x" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true, + "optional": true + } + } + }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "requires": { + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + } + } + }, + "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 + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "denodeify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", + "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "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" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://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" + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "~1.1.1", + "entities": "~1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + } + } + }, + "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 + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", + "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "double-ended-queue": { + "version": "2.1.0-0", + "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", + "dev": true, + "optional": true + }, + "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" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ejs": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", + "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.109", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.109.tgz", + "integrity": "sha512-1qhgVZD9KIULMyeBkbjU/dWmm30zpPUfdWZfVO3nPhbtqMHJqHr4Ua5wBcWtAymVFrUCuAJxjMF1OhG+bR21Ow==", + "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" + } + }, + "ember-cli-string-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz", + "integrity": "sha1-ObZ3/CgF9VFzc1N2/O8njqpEUqE=", + "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 + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "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" + } + }, + "engine.io": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.5.tgz", + "integrity": "sha512-D06ivJkYxyRrcEe0bTpNnBQNgP9d3xog+qZlLbui8EsMr/DouQpf5o9FzJnWYHEYE0YsFHllUv2R1dkgYZXHcA==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "uws": "~9.14.0", + "ws": "~3.3.1" + }, + "dependencies": { + "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" + } + } + } + }, + "engine.io-client": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.6.tgz", + "integrity": "sha512-hnuHsFluXnsKOndS4Hv6SvUrgdYx1pk2NqfaDMW+GWdgfU3+/V25Cj7I8a0x92idSpa5PIhJRKxPvp9mnoLsfg==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "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" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "enhanced-resolve": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", + "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "object-assign": "^4.0.1", + "tapable": "^0.2.7" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "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.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "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" + } + }, + "es5-ext": { + "version": "0.10.47", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.47.tgz", + "integrity": "sha512-/1TItLfj+TTfWoeRcDn/0FbGV6SNo4R+On2GGVucPU/j3BWnXE2Co8h8CTo4Tu34gFJtnmwS9xiScKs4EjZhdw==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "1" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-promise": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", + "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "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, + "optional": 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, + "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, + "optional": true + } + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "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 + }, + "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 + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "dev": true + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "eventsource": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", + "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", + "dev": true, + "requires": { + "original": ">=0.0.5" + } + }, + "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.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" + }, + "dependencies": { + "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" + } + } + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-braces": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", + "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", + "dev": true, + "requires": { + "array-slice": "^0.2.3", + "array-unique": "^0.2.1", + "braces": "^0.1.2" + }, + "dependencies": { + "braces": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", + "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", + "dev": true, + "requires": { + "expand-range": "^0.1.0" + } + }, + "expand-range": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", + "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", + "dev": true, + "requires": { + "is-number": "^0.1.1", + "repeat-string": "^0.2.2" + } + }, + "is-number": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", + "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", + "dev": true + }, + "repeat-string": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", + "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", + "dev": true + } + } + }, + "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" + } + }, + "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" + } + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "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 + } + } + }, + "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" + } + } + } + }, + "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" + } + }, + "extract-text-webpack-plugin": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz", + "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==", + "dev": true, + "requires": { + "async": "^2.4.1", + "loader-utils": "^1.1.0", + "schema-utils": "^0.3.0", + "webpack-sources": "^1.0.1" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "^5.0.0" + } + } + } + }, + "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": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "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, + "optional": true + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "file-loader": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", + "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^0.4.5" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "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 + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "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" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.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" + } + }, + "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.6.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", + "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", + "dev": true, + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "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" + } + } + } + }, + "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" + } + }, + "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.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "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" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "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-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "^1.0.0" + } + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "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.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", + "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": 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 + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": 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 + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "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 + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": 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, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": 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, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.3", + "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.5", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.2.0", + "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 + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": 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 + }, + "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.6.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, + "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, + "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 + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true + } + } + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "optional": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true, + "optional": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "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 + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": 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" + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "optional": true, + "requires": { + "globule": "^1.0.0" + } + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dev": true, + "optional": true, + "requires": { + "is-property": "^1.0.2" + } + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "optional": true, + "requires": { + "is-property": "^1.0.0" + } + }, + "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-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "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-uri": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.3.tgz", + "integrity": "sha512-x5j6Ks7FOgLD/GlvjKwgu7wdmMR55iuRHhn8hj/+gA+eSbxQvZ+AEomq+3MgVEZj1vpi738QahGbCCSIDtXtkw==", + "dev": true, + "optional": true, + "requires": { + "data-uri-to-buffer": "2", + "debug": "4", + "extend": "~3.0.2", + "file-uri-to-path": "1", + "ftp": "~0.3.10", + "readable-stream": "3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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, + "optional": true + }, + "readable-stream": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", + "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", + "dev": true, + "optional": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "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" + } + }, + "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" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "globule": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", + "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "dev": true, + "optional": true, + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, + "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 + }, + "handle-thing": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", + "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=", + "dev": true + }, + "handlebars": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", + "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==", + "dev": true, + "requires": { + "async": "^2.5.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "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 + } + } + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "optional": true, + "requires": { + "ajv": "^4.9.1", + "har-schema": "^1.0.5" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "optional": true, + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + } + } + }, + "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-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "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-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "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" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "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": { + "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" + } + } + } + }, + "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.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "optional": true, + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hipchat-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hipchat-notifier/-/hipchat-notifier-1.1.0.tgz", + "integrity": "sha1-ttJJdVQ3wZEII2d5nTupoPI7Ix4=", + "dev": true, + "optional": true, + "requires": { + "lodash": "^4.0.0", + "request": "^2.0.0" + } + }, + "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" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "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 + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + } + }, + "html-webpack-plugin": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz", + "integrity": "sha1-f5xCG36pHsRg9WUn1430hO51N9U=", + "dev": true, + "requires": { + "bluebird": "^3.4.7", + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "toposort": "^1.0.0" + }, + "dependencies": { + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "htmlparser2": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", + "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", + "dev": true, + "requires": { + "domelementtype": "1", + "domhandler": "2.1", + "domutils": "1.1", + "readable-stream": "1.0" + }, + "dependencies": { + "domutils": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", + "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "http-parser-js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.0.tgz", + "integrity": "sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==", + "dev": true + }, + "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-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "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" + } + } + } + }, + "http-proxy-middleware": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz", + "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=", + "dev": true, + "requires": { + "http-proxy": "^1.16.2", + "is-glob": "^3.1.0", + "lodash": "^4.17.2", + "micromatch": "^2.3.11" + }, + "dependencies": { + "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-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" + } + } + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "httpntlm": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", + "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", + "dev": true, + "requires": { + "httpreq": ">=0.4.22", + "underscore": "~1.7.0" + } + }, + "httpreq": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", + "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=", + "dev": true + }, + "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 + }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "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" + } + }, + "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 + } + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "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": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "import-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", + "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", + "dev": true, + "requires": { + "pkg-dir": "^2.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "dev": true, + "optional": true + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", + "dev": true, + "optional": 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 + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "internal-ip": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", + "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=", + "dev": true, + "requires": { + "meow": "^3.3.0" + } + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", + "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" + } + }, + "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": "https://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" + } + }, + "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-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "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" + } + }, + "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" + } + }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "dev": true, + "optional": true + }, + "is-my-json-valid": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz", + "integrity": "sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q==", + "dev": true, + "optional": true, + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" + } + }, + "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" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "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" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "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-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "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-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-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "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 + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "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": "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" + } + }, + "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-api": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.7.tgz", + "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==", + "dev": true, + "requires": { + "async": "^2.1.4", + "fileset": "^2.0.2", + "istanbul-lib-coverage": "^1.2.1", + "istanbul-lib-hook": "^1.2.2", + "istanbul-lib-instrument": "^1.10.2", + "istanbul-lib-report": "^1.1.5", + "istanbul-lib-source-maps": "^1.2.6", + "istanbul-reports": "^1.5.1", + "js-yaml": "^3.7.0", + "mkdirp": "^0.5.1", + "once": "^1.4.0" + } + }, + "istanbul-instrumenter-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz", + "integrity": "sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w==", + "dev": true, + "requires": { + "convert-source-map": "^1.5.0", + "istanbul-lib-instrument": "^1.7.3", + "loader-utils": "^1.1.0", + "schema-utils": "^0.3.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "^5.0.0" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", + "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz", + "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==", + "dev": true, + "requires": { + "append-transform": "^0.4.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", + "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", + "dev": true, + "requires": { + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.1", + "semver": "^5.3.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz", + "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^1.2.1", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" + }, + "dependencies": { + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz", + "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.2.1", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" + }, + "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" + } + }, + "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 + } + } + }, + "istanbul-reports": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.1.tgz", + "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==", + "dev": true, + "requires": { + "handlebars": "^4.0.3" + } + }, + "jasmine": { + "version": "2.99.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.99.0.tgz", + "integrity": "sha1-jKctEC5jm4Z8ZImFbg4YqceqQrc=", + "dev": true, + "requires": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.99.0" + }, + "dependencies": { + "jasmine-core": { + "version": "2.99.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", + "integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=", + "dev": true + } + } + }, + "jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true + }, + "jasmine-spec-reporter": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", + "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", + "dev": true, + "requires": { + "colors": "1.1.2" + } + }, + "jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true + }, + "js-base64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", + "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==", + "dev": true, + "optional": true + }, + "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 + }, + "js-yaml": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", + "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "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 + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "json-loader": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", + "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "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.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "optional": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "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 + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true, + "optional": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true, + "optional": 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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "karma": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/karma/-/karma-2.0.5.tgz", + "integrity": "sha512-rECezBeY7mjzGUWhFlB7CvPHgkHJLXyUmWg+6vHCEsdWNUTnmiS6jRrIMcJEWgU2DUGZzGWG0bTRVky8fsDTOA==", + "dev": true, + "requires": { + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "chokidar": "^2.0.3", + "colors": "^1.1.0", + "combine-lists": "^1.0.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "expand-braces": "^0.1.1", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.4", + "log4js": "^2.5.3", + "mime": "^1.3.4", + "minimatch": "^3.0.2", + "optimist": "^0.6.1", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", + "socket.io": "2.0.4", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "useragent": "2.2.1" + }, + "dependencies": { + "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" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "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" + } + }, + "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": { + "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" + } + }, + "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-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-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" + } + }, + "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 + } + } + }, + "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" + } + } + } + }, + "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" + } + } + } + }, + "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" + } + } + } + }, + "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" + } + }, + "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-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" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "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 + }, + "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" + } + }, + "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 + } + } + }, + "karma-chrome-launcher": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", + "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "dev": true, + "requires": { + "fs-access": "^1.0.0", + "which": "^1.2.1" + } + }, + "karma-coverage-istanbul-reporter": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.3.tgz", + "integrity": "sha1-O13/RmT6W41RlrmInj9hwforgNk=", + "dev": true, + "requires": { + "istanbul-api": "^1.3.1", + "minimatch": "^3.0.4" + } + }, + "karma-jasmine": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.2.tgz", + "integrity": "sha1-OU8rJf+0pkS5rabyLUQ+L9CIhsM=", + "dev": true + }, + "karma-jasmine-html-reporter": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz", + "integrity": "sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw=", + "dev": true, + "requires": { + "karma-jasmine": "^1.0.2" + } + }, + "karma-source-map-support": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.3.0.tgz", + "integrity": "sha512-HcPqdAusNez/ywa+biN4EphGz62MmQyPggUsDfsHqa7tSe4jdsxgvTKuDfIazjL+IOxpVWyT7Pr4dhAV+sxX5Q==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + }, + "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 + }, + "source-map-support": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", + "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "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" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "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" + } + }, + "less": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", + "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==", + "dev": true, + "requires": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.2.11", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", + "request": "2.81.0", + "source-map": "^0.5.3" + } + }, + "less-loader": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-4.1.0.tgz", + "integrity": "sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "loader-utils": "^1.1.0", + "pify": "^3.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "optional": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "libbase64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", + "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=", + "dev": true + }, + "libmime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz", + "integrity": "sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY=", + "dev": true, + "requires": { + "iconv-lite": "0.4.15", + "libbase64": "0.1.0", + "libqp": "1.1.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", + "dev": true + } + } + }, + "libqp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", + "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", + "dev": true + }, + "license-webpack-plugin": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-1.5.0.tgz", + "integrity": "sha512-Of/H79rZqm2aeg4RnP9SMSh19qkKemoLT5VaJV58uH5AxeYWEcBgGFs753JEJ/Hm6BPvQVfIlrrjoBwYj8p7Tw==", + "dev": true, + "requires": { + "ejs": "^2.5.7" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "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" + } + }, + "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.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true, + "optional": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "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.mergewith": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", + "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==", + "dev": true, + "optional": true + }, + "lodash.tail": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", + "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", + "dev": true + }, + "log4js": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.11.0.tgz", + "integrity": "sha512-z1XdwyGFg8/WGkOyF6DPJjivCWNLKrklGdViywdYnSKOvgtEBo2UyEMZS5sD2mZrQlU3TvO8wDWLc8mzE1ncBQ==", + "dev": true, + "requires": { + "amqplib": "^0.5.2", + "axios": "^0.15.3", + "circular-json": "^0.5.4", + "date-format": "^1.2.0", + "debug": "^3.1.0", + "hipchat-notifier": "^1.1.0", + "loggly": "^1.1.0", + "mailgun-js": "^0.18.0", + "nodemailer": "^2.5.0", + "redis": "^2.7.1", + "semver": "^5.5.0", + "slack-node": "~0.2.0", + "streamroller": "0.7.0" + }, + "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" + } + }, + "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 + } + } + }, + "loggly": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/loggly/-/loggly-1.1.1.tgz", + "integrity": "sha1-Cg/B0/o6XsRP3HuJe+uipGlc6+4=", + "dev": true, + "optional": true, + "requires": { + "json-stringify-safe": "5.0.x", + "request": "2.75.x", + "timespan": "2.3.x" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "optional": true + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "form-data": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", + "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", + "dev": true, + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.11" + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "optional": true, + "requires": { + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^2.0.0" + } + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", + "dev": true, + "optional": true + }, + "qs": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", + "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", + "dev": true, + "optional": true + }, + "request": { + "version": "2.75.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz", + "integrity": "sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM=", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "bl": "~1.1.2", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.0.0", + "har-validator": "~2.0.6", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "node-uuid": "~1.4.7", + "oauth-sign": "~0.8.1", + "qs": "~6.2.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "~0.4.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true, + "optional": true + } + } + }, + "loglevel": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", + "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "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" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "magic-string": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", + "dev": true, + "requires": { + "vlq": "^0.2.2" + } + }, + "mailcomposer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-4.0.1.tgz", + "integrity": "sha1-DhxEsqB890DuF9wUm6AJ8Zyt/rQ=", + "dev": true, + "optional": true, + "requires": { + "buildmail": "4.0.1", + "libmime": "3.0.0" + } + }, + "mailgun-js": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.18.1.tgz", + "integrity": "sha512-lvuMP14u24HS2uBsJEnzSyPMxzU2b99tQsIx1o6QNjqxjk8b3WvR+vq5oG1mjqz/IBYo+5gF+uSoDS0RkMVHmg==", + "dev": true, + "optional": true, + "requires": { + "async": "~2.6.0", + "debug": "~3.1.0", + "form-data": "~2.3.0", + "inflection": "~1.12.0", + "is-stream": "^1.1.0", + "path-proxy": "~1.0.0", + "promisify-call": "^2.0.2", + "proxy-agent": "~3.0.0", + "tsscmp": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "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, + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + } + } + }, + "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" + } + }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "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-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "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.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "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" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "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" + } + }, + "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" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "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" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "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" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==", + "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" + }, + "dependencies": { + "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 + }, + "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 + }, + "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 + } + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "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 + }, + "netmask": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", + "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", + "dev": true, + "optional": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-forge": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", + "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", + "dev": true + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "dev": true, + "optional": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": 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, + "optional": 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, + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "optional": 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, + "optional": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "optional": true, + "requires": { + "abbrev": "1" + } + }, + "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, + "optional": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true, + "optional": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true, + "optional": 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, + "optional": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "optional": 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" + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true, + "optional": true + }, + "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, + "optional": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "node-libs-browser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", + "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", + "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": "^3.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.11.0", + "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-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.2.tgz", + "integrity": "sha512-6Gbjq+d7uhkO7epaKi5DNgUJn7H0gEyA4Jg0Mo1uQOi3Rk50G83LtmhhFyw0LxnAFhtlspkiiw52ISP13qzcBg==", + "dev": true + }, + "node-sass": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz", + "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==", + "dev": true, + "optional": true, + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash.assign": "^4.2.0", + "lodash.clonedeep": "^4.3.2", + "lodash.mergewith": "^4.6.0", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.10.0", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "^2.2.4", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": 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, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "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, + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "optional": 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, + "optional": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.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, + "optional": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true, + "optional": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true, + "optional": 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, + "optional": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "optional": 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" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true + }, + "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, + "optional": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "nodemailer": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-2.7.2.tgz", + "integrity": "sha1-8kLmSa7q45tsftdA73sGHEBNMPk=", + "dev": true, + "optional": true, + "requires": { + "libmime": "3.0.0", + "mailcomposer": "4.0.1", + "nodemailer-direct-transport": "3.3.2", + "nodemailer-shared": "1.1.0", + "nodemailer-smtp-pool": "2.8.2", + "nodemailer-smtp-transport": "2.7.2", + "socks": "1.1.9" + }, + "dependencies": { + "smart-buffer": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", + "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=", + "dev": true, + "optional": true + }, + "socks": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.9.tgz", + "integrity": "sha1-Yo1+TQSRJDVEWsC25Fk3bLPm1pE=", + "dev": true, + "optional": true, + "requires": { + "ip": "^1.1.2", + "smart-buffer": "^1.0.4" + } + } + } + }, + "nodemailer-direct-transport": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz", + "integrity": "sha1-6W+vuQNYVglH5WkBfZfmBzilCoY=", + "dev": true, + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-fetch": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", + "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=", + "dev": true + }, + "nodemailer-shared": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", + "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", + "dev": true, + "requires": { + "nodemailer-fetch": "1.6.0" + } + }, + "nodemailer-smtp-pool": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz", + "integrity": "sha1-LrlNbPhXgLG0clzoU7nL1ejajHI=", + "dev": true, + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "nodemailer-wellknown": "0.1.10", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-smtp-transport": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz", + "integrity": "sha1-A9ccdjFPFKx9vHvwM6am0W1n+3c=", + "dev": true, + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "nodemailer-wellknown": "0.1.10", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-wellknown": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", + "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=", + "dev": true + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.2.tgz", + "integrity": "sha512-YcMnjqeoUckXTPKZSAsPjUPLxH85XotbpqK3w4RyCwdFQSU5FxxBys8buehkSfg0j9fKvV1hn7O0+8reEgkAiw==", + "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" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "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" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "null-check": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", + "dev": true + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "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 + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true, + "optional": 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-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "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" + } + } + } + }, + "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" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "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" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", + "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "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" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "optional": 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" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true, + "optional": true + } + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", + "dev": true + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "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": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "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-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-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "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 + }, + "pac-proxy-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-3.0.0.tgz", + "integrity": "sha512-AOUX9jES/EkQX2zRz0AW7lSx9jD//hQS8wFXBvcnd/J2Py9KaMJMqV/LPqJssj1tgGufotb2mmopGPR15ODv1Q==", + "dev": true, + "optional": true, + "requires": { + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "get-uri": "^2.0.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "pac-resolver": "^3.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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, + "optional": true + } + } + }, + "pac-resolver": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", + "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", + "dev": true, + "optional": true, + "requires": { + "co": "^4.6.0", + "degenerator": "^1.0.4", + "ip": "^1.1.5", + "netmask": "^1.0.6", + "thunkify": "^2.1.2" + } + }, + "pako": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz", + "integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA==", + "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" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parse-asn1": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.3.tgz", + "integrity": "sha512-VrPoetlz7B/FqjBLD2f5wBVZvsZVLnRUrxVLfRYhGXCODa/NWE4p3Wp+6+aV3ZPL3KM7/OZmxDIwwijD7yuucg==", + "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", + "safe-buffer": "^5.1.1" + } + }, + "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" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "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": "https://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-proxy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz", + "integrity": "sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4=", + "dev": true, + "optional": true, + "requires": { + "inflection": "~1.3.0" + }, + "dependencies": { + "inflection": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.3.8.tgz", + "integrity": "sha1-y9Fg2p91sUw8xjV41POWeEvzAU4=", + "dev": true, + "optional": true + } + } + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "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" + } + }, + "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": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true, + "optional": 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" + } + }, + "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" + } + }, + "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": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "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 + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "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 + }, + "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" + } + } + } + }, + "postcss-import": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-11.1.0.tgz", + "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==", + "dev": true, + "requires": { + "postcss": "^6.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-load-config": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz", + "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==", + "dev": true, + "requires": { + "cosmiconfig": "^4.0.0", + "import-cwd": "^2.0.0" + } + }, + "postcss-loader": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.6.tgz", + "integrity": "sha512-hgiWSc13xVQAq25cVw80CH0l49ZKlAnU1hKPOdRrNj89bokRr/bZF2nT+hebPPF9c9xs8c3gw3Fr2nxtmXYnNg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^6.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^0.4.0" + } + }, + "postcss-url": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-7.3.2.tgz", + "integrity": "sha512-QMV5mA+pCYZQcUEPQkmor9vcPQ2MT+Ipuu8qdi1gVxbNiIiErEGft+eny1ak19qALoBkccS5AHaCaCDzh7b9MA==", + "dev": true, + "requires": { + "mime": "^1.4.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.0", + "postcss": "^6.0.1", + "xxhashjs": "^0.2.1" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "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 + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "dev": true, + "requires": { + "renderkid": "^2.0.1", + "utila": "~0.4" + } + }, + "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 + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "optional": true, + "requires": { + "asap": "~2.0.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promisify-call": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/promisify-call/-/promisify-call-2.0.4.tgz", + "integrity": "sha1-1IwtRWUszM1SgB3ey9UzptS9X7o=", + "dev": true, + "optional": true, + "requires": { + "with-callback": "^1.0.2" + } + }, + "protractor": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.1.2.tgz", + "integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=", + "dev": true, + "requires": { + "@types/node": "^6.0.46", + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "~2.53.39", + "blocking-proxy": "0.0.5", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "^2.5.3", + "jasminewd2": "^2.1.0", + "optimist": "~0.6.0", + "q": "1.4.1", + "saucelabs": "~1.3.0", + "selenium-webdriver": "3.0.1", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "^1.0.0", + "webdriver-manager": "^12.0.6" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "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 + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + } + }, + "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" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "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" + } + }, + "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" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "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 + }, + "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": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "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 + }, + "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" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "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" + } + }, + "webdriver-manager": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.1.tgz", + "integrity": "sha512-L9TEQmZs6JbMMRQI1w60mfps265/NCr0toYJl7p/R2OAk6oXAfwI6jqYP7EWae+d7Ad2S2Aj4+rzxoSjqk3ZuA==", + "dev": true, + "requires": { + "adm-zip": "^0.4.9", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + } + } + } + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "proxy-agent": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.0.3.tgz", + "integrity": "sha512-PXVVVuH9tiQuxQltFJVSnXWuDtNr+8aNBP6XVDDCDiUuDN8eRCm+ii4/mFWmXWEA0w8jjJSlePa4LXlM4jIzNA==", + "dev": true, + "optional": true, + "requires": { + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "pac-proxy-agent": "^3.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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, + "optional": true + } + } + }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "dev": true, + "optional": 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.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "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 + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "dev": true, + "optional": 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 + }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==", + "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 + }, + "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 + } + } + }, + "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" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "raw-loader": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", + "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=", + "dev": true + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "dependencies": { + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://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" + }, + "dependencies": { + "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 + }, + "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 + }, + "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" + } + } + } + }, + "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": { + "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" + } + }, + "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-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-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" + } + }, + "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 + } + } + }, + "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" + } + } + } + }, + "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" + } + } + } + }, + "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" + } + }, + "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" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "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 + }, + "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" + } + } + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "redis": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", + "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "dev": true, + "optional": true, + "requires": { + "double-ended-queue": "^2.1.0-0", + "redis-commands": "^1.2.0", + "redis-parser": "^2.6.0" + } + }, + "redis-commands": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.4.0.tgz", + "integrity": "sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==", + "dev": true, + "optional": true + }, + "redis-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=", + "dev": true, + "optional": true + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "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" + } + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "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 + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "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 + }, + "renderkid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.2.tgz", + "integrity": "sha512-FsygIxevi1jSiPY9h7vZmBFUbAOcbYm9UwyiLNdVsLRs/5We9Ob5NMPbGYUTWiLq5L+ezlVdE0A8bbME5CWTpg==", + "dev": true, + "requires": { + "css-select": "^1.1.0", + "dom-converter": "~0.2", + "htmlparser2": "~3.3.0", + "strip-ansi": "^3.0.0", + "utila": "^0.4.0" + } + }, + "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 + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" + } + }, + "requestretry": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", + "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", + "dev": true, + "optional": true, + "requires": { + "extend": "^3.0.0", + "lodash": "^4.15.0", + "request": "^2.74.0", + "when": "^3.7.7" + }, + "dependencies": { + "when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", + "dev": true, + "optional": true + } + } + }, + "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-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "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 + }, + "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.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "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" + } + }, + "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-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 + }, + "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 + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "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" + } + }, + "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-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": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "requires": { + "symbol-observable": "1.0.1" + } + }, + "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": "https://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 + }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "dev": true, + "optional": true, + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^7.0.0" + } + }, + "sass-loader": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-6.0.7.tgz", + "integrity": "sha512-JoiyD00Yo1o61OJsoP2s2kb19L1/Y2p3QFcCdWdF6oomBGKVYuZyqHWemRBfQ2uGYsk+CH3eCguXNfpjzlcpaA==", + "dev": true, + "requires": { + "clone-deep": "^2.0.1", + "loader-utils": "^1.0.1", + "lodash.tail": "^4.1.1", + "neo-async": "^2.5.0", + "pify": "^3.0.0" + } + }, + "saucelabs": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz", + "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=", + "dev": true, + "requires": { + "https-proxy-agent": "^1.0.0" + }, + "dependencies": { + "agent-base": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", + "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "dev": true, + "requires": { + "extend": "~3.0.0", + "semver": "~5.0.1" + } + }, + "https-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "dev": true, + "requires": { + "agent-base": "2", + "debug": "2", + "extend": "3" + } + }, + "semver": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "dev": true + } + } + }, + "sax": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", + "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" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "optional": true, + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selenium-webdriver": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz", + "integrity": "sha1-ot6l2kqX9mcuiefKcnbO+jZRR6c=", + "dev": true, + "requires": { + "adm-zip": "^0.4.7", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "dependencies": { + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, + "selfsigned": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.4.tgz", + "integrity": "sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==", + "dev": true, + "requires": { + "node-forge": "0.7.5" + } + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "semver-intersect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz", + "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==", + "dev": true, + "requires": { + "semver": "^5.0.0" + } + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.6.1.tgz", + "integrity": "sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw==", + "dev": true + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "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 + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://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" + } + }, + "shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "dev": true, + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "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 + } + } + }, + "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 + }, + "silent-error": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/silent-error/-/silent-error-1.1.1.tgz", + "integrity": "sha512-n4iEKyNcg4v6/jpb3c0/iyH2G1nzUNl7Gpqtn/mHIJK9S/q/7MCfoO4rwVOoO59qPFIc0hVHvMbiOJ0NdtxKKw==", + "dev": true, + "requires": { + "debug": "^2.2.0" + } + }, + "slack-node": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/slack-node/-/slack-node-0.2.0.tgz", + "integrity": "sha1-3kuN3aqLeT9h29KTgQT9q/N9+jA=", + "dev": true, + "optional": true, + "requires": { + "requestretry": "^1.2.2" + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "smart-buffer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz", + "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==", + "dev": true + }, + "smtp-connection": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", + "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", + "dev": true, + "requires": { + "httpntlm": "1.6.1", + "nodemailer-shared": "1.1.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": { + "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" + } + } + } + }, + "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" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "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 + } + } + }, + "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" + } + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "optional": true, + "requires": { + "hoek": "2.x.x" + } + }, + "socket.io": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz", + "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=", + "dev": true, + "requires": { + "debug": "~2.6.6", + "engine.io": "~3.1.0", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.0.4", + "socket.io-parser": "~3.1.1" + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz", + "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~2.6.4", + "engine.io-client": "~3.1.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.1.1", + "to-array": "0.1.4" + } + }, + "socket.io-parser": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.3.tgz", + "integrity": "sha512-g0a2HPqLguqAczs3dMECuA1RgoGFPyvDqcbaDEdCWY9g59kdUAz3YRmaJBNKXflrHNwB7Q12Gkf/0CZXfdHR7g==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "has-binary2": "~1.0.2", + "isarray": "2.0.1" + }, + "dependencies": { + "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" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "sockjs-client": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.5.tgz", + "integrity": "sha1-G7fA9yIsQPQq3xT0RCy9Eml3GoM=", + "dev": true, + "requires": { + "debug": "^2.6.6", + "eventsource": "0.1.6", + "faye-websocket": "~0.11.0", + "inherits": "^2.0.1", + "json3": "^3.3.2", + "url-parse": "^1.1.8" + }, + "dependencies": { + "faye-websocket": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + } + } + }, + "socks": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.2.3.tgz", + "integrity": "sha512-+2r83WaRT3PXYoO/1z+RDEBE7Z2f9YcdQnJ0K/ncXXbV5gJ6wYfNAebYFYiiUjM6E4JyXnPY8cimwyvFYHVUUA==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "4.0.2" + } + }, + "socks-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz", + "integrity": "sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw==", + "dev": true, + "requires": { + "agent-base": "~4.2.0", + "socks": "~2.2.0" + } + }, + "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 + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "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.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "dev": true + }, + "spdy": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", + "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", + "dev": true, + "requires": { + "debug": "^2.6.8", + "handle-thing": "^1.2.5", + "http-deceiver": "^1.2.7", + "safe-buffer": "^5.0.1", + "select-hose": "^2.0.0", + "spdy-transport": "^2.0.18" + } + }, + "spdy-transport": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.1.1.tgz", + "integrity": "sha512-q7D8c148escoB3Z7ySCASadkegMmUZW8Wb/Q1u0/XBgDKMO880rLQDj8Twiew/tYi7ghemKUi/whSYOwE17f5Q==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "detect-node": "^2.0.3", + "hpack.js": "^2.1.6", + "obuf": "^1.1.1", + "readable-stream": "^2.2.9", + "safe-buffer": "^5.0.1", + "wbuf": "^1.7.2" + } + }, + "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.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "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" + } + } + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "dev": true, + "optional": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "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 + }, + "streamroller": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", + "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", + "dev": true, + "requires": { + "date-format": "^1.2.0", + "debug": "^3.1.0", + "mkdirp": "^0.5.1", + "readable-stream": "^2.3.0" + }, + "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" + } + }, + "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 + } + } + }, + "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" + } + }, + "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" + } + }, + "stringstream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "dev": true, + "optional": true + }, + "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" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "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 + }, + "style-loader": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.19.1.tgz", + "integrity": "sha512-IRE+ijgojrygQi3rsqT0U4dd+UcPCqcVvauZpCnQrGAlEe+FUIyrK93bUDScamesjP08JlQNsFJU+KmPedP5Og==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^0.3.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "^5.0.0" + } + } + } + }, + "stylus": { + "version": "0.54.5", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz", + "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", + "dev": true, + "requires": { + "css-parse": "1.7.x", + "debug": "*", + "glob": "7.0.x", + "mkdirp": "0.5.x", + "sax": "0.5.x", + "source-map": "0.1.x" + }, + "dependencies": { + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "stylus-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", + "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "when": "~3.6.x" + } + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" + }, + "tapable": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz", + "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true, + "optional": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://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" + } + }, + "thunkify": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", + "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", + "dev": true, + "optional": true + }, + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==", + "dev": true + }, + "time-stamp": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.2.0.tgz", + "integrity": "sha512-zxke8goJQpBeEgD82CXABeMh0LSJcj7CXEd0OHOg45HgcofF7pxNwZm9+RknpxpDhwN4gFpySkApKfFYfRQnUA==", + "dev": true + }, + "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" + } + }, + "timespan": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", + "integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=", + "dev": true, + "optional": true + }, + "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-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "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": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "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" + } + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "optional": true, + "requires": { + "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, + "optional": true + } + } + }, + "tree-kill": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", + "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", + "dev": true + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "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 + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.2" + } + }, + "ts-node": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-4.1.0.tgz", + "integrity": "sha512-xcZH12oVg9PShKhy3UHyDmuDLV3y7iKwX25aMVPt1SIXSuAfWkFiGPEkg+th8R4YKW/QCxDoW7lJdb15lx6QWg==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "chalk": "^2.3.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.0", + "tsconfig": "^7.0.0", + "v8flags": "^3.0.0", + "yn": "^2.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "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.10", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", + "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "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" + } + } + } + }, + "tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "requires": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "tsickle": { + "version": "0.27.5", + "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.27.5.tgz", + "integrity": "sha512-NP+CjM1EXza/M8mOXBLH3vkFEJiu1zfEAlC5WdJxHPn8l96QPz5eooP6uAgYtw1CcKfuSyIiheNUdKxtDWCNeg==", + "dev": true, + "requires": { + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map": "^0.6.0", + "source-map-support": "^0.5.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "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.10", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", + "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, + "tslint": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz", + "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.12.1" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "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" + } + } + } + }, + "tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "dev": true, + "optional": true + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "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-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", + "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", + "dev": true + }, + "uglify-js": { + "version": "3.4.9", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", + "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "dev": true, + "requires": { + "commander": "~2.17.1", + "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 + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": 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": { + "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 + }, + "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" + } + } + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", + "dev": true + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "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" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "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" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "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 + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "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 + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "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-loader": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.6.2.tgz", + "integrity": "sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "mime": "^1.4.1", + "schema-utils": "^0.3.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "^5.0.0" + } + } + } + }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "dev": true, + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "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 + }, + "useragent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz", + "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=", + "dev": true, + "requires": { + "lru-cache": "2.2.x", + "tmp": "0.0.x" + }, + "dependencies": { + "lru-cache": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", + "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=", + "dev": true + } + } + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "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 + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "uws": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/uws/-/uws-9.14.0.tgz", + "integrity": "sha512-HNMztPP5A1sKuVFmdZ6BPVpBQd5bUjNC8EFMFiICK+oho/OQsAJy5hnIx4btMHiOk8j04f/DbIlqnEZ9d72dqg==", + "dev": true, + "optional": true + }, + "v8flags": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.2.tgz", + "integrity": "sha512-MtivA7GF24yMPte9Rp/BWGCYQNaUj86zeYxV/x2RRJMKagImbbv3u8iJC57lNhWLPcGLJmHcHmFWkNsplbbLWw==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "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" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", + "dev": true + }, + "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" + } + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "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" + }, + "dependencies": { + "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" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "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" + } + }, + "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": { + "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" + } + }, + "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-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-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" + } + }, + "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 + } + } + }, + "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" + } + } + } + }, + "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" + } + } + } + }, + "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" + } + } + } + }, + "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" + } + }, + "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-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" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "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 + }, + "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" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webdriver-js-extender": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz", + "integrity": "sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=", + "dev": true, + "requires": { + "@types/selenium-webdriver": "^2.53.35", + "selenium-webdriver": "^2.53.2" + }, + "dependencies": { + "adm-zip": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", + "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=", + "dev": true + }, + "sax": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", + "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=", + "dev": true + }, + "selenium-webdriver": { + "version": "2.53.3", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz", + "integrity": "sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU=", + "dev": true, + "requires": { + "adm-zip": "0.4.4", + "rimraf": "^2.2.8", + "tmp": "0.0.24", + "ws": "^1.0.1", + "xml2js": "0.4.4" + } + }, + "tmp": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz", + "integrity": "sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI=", + "dev": true + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", + "dev": true + }, + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "dev": true, + "requires": { + "options": ">=0.0.5", + "ultron": "1.0.x" + } + }, + "xml2js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz", + "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=", + "dev": true, + "requires": { + "sax": "0.6.x", + "xmlbuilder": ">=1.0.0" + } + } + } + }, + "webpack": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.11.0.tgz", + "integrity": "sha512-3kOFejWqj5ISpJk4Qj/V7w98h9Vl52wak3CLiw/cDOfbVTq7FeoZ0SdoHHY9PYlHr50ZS42OfvzE2vB4nncKQg==", + "dev": true, + "requires": { + "acorn": "^5.0.0", + "acorn-dynamic-import": "^2.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "async": "^2.1.2", + "enhanced-resolve": "^3.4.0", + "escope": "^3.6.0", + "interpret": "^1.0.0", + "json-loader": "^0.5.4", + "json5": "^0.5.1", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "mkdirp": "~0.5.0", + "node-libs-browser": "^2.0.0", + "source-map": "^0.5.3", + "supports-color": "^4.2.1", + "tapable": "^0.2.7", + "uglifyjs-webpack-plugin": "^0.4.6", + "watchpack": "^1.4.0", + "webpack-sources": "^1.0.1", + "yargs": "^8.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.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" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "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" + }, + "dependencies": { + "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 + }, + "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 + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, + "uglifyjs-webpack-plugin": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", + "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", + "dev": true, + "requires": { + "source-map": "^0.5.6", + "uglify-js": "^2.8.29", + "webpack-sources": "^1.0.1" + } + }, + "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 + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^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": "^7.0.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 + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "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" + } + } + } + } + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "^4.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 + } + } + } + } + }, + "webpack-dev-middleware": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz", + "integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==", + "dev": true, + "requires": { + "memory-fs": "~0.4.1", + "mime": "^1.5.0", + "path-is-absolute": "^1.0.0", + "range-parser": "^1.0.3", + "time-stamp": "^2.0.0" + } + }, + "webpack-dev-server": { + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.3.tgz", + "integrity": "sha512-Qz22YEFhWx+M2vvJ+rQppRv39JA0h5NNbOOdODApdX6iZ52Diz7vTPXjF7kJlfn+Uc24Qr48I3SZ9yncQwRycg==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "array-includes": "^3.0.3", + "bonjour": "^3.5.0", + "chokidar": "^2.0.0", + "compression": "^1.5.2", + "connect-history-api-fallback": "^1.3.0", + "debug": "^3.1.0", + "del": "^3.0.0", + "express": "^4.16.2", + "html-entities": "^1.2.0", + "http-proxy-middleware": "~0.17.4", + "import-local": "^1.0.0", + "internal-ip": "1.2.0", + "ip": "^1.1.5", + "killable": "^1.0.0", + "loglevel": "^1.4.1", + "opn": "^5.1.0", + "portfinder": "^1.0.9", + "selfsigned": "^1.9.1", + "serve-index": "^1.7.2", + "sockjs": "0.3.19", + "sockjs-client": "1.1.5", + "spdy": "^3.4.1", + "strip-ansi": "^3.0.0", + "supports-color": "^5.1.0", + "webpack-dev-middleware": "1.12.2", + "yargs": "6.6.0" + }, + "dependencies": { + "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" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "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" + } + }, + "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" + }, + "dependencies": { + "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 + } + } + }, + "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" + } + }, + "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-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-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" + } + }, + "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 + } + } + }, + "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" + } + } + } + }, + "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" + } + } + } + }, + "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" + } + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "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" + } + }, + "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-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" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "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 + }, + "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" + } + }, + "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" + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^4.2.0" + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + } + } + } + }, + "webpack-merge": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.1.tgz", + "integrity": "sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw==", + "dev": true, + "requires": { + "lodash": "^4.17.5" + } + }, + "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 + } + } + }, + "webpack-subresource-integrity": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.3.2.tgz", + "integrity": "sha512-VpBtk0Ha1W0GebTzPj3Y8UqbmPDp+HqGlegRv+hS8g8/x818dw9NuEfJEOp5CF6zTPs3KF6aqknVu52Bh5h1eQ==", + "dev": true, + "requires": { + "webpack-sources": "^1.3.0" + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", + "dev": true + }, + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "with-callback": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/with-callback/-/with-callback-1.0.2.tgz", + "integrity": "sha1-oJYpuakgAo1yFAT7Q1vc/1yRvCE=", + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "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" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + }, + "dependencies": { + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + } + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true, + "optional": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "requires": { + "cuint": "^0.2.2" + } + }, + "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": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true, + "optional": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true, + "optional": true + } + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "^3.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true, + "optional": true + } + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + }, + "zone.js": { + "version": "0.8.29", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.29.tgz", + "integrity": "sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ==" + } + } +} diff --git a/spring-boot-angular/angularclient/package.json b/spring-boot-angular/angularclient/package.json new file mode 100644 index 0000000000..a745cf671a --- /dev/null +++ b/spring-boot-angular/angularclient/package.json @@ -0,0 +1,48 @@ +{ + "name": "sampleapp", + "version": "0.0.0", + "license": "MIT", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build --prod", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "^5.2.0", + "@angular/common": "^5.2.0", + "@angular/compiler": "^5.2.0", + "@angular/core": "^5.2.0", + "@angular/forms": "^5.2.0", + "@angular/http": "^5.2.0", + "@angular/platform-browser": "^5.2.0", + "@angular/platform-browser-dynamic": "^5.2.0", + "@angular/router": "^5.2.0", + "core-js": "^2.4.1", + "rxjs": "^5.5.6", + "zone.js": "^0.8.19" + }, + "devDependencies": { + "@angular/cli": "~1.7.4", + "@angular/compiler-cli": "^5.2.0", + "@angular/language-service": "^5.2.0", + "@types/jasmine": "~2.8.3", + "@types/jasminewd2": "~2.0.2", + "@types/node": "~6.0.60", + "codelyzer": "^4.0.1", + "jasmine-core": "~2.8.0", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~2.0.0", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "^1.2.1", + "karma-jasmine": "~1.1.0", + "karma-jasmine-html-reporter": "^0.2.2", + "protractor": "~5.1.2", + "ts-node": "~4.1.0", + "tslint": "~5.9.1", + "typescript": "~2.5.3" + } +} diff --git a/spring-boot-angular/angularclient/protractor.conf.js b/spring-boot-angular/angularclient/protractor.conf.js new file mode 100644 index 0000000000..7ee3b5ee86 --- /dev/null +++ b/spring-boot-angular/angularclient/protractor.conf.js @@ -0,0 +1,28 @@ +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './e2e/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: 'e2e/tsconfig.e2e.json' + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; diff --git a/spring-boot-angular/angularclient/src/app/app-routing.module.ts b/spring-boot-angular/angularclient/src/app/app-routing.module.ts new file mode 100644 index 0000000000..ecc848ac37 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/app-routing.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { UserListComponent } from './user-list/user-list.component'; +import { UserFormComponent } from './user-form/user-form.component'; + +const routes: Routes = [ + { path: 'users', component: UserListComponent }, + { path: 'adduser', component: UserFormComponent } +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/persistence-modules/hibernate5/transaction.log b/spring-boot-angular/angularclient/src/app/app.component.css similarity index 100% rename from persistence-modules/hibernate5/transaction.log rename to spring-boot-angular/angularclient/src/app/app.component.css diff --git a/spring-boot-angular/angularclient/src/app/app.component.html b/spring-boot-angular/angularclient/src/app/app.component.html new file mode 100644 index 0000000000..144a77ffe3 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/app.component.html @@ -0,0 +1,16 @@ +
+
+
+
+
+

{{ title }}

+ +
+
+ +
+
+
\ No newline at end of file diff --git a/spring-boot-angular/angularclient/src/app/app.component.spec.ts b/spring-boot-angular/angularclient/src/app/app.component.spec.ts new file mode 100644 index 0000000000..e4ca195309 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/app.component.spec.ts @@ -0,0 +1,31 @@ +import { TestBed, async } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AppComponent } from './app.component'; +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + RouterTestingModule + ], + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + it('should create the app', async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + })); + it(`should have as title 'app'`, async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('app'); + })); + it('should render title in a h1 tag', async(() => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); + })); +}); diff --git a/spring-boot-angular/angularclient/src/app/app.component.ts b/spring-boot-angular/angularclient/src/app/app.component.ts new file mode 100644 index 0000000000..b14112f90b --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/app.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + + title: string; + + constructor() { + this.title = 'Spring Boot - Angular Application'; + } +} diff --git a/spring-boot-angular/angularclient/src/app/app.module.ts b/spring-boot-angular/angularclient/src/app/app.module.ts new file mode 100644 index 0000000000..3c6c070d96 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/app.module.ts @@ -0,0 +1,26 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { AppRoutingModule } from './app-routing.module'; +import { FormsModule } from '@angular/forms'; +import { HttpClientModule } from '@angular/common/http'; +import { AppComponent } from './app.component'; +import { UserListComponent } from './user-list/user-list.component'; +import { UserFormComponent } from './user-form/user-form.component'; +import { UserService } from './service/user.service'; + +@NgModule({ + declarations: [ + AppComponent, + UserListComponent, + UserFormComponent + ], + imports: [ + BrowserModule, + AppRoutingModule, + HttpClientModule, + FormsModule + ], + providers: [UserService], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/spring-boot-angular/angularclient/src/app/model/user.ts b/spring-boot-angular/angularclient/src/app/model/user.ts new file mode 100644 index 0000000000..f78cda4bf9 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/model/user.ts @@ -0,0 +1,5 @@ +export class User { + id: string; + name: string; + email: string; +} diff --git a/spring-boot-angular/angularclient/src/app/service/user.service.spec.ts b/spring-boot-angular/angularclient/src/app/service/user.service.spec.ts new file mode 100644 index 0000000000..b26195c25d --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/service/user.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { UserService } from './user.service'; + +describe('UserService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [UserService] + }); + }); + + it('should be created', inject([UserService], (service: UserService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/spring-boot-angular/angularclient/src/app/service/user.service.ts b/spring-boot-angular/angularclient/src/app/service/user.service.ts new file mode 100644 index 0000000000..e587632017 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/service/user.service.ts @@ -0,0 +1,22 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { User } from '../model/user'; +import { Observable } from 'rxjs/Observable'; + +@Injectable() +export class UserService { + + private usersUrl: string; + + constructor(private http: HttpClient) { + this.usersUrl = 'http://localhost:8080/users'; + } + + public findAll(): Observable { + return this.http.get(this.usersUrl); + } + + public save(user: User) { + return this.http.post(this.usersUrl, user); + } +} diff --git a/spring-boot-angular/angularclient/src/app/user-form/user-form.component.css b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-boot-angular/angularclient/src/app/user-form/user-form.component.html b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.html new file mode 100644 index 0000000000..7cf1800e50 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.html @@ -0,0 +1,19 @@ +
+
+
+
+ + +
+
Name is required
+
+ + +
Email is required
+
+ +
+
+
\ No newline at end of file diff --git a/spring-boot-angular/angularclient/src/app/user-form/user-form.component.spec.ts b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.spec.ts new file mode 100644 index 0000000000..9e613476f5 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserFormComponent } from './user-form.component'; + +describe('UserFormComponent', () => { + let component: UserFormComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ UserFormComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/spring-boot-angular/angularclient/src/app/user-form/user-form.component.ts b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.ts new file mode 100644 index 0000000000..869d53aede --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/user-form/user-form.component.ts @@ -0,0 +1,26 @@ +import { Component } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { UserService } from '../service/user.service'; +import { User } from '../model/user'; + +@Component({ + selector: 'app-user-form', + templateUrl: './user-form.component.html', + styleUrls: ['./user-form.component.css'] +}) +export class UserFormComponent { + + user: User; + + constructor(private route: ActivatedRoute, private router: Router, private userService: UserService) { + this.user = new User(); + } + + onSubmit() { + this.userService.save(this.user).subscribe(result => this.gotoUserList()); + } + + gotoUserList() { + this.router.navigate(['/users']); + } +} diff --git a/spring-boot-angular/angularclient/src/app/user-list/user-list.component.css b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-boot-angular/angularclient/src/app/user-list/user-list.component.html b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.html new file mode 100644 index 0000000000..1ac849f552 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.html @@ -0,0 +1,20 @@ +
+
+ + + + + + + + + + + + + + + +
#NameEmail
{{ user.id }}{{ user.name }}{{ user.email }}
+
+
\ No newline at end of file diff --git a/spring-boot-angular/angularclient/src/app/user-list/user-list.component.spec.ts b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.spec.ts new file mode 100644 index 0000000000..9d521807d6 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserListComponent } from './user-list.component'; + +describe('UserListComponent', () => { + let component: UserListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ UserListComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/spring-boot-angular/angularclient/src/app/user-list/user-list.component.ts b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.ts new file mode 100644 index 0000000000..91226695f5 --- /dev/null +++ b/spring-boot-angular/angularclient/src/app/user-list/user-list.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit } from '@angular/core'; +import { User } from '../model/user'; +import { UserService } from '../service/user.service'; + +@Component({ + selector: 'app-user-list', + templateUrl: './user-list.component.html', + styleUrls: ['./user-list.component.css'] +}) +export class UserListComponent implements OnInit { + + users: User[]; + + constructor(private userService: UserService) { + + } + + ngOnInit() { + this.userService.findAll().subscribe(data => { + this.users = data; + }); + } +} diff --git a/spring-boot-angular/angularclient/src/assets/.gitkeep b/spring-boot-angular/angularclient/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-boot-angular/angularclient/src/environments/environment.prod.ts b/spring-boot-angular/angularclient/src/environments/environment.prod.ts new file mode 100644 index 0000000000..3612073bc3 --- /dev/null +++ b/spring-boot-angular/angularclient/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/spring-boot-angular/angularclient/src/environments/environment.ts b/spring-boot-angular/angularclient/src/environments/environment.ts new file mode 100644 index 0000000000..b7f639aeca --- /dev/null +++ b/spring-boot-angular/angularclient/src/environments/environment.ts @@ -0,0 +1,8 @@ +// The file contents for the current environment will overwrite these during build. +// The build system defaults to the dev environment which uses `environment.ts`, but if you do +// `ng build --env=prod` then `environment.prod.ts` will be used instead. +// The list of which env maps to which file can be found in `.angular-cli.json`. + +export const environment = { + production: false +}; diff --git a/spring-boot-angular/angularclient/src/favicon.ico b/spring-boot-angular/angularclient/src/favicon.ico new file mode 100644 index 0000000000..8081c7ceaf Binary files /dev/null and b/spring-boot-angular/angularclient/src/favicon.ico differ diff --git a/spring-boot-angular/angularclient/src/index.html b/spring-boot-angular/angularclient/src/index.html new file mode 100644 index 0000000000..1ce7ff1ca6 --- /dev/null +++ b/spring-boot-angular/angularclient/src/index.html @@ -0,0 +1,17 @@ + + + + + + Spring Boot - Angular Application + + + + + + + + + + \ No newline at end of file diff --git a/spring-boot-angular/angularclient/src/main.ts b/spring-boot-angular/angularclient/src/main.ts new file mode 100644 index 0000000000..91ec6da5f0 --- /dev/null +++ b/spring-boot-angular/angularclient/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.log(err)); diff --git a/spring-boot-angular/angularclient/src/polyfills.ts b/spring-boot-angular/angularclient/src/polyfills.ts new file mode 100644 index 0000000000..af84770782 --- /dev/null +++ b/spring-boot-angular/angularclient/src/polyfills.ts @@ -0,0 +1,79 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +// import 'core-js/es6/symbol'; +// import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +// import 'core-js/es6/string'; +// import 'core-js/es6/date'; +// import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/weak-map'; +// import 'core-js/es6/set'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + + +/** Evergreen browsers require these. **/ +// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. +import 'core-js/es7/reflect'; + + +/** + * Required to support Web Animations `@angular/platform-browser/animations`. + * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + */ + + // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + + /* + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + */ +// (window as any).__Zone_enable_cross_context_check = true; + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/spring-boot-angular/angularclient/src/styles.css b/spring-boot-angular/angularclient/src/styles.css new file mode 100644 index 0000000000..90d4ee0072 --- /dev/null +++ b/spring-boot-angular/angularclient/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/spring-boot-angular/angularclient/src/tsconfig.app.json b/spring-boot-angular/angularclient/src/tsconfig.app.json new file mode 100644 index 0000000000..39ba8dbacb --- /dev/null +++ b/spring-boot-angular/angularclient/src/tsconfig.app.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "baseUrl": "./", + "module": "es2015", + "types": [] + }, + "exclude": [ + "test.ts", + "**/*.spec.ts" + ] +} diff --git a/spring-boot-angular/angularclient/src/tsconfig.spec.json b/spring-boot-angular/angularclient/src/tsconfig.spec.json new file mode 100644 index 0000000000..ac22a298ac --- /dev/null +++ b/spring-boot-angular/angularclient/src/tsconfig.spec.json @@ -0,0 +1,19 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/spec", + "baseUrl": "./", + "module": "commonjs", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/spring-boot-angular/angularclient/src/typings.d.ts b/spring-boot-angular/angularclient/src/typings.d.ts new file mode 100644 index 0000000000..ef5c7bd620 --- /dev/null +++ b/spring-boot-angular/angularclient/src/typings.d.ts @@ -0,0 +1,5 @@ +/* SystemJS module definition */ +declare var module: NodeModule; +interface NodeModule { + id: string; +} diff --git a/spring-boot-angular/angularclient/tsconfig.json b/spring-boot-angular/angularclient/tsconfig.json new file mode 100644 index 0000000000..a6c016bf38 --- /dev/null +++ b/spring-boot-angular/angularclient/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2017", + "dom" + ] + } +} diff --git a/spring-boot-angular/angularclient/tslint.json b/spring-boot-angular/angularclient/tslint.json new file mode 100644 index 0000000000..9963d6c395 --- /dev/null +++ b/spring-boot-angular/angularclient/tslint.json @@ -0,0 +1,143 @@ +{ + "rulesDirectory": [ + "node_modules/codelyzer" + ], + "rules": { + "arrow-return-shorthand": true, + "callable-types": true, + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "deprecation": { + "severity": "warn" + }, + "eofline": true, + "forin": true, + "import-blacklist": [ + true, + "rxjs", + "rxjs/Rx" + ], + "import-spacing": true, + "indent": [ + true, + "spaces" + ], + "interface-over-type-literal": true, + "label-position": true, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-super": true, + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-misused-new": true, + "no-non-null-assertion": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unnecessary-initializer": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "prefer-const": true, + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + true, + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "unified-signatures": true, + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ], + "no-output-on-prefix": true, + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": true, + "component-class-suffix": true, + "directive-class-suffix": true + } +} diff --git a/spring-boot-angular/pom.xml b/spring-boot-angular/pom.xml new file mode 100644 index 0000000000..6ea98eb3d0 --- /dev/null +++ b/spring-boot-angular/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + com.baeldung.springbootangular + spring-boot-angular + spring-boot-angular + 1.0 + jar + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + com.h2database + h2 + 1.4.197 + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-boot-angular/src/main/java/com/baeldung/application/Application.java b/spring-boot-angular/src/main/java/com/baeldung/application/Application.java new file mode 100644 index 0000000000..f1155c3106 --- /dev/null +++ b/spring-boot-angular/src/main/java/com/baeldung/application/Application.java @@ -0,0 +1,28 @@ +package com.baeldung.application; + +import com.baeldung.application.entities.User; +import com.baeldung.application.repositories.UserRepository; +import java.util.stream.Stream; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Bean + CommandLineRunner init(UserRepository userRepository) { + return args -> { + Stream.of("John", "Julie", "Jennifer", "Helen", "Rachel").forEach(name -> { + User user = new User(name, name.toLowerCase() + "@domain.com"); + userRepository.save(user); + }); + userRepository.findAll().forEach(System.out::println); + }; + } +} diff --git a/spring-boot-angular/src/main/java/com/baeldung/application/controllers/UserController.java b/spring-boot-angular/src/main/java/com/baeldung/application/controllers/UserController.java new file mode 100644 index 0000000000..14c90d5b10 --- /dev/null +++ b/spring-boot-angular/src/main/java/com/baeldung/application/controllers/UserController.java @@ -0,0 +1,31 @@ +package com.baeldung.application.controllers; + +import com.baeldung.application.entities.User; +import com.baeldung.application.repositories.UserRepository; +import java.util.List; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@CrossOrigin(origins = "http://localhost:4200") +public class UserController { + + private final UserRepository userRepository; + + public UserController(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @GetMapping("/users") + public List getUsers() { + return (List) userRepository.findAll(); + } + + @PostMapping("/users") + void addUser(@RequestBody User user) { + userRepository.save(user); + } +} diff --git a/spring-boot-angular/src/main/java/com/baeldung/application/entities/User.java b/spring-boot-angular/src/main/java/com/baeldung/application/entities/User.java new file mode 100644 index 0000000000..4c346fa5b9 --- /dev/null +++ b/spring-boot-angular/src/main/java/com/baeldung/application/entities/User.java @@ -0,0 +1,43 @@ +package com.baeldung.application.entities; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + private final String name; + private final String email; + + public User() { + this.name = ""; + this.email = ""; + } + + public User(String name, String email) { + this.name = name; + this.email = email; + } + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + @Override + public String toString() { + return "User{" + "id=" + id + ", name=" + name + ", email=" + email + '}'; + } +} diff --git a/spring-boot-angular/src/main/java/com/baeldung/application/repositories/UserRepository.java b/spring-boot-angular/src/main/java/com/baeldung/application/repositories/UserRepository.java new file mode 100644 index 0000000000..5a81cadcbe --- /dev/null +++ b/spring-boot-angular/src/main/java/com/baeldung/application/repositories/UserRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.application.repositories; + +import com.baeldung.application.entities.User; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; +import org.springframework.web.bind.annotation.CrossOrigin; + +@Repository +public interface UserRepository extends CrudRepository{} diff --git a/spring-boot-angular/src/main/java/com/baeldung/pom.xml b/spring-boot-angular/src/main/java/com/baeldung/pom.xml new file mode 100644 index 0000000000..d4ebc870b4 --- /dev/null +++ b/spring-boot-angular/src/main/java/com/baeldung/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + com.baeldung.springbootangular + spring-boot-angular + 1.0 + jar + Spring Boot Angular Application + + org.springframework.boot + spring-boot-starter-parent + 2.1.3.RELEASE + + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + com.h2database + h2 + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/spring-boot-bootstrap/README.md b/spring-boot-bootstrap/README.md index 2186aa8fec..6a88f25bd7 100644 --- a/spring-boot-bootstrap/README.md +++ b/spring-boot-bootstrap/README.md @@ -1,6 +1,5 @@ ### Relevant Articles: -- [Bootstrap a Simple Application using Spring Boot](http://www.baeldung.com/spring-boot-start) -- [Spring Boot Dependency Management with a Custom Parent](http://www.baeldung.com/spring-boot-dependency-management-custom-parent) +- [Spring Boot Tutorial – Bootstrap a Simple Application](http://www.baeldung.com/spring-boot-start) - [Thin JARs with Spring Boot](http://www.baeldung.com/spring-boot-thin-jar) - [Deploying a Spring Boot Application to Cloud Foundry](https://www.baeldung.com/spring-boot-app-deploy-to-cloud-foundry) - [Deploy a Spring Boot Application to Google App Engine](https://www.baeldung.com/spring-boot-google-app-engine) diff --git a/spring-boot-bootstrap/pom.xml b/spring-boot-bootstrap/pom.xml index f13801f532..70ebb225c8 100644 --- a/spring-boot-bootstrap/pom.xml +++ b/spring-boot-bootstrap/pom.xml @@ -84,7 +84,7 @@ openshift 0.3.0.RELEASE - Finchley.SR2 + Greenwich.RELEASE 3.5.37 @@ -166,7 +166,7 @@ org.springframework.cloud spring-cloud-dependencies - Finchley.SR1 + Greenwich.RELEASE pom import @@ -214,7 +214,7 @@ org.springframework.cloud spring-cloud-dependencies - Finchley.SR1 + Greenwich.RELEASE pom import diff --git a/spring-boot-bootstrap/src/main/java/com/baeldung/Application.java b/spring-boot-bootstrap/src/main/java/com/baeldung/Application.java index 567e9b2678..d5a597e48b 100644 --- a/spring-boot-bootstrap/src/main/java/com/baeldung/Application.java +++ b/spring-boot-bootstrap/src/main/java/com/baeldung/Application.java @@ -4,12 +4,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.boot.web.servlet.ServletComponentScan; -import org.springframework.context.annotation.ComponentScan; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @ServletComponentScan -@SpringBootApplication -@ComponentScan("com.baeldung") +@SpringBootApplication(scanBasePackages = "com.baeldung") @EnableJpaRepositories("com.baeldung.persistence.repo") @EntityScan("com.baeldung.persistence.model") public class Application { diff --git a/spring-boot-bootstrap/src/main/resources/templates/error.html b/spring-boot-bootstrap/src/main/resources/templates/error.html index f2b51a1938..ca3a740b71 100644 --- a/spring-boot-bootstrap/src/main/resources/templates/error.html +++ b/spring-boot-bootstrap/src/main/resources/templates/error.html @@ -1,19 +1,19 @@ - + Error Occurred
-

Error Occurred!

-
- \ No newline at end of file + diff --git a/spring-boot-bootstrap/src/main/resources/templates/home.html b/spring-boot-bootstrap/src/main/resources/templates/home.html index 5707cfb82a..0428ca1127 100644 --- a/spring-boot-bootstrap/src/main/resources/templates/home.html +++ b/spring-boot-bootstrap/src/main/resources/templates/home.html @@ -1,7 +1,7 @@ - + Home Page

Hello !

Welcome to Our App

- \ No newline at end of file + diff --git a/spring-boot-crud/pom.xml b/spring-boot-crud/pom.xml index 749bf9cb5a..73635b0a1c 100644 --- a/spring-boot-crud/pom.xml +++ b/spring-boot-crud/pom.xml @@ -3,15 +3,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 - com.baeldung.spring-boot-crud spring-boot-crud - 0.1.0 spring-boot-crud - org.springframework.boot - spring-boot-starter-parent - 2.0.6.RELEASE + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 @@ -41,11 +40,7 @@ h2 runtime
-
- - UTF-8 - 1.8 - + spring-boot-crud @@ -62,4 +57,10 @@ + + + UTF-8 + 1.8 + + \ No newline at end of file diff --git a/spring-boot-data/README.md b/spring-boot-data/README.md new file mode 100644 index 0000000000..21f7303c48 --- /dev/null +++ b/spring-boot-data/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Formatting JSON Dates in Spring ](https://www.baeldung.com/spring-boot-formatting-json-dates) \ No newline at end of file diff --git a/spring-boot-data/pom.xml b/spring-boot-data/pom.xml new file mode 100644 index 0000000000..8735a54e7b --- /dev/null +++ b/spring-boot-data/pom.xml @@ -0,0 +1,122 @@ + + + 4.0.0 + spring-boot-data + war + spring-boot-data + Spring Boot Data Module + + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + spring-boot + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-war-plugin + + + + pl.project13.maven + git-commit-id-plugin + ${git-commit-id-plugin.version} + + + get-the-git-infos + + revision + + initialize + + + validate-the-git-infos + + validateRevision + + package + + + + true + ${project.build.outputDirectory}/git.properties + + + + + + + + + autoconfiguration + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*LiveTest.java + **/*IntegrationTest.java + **/*IntTest.java + + + **/AutoconfigurationTest.java + + + + + + + json + + + + + + + + + + com.baeldung.SpringBootDataApplication + 2.2.4 + + + diff --git a/spring-boot-data/src/main/java/com/baeldung/SpringBootDataApplication.java b/spring-boot-data/src/main/java/com/baeldung/SpringBootDataApplication.java new file mode 100644 index 0000000000..3aa093bb41 --- /dev/null +++ b/spring-boot-data/src/main/java/com/baeldung/SpringBootDataApplication.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootDataApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootDataApplication.class, args); + } + +} diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/Contact.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/Contact.java new file mode 100644 index 0000000000..f131d17196 --- /dev/null +++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/Contact.java @@ -0,0 +1,70 @@ +package com.baeldung.jsondateformat; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +public class Contact { + + private String name; + private String address; + private String phone; + + @JsonFormat(pattern="yyyy-MM-dd") + private LocalDate birthday; + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") + private LocalDateTime lastUpdate; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public LocalDate getBirthday() { + return birthday; + } + + public void setBirthday(LocalDate birthday) { + this.birthday = birthday; + } + + public LocalDateTime getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(LocalDateTime lastUpdate) { + this.lastUpdate = lastUpdate; + } + + public Contact() { + } + + public Contact(String name, String address, String phone, LocalDate birthday, LocalDateTime lastUpdate) { + this.name = name; + this.address = address; + this.phone = phone; + this.birthday = birthday; + this.lastUpdate = lastUpdate; + } +} diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactApp.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactApp.java new file mode 100644 index 0000000000..79037e1038 --- /dev/null +++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactApp.java @@ -0,0 +1,13 @@ +package com.baeldung.jsondateformat; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ContactApp { + + public static void main(String[] args) { + SpringApplication.run(ContactApp.class, args); + } + +} diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactAppConfig.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactAppConfig.java new file mode 100644 index 0000000000..7a20ebfa51 --- /dev/null +++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactAppConfig.java @@ -0,0 +1,33 @@ +package com.baeldung.jsondateformat; + +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; + +import java.time.format.DateTimeFormatter; + +@Configuration +public class ContactAppConfig { + + private static final String dateFormat = "yyyy-MM-dd"; + + private static final String dateTimeFormat = "yyyy-MM-dd HH:mm:ss"; + + @Bean + @ConditionalOnProperty(value = "spring.jackson.date-format", matchIfMissing = true, havingValue = "none") + public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() { + return new Jackson2ObjectMapperBuilderCustomizer() { + @Override + public void customize(Jackson2ObjectMapperBuilder builder) { + builder.simpleDateFormat(dateTimeFormat); + builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat))); + builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat))); + } + }; + } + +} diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactController.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactController.java new file mode 100644 index 0000000000..8894d82fc7 --- /dev/null +++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactController.java @@ -0,0 +1,77 @@ +package com.baeldung.jsondateformat; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@RestController +@RequestMapping(value = "/contacts") +public class ContactController { + + @GetMapping + public List getContacts() { + List contacts = new ArrayList<>(); + + Contact contact1 = new Contact("John Doe", "123 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now()); + Contact contact2 = new Contact("John Doe 2", "124 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now()); + Contact contact3 = new Contact("John Doe 3", "125 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now()); + + contacts.add(contact1); + contacts.add(contact2); + contacts.add(contact3); + + return contacts; + } + + @GetMapping("/javaUtilDate") + public List getContactsWithJavaUtilDate() { + List contacts = new ArrayList<>(); + + ContactWithJavaUtilDate contact1 = new ContactWithJavaUtilDate("John Doe", "123 Sesame Street", "123-456-789", new Date(), new Date()); + ContactWithJavaUtilDate contact2 = new ContactWithJavaUtilDate("John Doe 2", "124 Sesame Street", "123-456-789", new Date(), new Date()); + ContactWithJavaUtilDate contact3 = new ContactWithJavaUtilDate("John Doe 3", "125 Sesame Street", "123-456-789", new Date(), new Date()); + + contacts.add(contact1); + contacts.add(contact2); + contacts.add(contact3); + + return contacts; + } + + @GetMapping("/plain") + public List getPlainContacts() { + List contacts = new ArrayList<>(); + + PlainContact contact1 = new PlainContact("John Doe", "123 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now()); + PlainContact contact2 = new PlainContact("John Doe 2", "124 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now()); + PlainContact contact3 = new PlainContact("John Doe 3", "125 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now()); + + contacts.add(contact1); + contacts.add(contact2); + contacts.add(contact3); + + return contacts; + } + + @GetMapping("/plainWithJavaUtilDate") + public List getPlainContactsWithJavaUtilDate() { + List contacts = new ArrayList<>(); + + PlainContactWithJavaUtilDate contact1 = new PlainContactWithJavaUtilDate("John Doe", "123 Sesame Street", "123-456-789", new Date(), new Date()); + PlainContactWithJavaUtilDate contact2 = new PlainContactWithJavaUtilDate("John Doe 2", "124 Sesame Street", "123-456-789", new Date(), new Date()); + PlainContactWithJavaUtilDate contact3 = new PlainContactWithJavaUtilDate("John Doe 3", "125 Sesame Street", "123-456-789", new Date(), new Date()); + + contacts.add(contact1); + contacts.add(contact2); + contacts.add(contact3); + + return contacts; + } + +} diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactWithJavaUtilDate.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactWithJavaUtilDate.java new file mode 100644 index 0000000000..5a1c508098 --- /dev/null +++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactWithJavaUtilDate.java @@ -0,0 +1,69 @@ +package com.baeldung.jsondateformat; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.util.Date; + +public class ContactWithJavaUtilDate { + + private String name; + private String address; + private String phone; + + @JsonFormat(pattern="yyyy-MM-dd") + private Date birthday; + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") + private Date lastUpdate; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Date getBirthday() { + return birthday; + } + + public void setBirthday(Date birthday) { + this.birthday = birthday; + } + + public Date getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(Date lastUpdate) { + this.lastUpdate = lastUpdate; + } + + public ContactWithJavaUtilDate() { + } + + public ContactWithJavaUtilDate(String name, String address, String phone, Date birthday, Date lastUpdate) { + this.name = name; + this.address = address; + this.phone = phone; + this.birthday = birthday; + this.lastUpdate = lastUpdate; + } +} diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContact.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContact.java new file mode 100644 index 0000000000..7e9e53d205 --- /dev/null +++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContact.java @@ -0,0 +1,66 @@ +package com.baeldung.jsondateformat; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +public class PlainContact { + + private String name; + private String address; + private String phone; + + private LocalDate birthday; + + private LocalDateTime lastUpdate; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public LocalDate getBirthday() { + return birthday; + } + + public void setBirthday(LocalDate birthday) { + this.birthday = birthday; + } + + public LocalDateTime getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(LocalDateTime lastUpdate) { + this.lastUpdate = lastUpdate; + } + + public PlainContact() { + } + + public PlainContact(String name, String address, String phone, LocalDate birthday, LocalDateTime lastUpdate) { + this.name = name; + this.address = address; + this.phone = phone; + this.birthday = birthday; + this.lastUpdate = lastUpdate; + } +} diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContactWithJavaUtilDate.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContactWithJavaUtilDate.java new file mode 100644 index 0000000000..daefb15543 --- /dev/null +++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContactWithJavaUtilDate.java @@ -0,0 +1,69 @@ +package com.baeldung.jsondateformat; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.util.Date; + +public class PlainContactWithJavaUtilDate { + + private String name; + private String address; + private String phone; + + @JsonFormat(pattern="yyyy-MM-dd") + private Date birthday; + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") + private Date lastUpdate; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Date getBirthday() { + return birthday; + } + + public void setBirthday(Date birthday) { + this.birthday = birthday; + } + + public Date getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(Date lastUpdate) { + this.lastUpdate = lastUpdate; + } + + public PlainContactWithJavaUtilDate() { + } + + public PlainContactWithJavaUtilDate(String name, String address, String phone, Date birthday, Date lastUpdate) { + this.name = name; + this.address = address; + this.phone = phone; + this.birthday = birthday; + this.lastUpdate = lastUpdate; + } +} diff --git a/spring-boot-data/src/main/resources/application.properties b/spring-boot-data/src/main/resources/application.properties new file mode 100644 index 0000000000..845b783634 --- /dev/null +++ b/spring-boot-data/src/main/resources/application.properties @@ -0,0 +1,2 @@ +spring.jackson.date-format=yyyy-MM-dd HH:mm:ss +spring.jackson.time-zone=Europe/Zagreb \ No newline at end of file diff --git a/spring-boot-data/src/test/java/com/baeldung/jsondateformat/ContactAppIntegrationTest.java b/spring-boot-data/src/test/java/com/baeldung/jsondateformat/ContactAppIntegrationTest.java new file mode 100644 index 0000000000..f76440d1bc --- /dev/null +++ b/spring-boot-data/src/test/java/com/baeldung/jsondateformat/ContactAppIntegrationTest.java @@ -0,0 +1,100 @@ +package com.baeldung.jsondateformat; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import java.io.IOException; +import java.text.ParseException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, classes = ContactApp.class) +@TestPropertySource(properties = { + "spring.jackson.date-format=yyyy-MM-dd HH:mm:ss" +}) +public class ContactAppIntegrationTest { + + private final ObjectMapper mapper = new ObjectMapper(); + + @LocalServerPort + private int port; + + @Autowired + private TestRestTemplate restTemplate; + + @Test + public void givenJsonFormatAnnotationAndJava8DateType_whenGet_thenReturnExpectedDateFormat() throws IOException, ParseException { + ResponseEntity response = restTemplate.getForEntity("http://localhost:" + port + "/contacts", String.class); + + assertEquals(200, response.getStatusCodeValue()); + + List> respMap = mapper.readValue(response.getBody(), new TypeReference>>(){}); + + LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + + assertNotNull(birthdayDate); + assertNotNull(lastUpdateTime); + } + + @Test + public void givenJsonFormatAnnotationAndLegacyDateType_whenGet_thenReturnExpectedDateFormat() throws IOException { + ResponseEntity response = restTemplate.getForEntity("http://localhost:" + port + "/contacts/javaUtilDate", String.class); + + assertEquals(200, response.getStatusCodeValue()); + + List> respMap = mapper.readValue(response.getBody(), new TypeReference>>(){}); + + LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + + assertNotNull(birthdayDate); + assertNotNull(lastUpdateTime); + } + + @Test + public void givenDefaultDateFormatInAppPropertiesAndLegacyDateType_whenGet_thenReturnExpectedDateFormat() throws IOException { + ResponseEntity response = restTemplate.getForEntity("http://localhost:" + port + "/contacts/plainWithJavaUtilDate", String.class); + + assertEquals(200, response.getStatusCodeValue()); + + List> respMap = mapper.readValue(response.getBody(), new TypeReference>>(){}); + + LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + + assertNotNull(birthdayDate); + assertNotNull(lastUpdateTime); + } + + @Test(expected = DateTimeParseException.class) + public void givenDefaultDateFormatInAppPropertiesAndJava8DateType_whenGet_thenNotApplyFormat() throws IOException { + ResponseEntity response = restTemplate.getForEntity("http://localhost:" + port + "/contacts/plain", String.class); + + assertEquals(200, response.getStatusCodeValue()); + + List> respMap = mapper.readValue(response.getBody(), new TypeReference>>(){}); + + LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } + +} diff --git a/spring-boot-data/src/test/java/com/baeldung/jsondateformat/ContactAppWithObjectMapperCustomizerIntegrationTest.java b/spring-boot-data/src/test/java/com/baeldung/jsondateformat/ContactAppWithObjectMapperCustomizerIntegrationTest.java new file mode 100644 index 0000000000..c286012653 --- /dev/null +++ b/spring-boot-data/src/test/java/com/baeldung/jsondateformat/ContactAppWithObjectMapperCustomizerIntegrationTest.java @@ -0,0 +1,67 @@ +package com.baeldung.jsondateformat; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, classes = ContactApp.class) +public class ContactAppWithObjectMapperCustomizerIntegrationTest { + + private final ObjectMapper mapper = new ObjectMapper(); + + @Autowired + private TestRestTemplate restTemplate; + + @LocalServerPort + private int port; + + @Test + public void givenDefaultDateFormatInAppPropertiesAndLegacyDateType_whenGet_thenReturnExpectedDateFormat() throws IOException { + ResponseEntity response = restTemplate.getForEntity("http://localhost:" + this.port + "/contacts/plainWithJavaUtilDate", String.class); + + assertEquals(200, response.getStatusCodeValue()); + + List> respMap = mapper.readValue(response.getBody(), new TypeReference>>(){}); + + LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + + assertNotNull(birthdayDate); + assertNotNull(lastUpdateTime); + } + + @Test + public void givenDefaultDateFormatInAppPropertiesAndJava8DateType_whenGet_thenReturnExpectedDateFormat() throws IOException { + ResponseEntity response = restTemplate.getForEntity("http://localhost:" + this.port + "/contacts/plain", String.class); + + assertEquals(200, response.getStatusCodeValue()); + + List> respMap = mapper.readValue(response.getBody(), new TypeReference>>(){}); + + LocalDate birthdayDate = LocalDate.parse(respMap.get(0).get("birthday"), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + LocalDateTime lastUpdateTime = LocalDateTime.parse(respMap.get(0).get("lastUpdate"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + + assertNotNull(birthdayDate); + assertNotNull(lastUpdateTime); + } + +} diff --git a/spring-boot-data/src/test/resources/application.properties b/spring-boot-data/src/test/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-boot-disable-console-logging/disabling-console-jul/pom.xml b/spring-boot-disable-console-logging/disabling-console-jul/pom.xml index 9ccbd56231..f6f7890df1 100644 --- a/spring-boot-disable-console-logging/disabling-console-jul/pom.xml +++ b/spring-boot-disable-console-logging/disabling-console-jul/pom.xml @@ -6,10 +6,10 @@ - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - + org.springframework.boot + spring-boot-starter-parent + 2.1.1.RELEASE +
diff --git a/spring-boot-disable-console-logging/disabling-console-log4j2/pom.xml b/spring-boot-disable-console-logging/disabling-console-log4j2/pom.xml index 0b360bb366..1cf3eb3e68 100644 --- a/spring-boot-disable-console-logging/disabling-console-log4j2/pom.xml +++ b/spring-boot-disable-console-logging/disabling-console-log4j2/pom.xml @@ -6,10 +6,10 @@ - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - + org.springframework.boot + spring-boot-starter-parent + 2.1.1.RELEASE + diff --git a/spring-boot-keycloak/src/main/resources/application.properties b/spring-boot-keycloak/src/main/resources/application.properties index f667d3b27e..6e7da2cb90 100644 --- a/spring-boot-keycloak/src/main/resources/application.properties +++ b/spring-boot-keycloak/src/main/resources/application.properties @@ -1,3 +1,6 @@ +### server port +server.port=8081 + #Keycloak Configuration keycloak.auth-server-url=http://localhost:8180/auth keycloak.realm=SpringBootKeycloak diff --git a/spring-boot-libraries/README.MD b/spring-boot-libraries/README.MD index cc32ce8355..f3706e0fa4 100644 --- a/spring-boot-libraries/README.MD +++ b/spring-boot-libraries/README.MD @@ -4,3 +4,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: - [Guide to ShedLock with Spring](https://www.baeldung.com/shedlock-spring) +- [A Guide to the Problem Spring Web Library](https://www.baeldung.com/problem-spring-web) diff --git a/spring-boot-mvc/README.md b/spring-boot-mvc/README.md index 0e1ac5a8ce..d5a39cdc9f 100644 --- a/spring-boot-mvc/README.md +++ b/spring-boot-mvc/README.md @@ -11,3 +11,4 @@ - [Cache Eviction in Spring Boot](https://www.baeldung.com/spring-boot-evict-cache) - [Setting Up Swagger 2 with a Spring REST API](http://www.baeldung.com/swagger-2-documentation-for-spring-rest-api) - [Conditionally Enable Scheduled Jobs in Spring](https://www.baeldung.com/spring-scheduled-enabled-conditionally) +- [Accessing Spring MVC Model Objects in JavaScript](https://www.baeldung.com/spring-mvc-model-objects-js) diff --git a/spring-boot-ops/README.md b/spring-boot-ops/README.md index 553b02ebf0..d5063f14e5 100644 --- a/spring-boot-ops/README.md +++ b/spring-boot-ops/README.md @@ -10,3 +10,5 @@ - [Spring Boot Console Application](http://www.baeldung.com/spring-boot-console-app) - [Comparing Embedded Servlet Containers in Spring Boot](http://www.baeldung.com/spring-boot-servlet-containers) - [Programmatically Restarting a Spring Boot Application](https://www.baeldung.com/java-restart-spring-boot-app) + - [Spring Properties File Outside jar](https://www.baeldung.com/spring-properties-file-outside-jar) + diff --git a/spring-boot-ops/pom.xml b/spring-boot-ops/pom.xml index 625b2ad188..f36434b682 100644 --- a/spring-boot-ops/pom.xml +++ b/spring-boot-ops/pom.xml @@ -95,6 +95,15 @@ ${project.artifactId} + + + src/main/resources + true + + **/conf.properties + + + org.springframework.boot @@ -110,6 +119,29 @@ + + org.apache.maven.plugins + maven-failsafe-plugin + 2.18 + + + + integration-tests + + integration-test + verify + + + + + **/ExternalPropertyFileLoaderIntegrationTest.java + + + + + diff --git a/spring-boot-ops/src/main/java/com/baeldung/properties/ConfProperties.java b/spring-boot-ops/src/main/java/com/baeldung/properties/ConfProperties.java new file mode 100644 index 0000000000..0b6041bb06 --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/properties/ConfProperties.java @@ -0,0 +1,43 @@ +package com.baeldung.properties; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ConfProperties { + + @Value("${url}") + private String url; + + @Value("${username}") + private String username; + + @Value("${password}") + private String password; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + +} diff --git a/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyConfigurer.java b/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyConfigurer.java new file mode 100644 index 0000000000..0cdbb452d5 --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyConfigurer.java @@ -0,0 +1,18 @@ +package com.baeldung.properties; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.core.io.FileSystemResource; + +@Configuration +public class ExternalPropertyConfigurer { + + @Bean + public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer(); + properties.setLocation(new FileSystemResource("src/main/resources/external/conf.properties")); + properties.setIgnoreResourceNotFound(false); + return properties; + } +} \ No newline at end of file diff --git a/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyFileLoader.java b/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyFileLoader.java new file mode 100644 index 0000000000..dc5e14549b --- /dev/null +++ b/spring-boot-ops/src/main/java/com/baeldung/properties/ExternalPropertyFileLoader.java @@ -0,0 +1,18 @@ +package com.baeldung.properties; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ExternalPropertyFileLoader { + + @Autowired + ConfProperties prop; + + public static void main(String[] args) { + new SpringApplicationBuilder(ExternalPropertyFileLoader.class).build() + .run(args); + } + +} diff --git a/spring-boot-ops/src/main/resources/external/conf.properties b/spring-boot-ops/src/main/resources/external/conf.properties new file mode 100644 index 0000000000..cfcd23dc76 --- /dev/null +++ b/spring-boot-ops/src/main/resources/external/conf.properties @@ -0,0 +1,4 @@ +url=jdbc:postgresql://localhost:5432/ +username=admin +password=root +spring.main.allow-bean-definition-overriding=true \ No newline at end of file diff --git a/spring-boot-ops/src/test/java/com/baeldung/properties/ExternalPropertyFileLoaderIntegrationTest.java b/spring-boot-ops/src/test/java/com/baeldung/properties/ExternalPropertyFileLoaderIntegrationTest.java new file mode 100644 index 0000000000..2001db57d0 --- /dev/null +++ b/spring-boot-ops/src/test/java/com/baeldung/properties/ExternalPropertyFileLoaderIntegrationTest.java @@ -0,0 +1,27 @@ +package com.baeldung.properties; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = ExternalPropertyFileLoader.class) +public class ExternalPropertyFileLoaderIntegrationTest { + + @Autowired + ConfProperties props; + + @Test + public void whenExternalisedPropertiesLoaded_thenReadValues() throws IOException { + assertEquals("jdbc:postgresql://localhost:5432/", props.getUrl()); + assertEquals("admin", props.getUsername()); + assertEquals("root", props.getPassword()); + } + +} diff --git a/spring-boot-rest/README.md b/spring-boot-rest/README.md index 3fbd21f24e..af372077f0 100644 --- a/spring-boot-rest/README.md +++ b/spring-boot-rest/README.md @@ -6,3 +6,8 @@ Module for the articles that are part of the Spring REST E-book: 4. [Build a REST API with Spring and Java Config](http://www.baeldung.com/building-a-restful-web-service-with-spring-and-java-based-configuration) 5. [HATEOAS for a Spring REST Service](http://www.baeldung.com/rest-api-discoverability-with-spring) 6. [REST API Discoverability and HATEOAS](http://www.baeldung.com/restful-web-service-discoverability) +7. [Versioning a REST API](http://www.baeldung.com/rest-versioning) +8. [Http Message Converters with the Spring Framework](http://www.baeldung.com/spring-httpmessageconverter-rest) +9. [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring) +10. [Testing REST with multiple MIME types](http://www.baeldung.com/testing-rest-api-with-multiple-media-types) +11. [Testing Web APIs with Postman Collections](https://www.baeldung.com/postman-testing-collections) diff --git a/spring-boot-rest/pom.xml b/spring-boot-rest/pom.xml index 3c8c4d7486..decaccd148 100644 --- a/spring-boot-rest/pom.xml +++ b/spring-boot-rest/pom.xml @@ -25,16 +25,26 @@ com.fasterxml.jackson.dataformat jackson-dataformat-xml - + + + org.springframework + spring-oxm + + + com.thoughtworks.xstream + xstream + ${xstream.version} + + com.h2database h2 - + org.springframework.boot spring-boot-starter-data-jpa - - + + @@ -67,5 +77,6 @@ com.baeldung.SpringBootRestApplication 27.0.1-jre + 1.4.11.1 diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java index 1cc732ab08..fbbba23013 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java @@ -9,7 +9,7 @@ public interface IOperations { // read - one - T findOne(final long id); + T findById(final long id); // read - all diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java index 9af3d07bed..c8af731bc5 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java @@ -7,7 +7,11 @@ import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.Version; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Foo") @Entity public class Foo implements Serializable { @@ -17,6 +21,9 @@ public class Foo implements Serializable { @Column(nullable = false) private String name; + + @Version + private long version; public Foo() { super(); @@ -46,6 +53,14 @@ public class Foo implements Serializable { this.name = name; } + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + // @Override diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java index 5900c443b8..f589eaecf5 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java @@ -18,9 +18,8 @@ public abstract class AbstractService implements IOperat @Override @Transactional(readOnly = true) - public T findOne(final long id) { - return getDao().findById(id) - .get(); + public T findById(final long id) { + return getDao().findById(id).orElse(null); } // read - all diff --git a/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java b/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java index 80ee975e84..ab16b61e1d 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java +++ b/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java @@ -1,10 +1,69 @@ package com.baeldung.spring; +import java.util.List; + +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.http.converter.xml.MarshallingHttpMessageConverter; +import org.springframework.oxm.xstream.XStreamMarshaller; +import org.springframework.web.filter.ShallowEtagHeaderFilter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - @Configuration +// If we want to enable xml configurations for message-converter: +// @ImportResource("classpath:WEB-INF/api-servlet.xml") public class WebConfig implements WebMvcConfigurer { + // @Override + // public void configureMessageConverters(final List> messageConverters) { + // messageConverters.add(new MappingJackson2HttpMessageConverter()); + // messageConverters.add(createXmlHttpMessageConverter()); + // } + // + // private HttpMessageConverter createXmlHttpMessageConverter() { + // final MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter(); + // + // final XStreamMarshaller xstreamMarshaller = new XStreamMarshaller(); + // xstreamMarshaller.setAutodetectAnnotations(true); + // xmlConverter.setMarshaller(xstreamMarshaller); + // xmlConverter.setUnmarshaller(xstreamMarshaller); + // + // return xmlConverter; + // } + + // Another possibility is to create a bean which will be automatically added to the Spring Boot Autoconfigurations + // @Bean + // public HttpMessageConverter createXmlHttpMessageConverter() { + // final MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter(); + // + // final XStreamMarshaller xstreamMarshaller = new XStreamMarshaller(); + // xstreamMarshaller.setAutodetectAnnotations(true); + // xmlConverter.setMarshaller(xstreamMarshaller); + // xmlConverter.setUnmarshaller(xstreamMarshaller); + // + // return xmlConverter; + // } + + // Etags + + // If we're not using Spring Boot we can make use of + // AbstractAnnotationConfigDispatcherServletInitializer#getServletFilters + @Bean + public FilterRegistrationBean shallowEtagHeaderFilter() { + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>( new ShallowEtagHeaderFilter()); + filterRegistrationBean.addUrlPatterns("/foos/*"); + filterRegistrationBean.setName("etagFilter"); + return filterRegistrationBean; + } + + // We can also just declare the filter directly + // @Bean + // public ShallowEtagHeaderFilter shallowEtagHeaderFilter() { + // return new ShallowEtagHeaderFilter(); + // } + } \ No newline at end of file diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java index 59e33263db..8174480078 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java @@ -9,6 +9,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -19,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; import org.springframework.web.util.UriComponentsBuilder; import com.baeldung.persistence.model.Foo; @@ -31,7 +33,7 @@ import com.baeldung.web.util.RestPreconditions; import com.google.common.base.Preconditions; @RestController -@RequestMapping(value = "/auth/foos") +@RequestMapping(value = "/foos") public class FooController { @Autowired @@ -45,15 +47,34 @@ public class FooController { } // API + + // Note: the global filter overrides the ETag value we set here. We can still analyze its behaviour in the Integration Test. + @GetMapping(value = "/{id}/custom-etag") + public ResponseEntity findByIdWithCustomEtag(@PathVariable("id") final Long id, + final HttpServletResponse response) { + final Foo foo = RestPreconditions.checkFound(service.findById(id)); + + eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response)); + return ResponseEntity.ok() + .eTag(Long.toString(foo.getVersion())) + .body(foo); + } // read - one @GetMapping(value = "/{id}") public Foo findById(@PathVariable("id") final Long id, final HttpServletResponse response) { - final Foo resourceById = RestPreconditions.checkFound(service.findOne(id)); + try { + final Foo resourceById = RestPreconditions.checkFound(service.findById(id)); + + eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response)); + return resourceById; + } + catch (MyResourceNotFoundException exc) { + throw new ResponseStatusException( + HttpStatus.NOT_FOUND, "Foo Not Found", exc); + } - eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response)); - return resourceById; } // read - all @@ -107,7 +128,7 @@ public class FooController { @ResponseStatus(HttpStatus.OK) public void update(@PathVariable("id") final Long id, @RequestBody final Foo resource) { Preconditions.checkNotNull(resource); - RestPreconditions.checkFound(service.findOne(resource.getId())); + RestPreconditions.checkFound(service.findById(resource.getId())); service.update(resource); } diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java index 436e41e8eb..d618e9f0bf 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java @@ -7,34 +7,28 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.util.UriTemplate; import com.baeldung.web.util.LinkUtil; @Controller -@RequestMapping(value = "/auth/") public class RootController { - public RootController() { - super(); - } - // API // discover - @RequestMapping(value = "admin", method = RequestMethod.GET) + @GetMapping("/") @ResponseStatus(value = HttpStatus.NO_CONTENT) public void adminRoot(final HttpServletRequest request, final HttpServletResponse response) { final String rootUri = request.getRequestURL() .toString(); - final URI fooUri = new UriTemplate("{rootUri}/{resource}").expand(rootUri, "foo"); - final String linkToFoo = LinkUtil.createLinkHeader(fooUri.toASCIIString(), "collection"); - response.addHeader("Link", linkToFoo); + final URI fooUri = new UriTemplate("{rootUri}{resource}").expand(rootUri, "foos"); + final String linkToFoos = LinkUtil.createLinkHeader(fooUri.toASCIIString(), "collection"); + response.addHeader("Link", linkToFoos); } } diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/Student.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/Student.java new file mode 100644 index 0000000000..3b6a5c0298 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/Student.java @@ -0,0 +1,53 @@ +package com.baeldung.web.controller.students; + +public class Student { + + private long id; + private String firstName; + private String lastName; + + public Student() {} + + public Student(String firstName, String lastName) { + super(); + this.firstName = firstName; + this.lastName = lastName; + } + + public Student(long id, String firstName, String lastName) { + super(); + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]"; + } + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentController.java new file mode 100644 index 0000000000..f937e0c757 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentController.java @@ -0,0 +1,73 @@ +package com.baeldung.web.controller.students; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import com.baeldung.web.controller.students.StudentService; + +@RestController +@RequestMapping("/students") +public class StudentController { + + @Autowired + private StudentService service; + + @GetMapping("/") + public List read() { + return service.readAll(); + } + + @GetMapping("/{id}") + public ResponseEntity read(@PathVariable("id") Long id) { + Student foundStudent = service.read(id); + if (foundStudent == null) { + return ResponseEntity.notFound().build(); + } else { + return ResponseEntity.ok(foundStudent); + } + } + + @PostMapping("/") + public ResponseEntity create(@RequestBody Student student) throws URISyntaxException { + Student createdStudent = service.create(student); + + URI uri = ServletUriComponentsBuilder.fromCurrentRequest() + .path("/{id}") + .buildAndExpand(createdStudent.getId()) + .toUri(); + + return ResponseEntity.created(uri) + .body(createdStudent); + + } + + @PutMapping("/{id}") + public ResponseEntity update(@RequestBody Student student, @PathVariable Long id) { + Student updatedStudent = service.update(id, student); + if (updatedStudent == null) { + return ResponseEntity.notFound().build(); + } else { + return ResponseEntity.ok(updatedStudent); + } + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteStudent(@PathVariable Long id) { + service.delete(id); + + return ResponseEntity.noContent().build(); + } + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentService.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentService.java new file mode 100644 index 0000000000..d923f4f14f --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/students/StudentService.java @@ -0,0 +1,51 @@ +package com.baeldung.web.controller.students; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; + +@Service +public class StudentService { + + // DB repository mock + private Map repository = Arrays.asList( + new Student[]{ + new Student(1, "Alan","Turing"), + new Student(2, "Sebastian","Bach"), + new Student(3, "Pablo","Picasso"), + }).stream() + .collect(Collectors.toConcurrentMap(s -> s.getId(), Function.identity())); + + // DB id sequence mock + private AtomicLong sequence = new AtomicLong(3); + + public List readAll() { + return repository.values().stream().collect(Collectors.toList()); + } + + public Student read(Long id) { + return repository.get(id); + } + + public Student create(Student student) { + long key = sequence.incrementAndGet(); + student.setId(key); + repository.put(key, student); + return student; + } + + public Student update(Long id, Student student) { + student.setId(id); + Student oldStudent = repository.replace(id, student); + return oldStudent == null ? null : student; + } + + public void delete(Long id) { + repository.remove(id); + } +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java index 31555ef353..afcd364cce 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java +++ b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java @@ -115,7 +115,7 @@ class PaginatedResultsRetrievedDiscoverabilityListener implements ApplicationLis protected void plural(final UriComponentsBuilder uriBuilder, final Class clazz) { final String resourceName = clazz.getSimpleName() .toLowerCase() + "s"; - uriBuilder.path("/auth/" + resourceName); + uriBuilder.path("/" + resourceName); } } diff --git a/spring-boot-rest/src/main/resources/WEB-INF/api-servlet.xml b/spring-boot-rest/src/main/resources/WEB-INF/api-servlet.xml new file mode 100644 index 0000000000..78e38e1448 --- /dev/null +++ b/spring-boot-rest/src/main/resources/WEB-INF/api-servlet.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-boot-rest/src/main/resources/WEB-INF/web.xml b/spring-boot-rest/src/main/resources/WEB-INF/web.xml new file mode 100644 index 0000000000..7f36b33b38 --- /dev/null +++ b/spring-boot-rest/src/main/resources/WEB-INF/web.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-boot-rest/src/main/resources/application.properties b/spring-boot-rest/src/main/resources/application.properties index a0179f1e4b..176deb4f49 100644 --- a/spring-boot-rest/src/main/resources/application.properties +++ b/spring-boot-rest/src/main/resources/application.properties @@ -1,6 +1,5 @@ -server.port=8082 server.servlet.context-path=/spring-boot-rest ### Spring Boot default error handling configurations #server.error.whitelabel.enabled=false -#server.error.include-stacktrace=always \ No newline at end of file +#server.error.include-stacktrace=always diff --git a/spring-boot-rest/src/test/java/com/baeldung/Consts.java b/spring-boot-rest/src/test/java/com/baeldung/Consts.java index e33efd589e..4850a1b36a 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/Consts.java +++ b/spring-boot-rest/src/test/java/com/baeldung/Consts.java @@ -1,5 +1,5 @@ package com.baeldung; public interface Consts { - int APPLICATION_PORT = 8082; + int APPLICATION_PORT = 8080; } diff --git a/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java index 61eb9400cc..ecf938be50 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java @@ -1,21 +1,28 @@ package com.baeldung.common.web; import static com.baeldung.web.util.HTTPLinkHeaderUtil.extractURIByRel; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.apache.commons.lang3.RandomStringUtils.randomNumeric; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import java.io.Serializable; import java.util.List; +import org.junit.Ignore; import org.junit.Test; +import com.baeldung.persistence.model.Foo; import com.google.common.net.HttpHeaders; import io.restassured.RestAssured; +import io.restassured.http.ContentType; import io.restassured.response.Response; public abstract class AbstractBasicLiveTest extends AbstractLiveTest { @@ -97,7 +104,82 @@ public abstract class AbstractBasicLiveTest extends Abst final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next"); assertNull(uriToNextPage); } + + // etags - // count + @Test + public void givenResourceExists_whenRetrievingResource_thenEtagIsAlsoReturned() { + // Given + final String uriOfResource = createAsUri(); + + // When + final Response findOneResponse = RestAssured.given() + .header("Accept", "application/json") + .get(uriOfResource); + + // Then + assertNotNull(findOneResponse.getHeader(HttpHeaders.ETAG)); + } + + @Test + public void givenResourceWasRetrieved_whenRetrievingAgainWithEtag_thenNotModifiedReturned() { + // Given + final String uriOfResource = createAsUri(); + final Response findOneResponse = RestAssured.given() + .header("Accept", "application/json") + .get(uriOfResource); + final String etagValue = findOneResponse.getHeader(HttpHeaders.ETAG); + + // When + final Response secondFindOneResponse = RestAssured.given() + .header("Accept", "application/json") + .headers("If-None-Match", etagValue) + .get(uriOfResource); + + // Then + assertTrue(secondFindOneResponse.getStatusCode() == 304); + } + + @Test + public void givenResourceWasRetrievedThenModified_whenRetrievingAgainWithEtag_thenResourceIsReturned() { + // Given + final String uriOfResource = createAsUri(); + final Response firstFindOneResponse = RestAssured.given() + .header("Accept", "application/json") + .get(uriOfResource); + final String etagValue = firstFindOneResponse.getHeader(HttpHeaders.ETAG); + final long createdId = firstFindOneResponse.jsonPath().getLong("id"); + + Foo updatedFoo = new Foo("updated value"); + updatedFoo.setId(createdId); + Response updatedResponse = RestAssured.given().contentType(ContentType.JSON).body(updatedFoo) + .put(uriOfResource); + assertThat(updatedResponse.getStatusCode() == 200); + + // When + final Response secondFindOneResponse = RestAssured.given() + .header("Accept", "application/json") + .headers("If-None-Match", etagValue) + .get(uriOfResource); + + // Then + assertTrue(secondFindOneResponse.getStatusCode() == 200); + } + + @Test + @Ignore("Not Yet Implemented By Spring - https://jira.springsource.org/browse/SPR-10164") + public void givenResourceExists_whenRetrievedWithIfMatchIncorrectEtag_then412IsReceived() { + // Given + final String uriOfResource = createAsUri(); + + // When + final Response findOneResponse = RestAssured.given() + .header("Accept", "application/json") + .headers("If-Match", randomAlphabetic(8)) + .get(uriOfResource); + + // Then + assertTrue(findOneResponse.getStatusCode() == 412); + } } diff --git a/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java index d26632bc38..18f612d398 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java @@ -59,7 +59,7 @@ public abstract class AbstractLiveTest { // protected String getURL() { - return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/auth/foos"; + return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/foos"; } } diff --git a/spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java b/spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java index 740ee07839..1a3bae7c87 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java +++ b/spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java @@ -27,8 +27,7 @@ public class TestMarshallerFactory implements FactoryBean { case "json": return new JacksonMarshaller(); case "xml": - // If we need to implement xml marshaller we can include spring-rest-full XStreamMarshaller - throw new IllegalStateException(); + return new XStreamMarshaller(); default: throw new IllegalStateException(); } diff --git a/spring-rest-full/src/test/java/org/baeldung/test/XStreamMarshaller.java b/spring-boot-rest/src/test/java/com/baeldung/test/XStreamMarshaller.java similarity index 94% rename from spring-rest-full/src/test/java/org/baeldung/test/XStreamMarshaller.java rename to spring-boot-rest/src/test/java/com/baeldung/test/XStreamMarshaller.java index d7cf084e34..957b35218e 100644 --- a/spring-rest-full/src/test/java/org/baeldung/test/XStreamMarshaller.java +++ b/spring-boot-rest/src/test/java/com/baeldung/test/XStreamMarshaller.java @@ -1,8 +1,8 @@ -package org.baeldung.test; +package com.baeldung.test; import java.util.List; -import org.baeldung.persistence.model.Foo; +import com.baeldung.persistence.model.Foo; import org.springframework.http.MediaType; import com.google.common.base.Preconditions; diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerAppIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerAppIntegrationTest.java index bd5b5eb58e..3300b91fde 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerAppIntegrationTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerAppIntegrationTest.java @@ -27,7 +27,7 @@ public class FooControllerAppIntegrationTest { @Test public void whenFindPaginatedRequest_thenEmptyResponse() throws Exception { - this.mockMvc.perform(get("/auth/foos").param("page", "0") + this.mockMvc.perform(get("/foos").param("page", "0") .param("size", "2")) .andExpect(status().isOk()) .andExpect(content().json("[]")); diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerCustomEtagIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerCustomEtagIntegrationTest.java new file mode 100644 index 0000000000..9e7b60ed8c --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerCustomEtagIntegrationTest.java @@ -0,0 +1,116 @@ +package com.baeldung.web; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import com.baeldung.persistence.model.Foo; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.net.HttpHeaders; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc(addFilters = false) +public class FooControllerCustomEtagIntegrationTest { + + @Autowired + private MockMvc mvc; + + private String FOOS_ENDPOINT = "/foos/"; + private String CUSTOM_ETAG_ENDPOINT_SUFFIX = "/custom-etag"; + + private static String serializeFoo(Foo foo) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(foo); + } + + private static String createFooJson() throws Exception { + return serializeFoo(new Foo(randomAlphabetic(6))); + } + + private static Foo deserializeFoo(String fooJson) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(fooJson, Foo.class); + } + + @Test + public void givenResourceExists_whenRetrievingResourceUsingCustomEtagEndpoint_thenEtagIsAlsoReturned() + throws Exception { + // Given + String createdResourceUri = this.mvc.perform(post(FOOS_ENDPOINT).contentType(MediaType.APPLICATION_JSON) + .content(createFooJson())) + .andExpect(status().isCreated()) + .andReturn() + .getResponse() + .getHeader(HttpHeaders.LOCATION); + + // When + ResultActions result = this.mvc + .perform(get(createdResourceUri + CUSTOM_ETAG_ENDPOINT_SUFFIX).contentType(MediaType.APPLICATION_JSON)); + + // Then + result.andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.ETAG, "\"0\"")); + } + + @Test + public void givenResourceWasRetrieved_whenRetrievingAgainWithEtagUsingCustomEtagEndpoint_thenNotModifiedReturned() throws Exception { + // Given + String createdResourceUri = this.mvc.perform(post(FOOS_ENDPOINT).contentType(MediaType.APPLICATION_JSON) + .content(createFooJson())) + .andExpect(status().isCreated()) + .andReturn() + .getResponse() + .getHeader(HttpHeaders.LOCATION); + ResultActions findOneResponse = this.mvc + .perform(get(createdResourceUri + CUSTOM_ETAG_ENDPOINT_SUFFIX).contentType(MediaType.APPLICATION_JSON)); + String etag = findOneResponse.andReturn().getResponse().getHeader(HttpHeaders.ETAG); + + // When + ResultActions result = this.mvc + .perform(get(createdResourceUri + CUSTOM_ETAG_ENDPOINT_SUFFIX).contentType(MediaType.APPLICATION_JSON).header(HttpHeaders.IF_NONE_MATCH, etag)); + + // Then + result.andExpect(status().isNotModified()); + } + + @Test + public void givenResourceWasRetrievedThenModified_whenRetrievingAgainWithEtagUsingCustomEtagEndpoint_thenResourceIsReturned() throws Exception { + // Given + String createdResourceUri = this.mvc.perform(post(FOOS_ENDPOINT).contentType(MediaType.APPLICATION_JSON) + .content(createFooJson())) + .andExpect(status().isCreated()) + .andReturn() + .getResponse() + .getHeader(HttpHeaders.LOCATION); + ResultActions findOneResponse = this.mvc + .perform(get(createdResourceUri + CUSTOM_ETAG_ENDPOINT_SUFFIX).contentType(MediaType.APPLICATION_JSON)); + String etag = findOneResponse.andReturn().getResponse().getHeader(HttpHeaders.ETAG); + Foo createdFoo = deserializeFoo(findOneResponse.andReturn().getResponse().getContentAsString()); + createdFoo.setName("updated name"); + this.mvc + .perform(put(createdResourceUri).contentType(MediaType.APPLICATION_JSON).content(serializeFoo(createdFoo))); + + // When + ResultActions result = this.mvc + .perform(get(createdResourceUri + CUSTOM_ETAG_ENDPOINT_SUFFIX).contentType(MediaType.APPLICATION_JSON).header(HttpHeaders.IF_NONE_MATCH, etag)); + + // Then + result.andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.ETAG, "\"1\"")); + } + +} diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerWebLayerIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerWebLayerIntegrationTest.java index 7e41cf6393..bd98523b0a 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerWebLayerIntegrationTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooControllerWebLayerIntegrationTest.java @@ -51,7 +51,7 @@ public class FooControllerWebLayerIntegrationTest { doNothing().when(publisher) .publishEvent(any(PaginatedResultsRetrievedEvent.class)); - this.mockMvc.perform(get("/auth/foos").param("page", "0") + this.mockMvc.perform(get("/foos").param("page", "0") .param("size", "2")) .andExpect(status().isOk()) .andExpect(jsonPath("$",Matchers.hasSize(1))); diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java index 359a62a4d8..6a365f3bd5 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java @@ -74,7 +74,7 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest { } protected String getPageableURL() { - return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/auth/foos/pageable"; + return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/foos/pageable"; } } diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java index b7cceb9008..bc45d8352a 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java @@ -8,8 +8,8 @@ import org.junit.runners.Suite; @Suite.SuiteClasses({ // @formatter:off FooDiscoverabilityLiveTest.class, - FooLiveTest.class - ,FooPageableLiveTest.class + FooLiveTest.class, + FooPageableLiveTest.class }) // public class LiveTestSuiteLiveTest { diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/StudentControllerIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/StudentControllerIntegrationTest.java new file mode 100644 index 0000000000..54ac69ebeb --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/web/StudentControllerIntegrationTest.java @@ -0,0 +1,76 @@ +package com.baeldung.web; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.server.MediaTypeNotSupportedStatusException; + +import com.baeldung.web.controller.students.Student; +import com.fasterxml.jackson.databind.ObjectMapper; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class StudentControllerIntegrationTest { + + private static final String STUDENTS_PATH = "/students/"; + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenReadAll_thenStatusIsOk() throws Exception { + this.mockMvc.perform(get(STUDENTS_PATH)) + .andExpect(status().isOk()); + } + + @Test + public void whenReadOne_thenStatusIsOk() throws Exception { + this.mockMvc.perform(get(STUDENTS_PATH + 1)) + .andExpect(status().isOk()); + } + + @Test + public void whenCreate_thenStatusIsCreated() throws Exception { + Student student = new Student(10, "Albert", "Einstein"); + this.mockMvc.perform(post(STUDENTS_PATH).content(asJsonString(student)) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isCreated()); + } + + @Test + public void whenUpdate_thenStatusIsOk() throws Exception { + Student student = new Student(1, "Nikola", "Tesla"); + this.mockMvc.perform(put(STUDENTS_PATH + 1) + .content(asJsonString(student)) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isOk()); + } + + @Test + public void whenDelete_thenStatusIsNoContent() throws Exception { + this.mockMvc.perform(delete(STUDENTS_PATH + 3)) + .andExpect(status().isNoContent()); + } + + private String asJsonString(final Object obj) { + try { + return new ObjectMapper().writeValueAsString(obj); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/spring-boot-rest/src/test/resources/foo_API_test.postman_collection.json b/spring-boot-rest/src/test/resources/foo_API_test.postman_collection.json new file mode 100644 index 0000000000..dc4acafab3 --- /dev/null +++ b/spring-boot-rest/src/test/resources/foo_API_test.postman_collection.json @@ -0,0 +1,180 @@ +{ + "info": { + "_postman_id": "9989b5be-13ba-4d22-8e43-d05dbf628e58", + "name": "foo API test", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "add a foo", + "event": [ + { + "listen": "test", + "script": { + "id": "a01534dc-6fc7-4c54-ba1d-6bcf311e5836", + "exec": [ + "pm.test(\"success status\", () => pm.response.to.be.success );", + "", + "pm.test(\"name is correct\", () => ", + " pm.expect(pm.response.json().name).to.equal(\"Transformers\"));", + "", + "pm.test(\"id was assigned\", () => ", + " pm.expect(pm.response.json().id).to.be.not.null );", + "", + "pm.variables.set(\"id\", pm.response.json().id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Transformers\"\n}" + }, + "url": { + "raw": "http://localhost:8080/spring-boot-rest/foos", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "spring-boot-rest", + "foos" + ] + } + }, + "response": [] + }, + { + "name": "get a foo", + "event": [ + { + "listen": "test", + "script": { + "id": "03de440c-b483-4ab8-a11a-d0c99b349963", + "exec": [ + "pm.test(\"success status\", () => pm.response.to.be.success );", + "", + "pm.test(\"name is correct\", () => ", + " pm.expect(pm.response.json().name).to.equal(\"Transformers\"));", + "", + "pm.test(\"id is correct\", () => ", + " pm.expect(pm.response.json().id).to.equal(pm.variables.get(\"id\")) );" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://localhost:8080/spring-boot-rest/foos/{{id}}", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "spring-boot-rest", + "foos", + "{{id}}" + ] + } + }, + "response": [] + }, + { + "name": "delete a foo", + "event": [ + { + "listen": "test", + "script": { + "id": "74c1bb0f-c06c-48b1-a545-459233541b14", + "exec": [ + "pm.test(\"success status\", () => pm.response.to.be.success );" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://localhost:8080/spring-boot-rest/foos/{{id}}", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "spring-boot-rest", + "foos", + "{{id}}" + ] + } + }, + "response": [] + }, + { + "name": "verify delete", + "event": [ + { + "listen": "test", + "script": { + "id": "03de440c-b483-4ab8-a11a-d0c99b349963", + "exec": [ + "pm.test(\"status is 500\", () => pm.response.to.have.status(500) );", + "", + "pm.test(\"no value present\", () => ", + " pm.expect(pm.response.json().cause).to.equal(\"No value present\"));" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://localhost:8080/spring-boot-rest/foos/{{id}}", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "spring-boot-rest", + "foos", + "{{id}}" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/spring-boot-security/pom.xml b/spring-boot-security/pom.xml index aaa0fbf4c7..79a77775de 100644 --- a/spring-boot-security/pom.xml +++ b/spring-boot-security/pom.xml @@ -8,10 +8,10 @@ jar - parent-boot-1 + parent-boot-2 com.baeldung 0.0.1-SNAPSHOT - ../parent-boot-1 + ../parent-boot-2 @@ -22,6 +22,12 @@ org.springframework.security.oauth spring-security-oauth2 + 2.3.3.RELEASE + + + org.springframework.security.oauth.boot + spring-security-oauth2-autoconfigure + 2.1.2.RELEASE org.springframework.boot @@ -55,6 +61,12 @@ spring-security-test test + + org.springframework.boot + spring-boot-autoconfigure + 2.1.1.RELEASE + + diff --git a/spring-boot-security/src/main/java/com/baeldung/integrationtesting/WebSecurityConfigurer.java b/spring-boot-security/src/main/java/com/baeldung/integrationtesting/WebSecurityConfigurer.java index 32a48ce612..16ce8e6fc6 100644 --- a/spring-boot-security/src/main/java/com/baeldung/integrationtesting/WebSecurityConfigurer.java +++ b/spring-boot-security/src/main/java/com/baeldung/integrationtesting/WebSecurityConfigurer.java @@ -12,7 +12,7 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("spring") - .password("secret") + .password("{noop}secret") .roles("USER"); } diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/SpringBootSecurityApplication.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/SpringBootSecurityApplication.java index 2ecad4ae35..7007c15596 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/SpringBootSecurityApplication.java +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/SpringBootSecurityApplication.java @@ -2,14 +2,13 @@ package com.baeldung.springbootsecurity.basic_auth; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; @SpringBootApplication(exclude = { SecurityAutoConfiguration.class // ,ManagementWebSecurityAutoConfiguration.class }, scanBasePackages = "com.baeldung.springbootsecurity.basic_auth") public class SpringBootSecurityApplication { - public static void main(String[] args) { SpringApplication.run(SpringBootSecurityApplication.class, args); } diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/config/BasicAuthConfiguration.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/config/BasicAuthConfiguration.java index 993c573fb0..592ef5354d 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/config/BasicAuthConfiguration.java +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/basic_auth/config/BasicAuthConfiguration.java @@ -5,6 +5,8 @@ import org.springframework.security.config.annotation.authentication.builders.Au import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity @@ -12,14 +14,15 @@ public class BasicAuthConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth + PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); + auth .inMemoryAuthentication() .withUser("user") - .password("password") + .password(encoder.encode("password")) .roles("USER") .and() .withUser("admin") - .password("admin") + .password(encoder.encode("admin")) .roles("USER", "ADMIN"); } diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthorizationServerConfig.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthorizationServerConfig.java index b403feb5c1..4686100638 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthorizationServerConfig.java +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/AuthorizationServerConfig.java @@ -25,13 +25,13 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap clients .inMemory() .withClient("baeldung") - .secret("baeldung") + .secret("{noop}baeldung") .authorizedGrantTypes("client_credentials", "password", "authorization_code") .scopes("openid", "read") .autoApprove(true) .and() .withClient("baeldung-admin") - .secret("baeldung") + .secret("{noop}baeldung") .authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token") .scopes("read", "write") .autoApprove(true); diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/WebSecurityConfiguration.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/WebSecurityConfiguration.java new file mode 100644 index 0000000000..f2540c01b8 --- /dev/null +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2server/config/WebSecurityConfiguration.java @@ -0,0 +1,15 @@ +package com.baeldung.springbootsecurity.oauth2server.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Bean + public AuthenticationManager customAuthenticationManager() throws Exception { + return authenticationManager(); + } +} diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2sso/SpringBootOAuth2SsoApplication.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2sso/SpringBootOAuth2SsoApplication.java index b1cd580f08..342c246e66 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2sso/SpringBootOAuth2SsoApplication.java +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/oauth2sso/SpringBootOAuth2SsoApplication.java @@ -1,6 +1,7 @@ package com.baeldung.springbootsecurity.oauth2sso; import org.springframework.boot.autoconfigure.SpringBootApplication; + import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; import org.springframework.boot.builder.SpringApplicationBuilder; diff --git a/spring-boot-security/src/main/java/com/baeldung/springsecuritytaglibs/config/SpringBootSecurityTagLibsConfig.java b/spring-boot-security/src/main/java/com/baeldung/springsecuritytaglibs/config/SpringBootSecurityTagLibsConfig.java index 665dd0bce9..59ae2885ad 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springsecuritytaglibs/config/SpringBootSecurityTagLibsConfig.java +++ b/spring-boot-security/src/main/java/com/baeldung/springsecuritytaglibs/config/SpringBootSecurityTagLibsConfig.java @@ -14,7 +14,7 @@ public class SpringBootSecurityTagLibsConfig extends WebSecurityConfigurerAdapte protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("testUser") - .password("password") + .password("{noop}password") .roles("ADMIN"); } diff --git a/spring-boot-security/src/main/resources/application-authz.properties b/spring-boot-security/src/main/resources/application-authz.properties index d29b0cdd3c..0c53999bb3 100644 --- a/spring-boot-security/src/main/resources/application-authz.properties +++ b/spring-boot-security/src/main/resources/application-authz.properties @@ -1,3 +1,3 @@ -security.user.password=password +spring.security.user.password=password security.oauth2.client.client-id=client security.oauth2.client.client-secret=secret diff --git a/spring-boot-security/src/main/resources/application-taglibs.properties b/spring-boot-security/src/main/resources/application-taglibs.properties index 218868405f..3e482ed92a 100644 --- a/spring-boot-security/src/main/resources/application-taglibs.properties +++ b/spring-boot-security/src/main/resources/application-taglibs.properties @@ -1,3 +1,3 @@ #jsp config -spring.mvc.view.prefix: /WEB-INF/views/ -spring.mvc.view.suffix: .jsp +spring.mvc.view.prefix= /WEB-INF/views/ +spring.mvc.view.suffix= .jsp diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java index 32c3fbdef4..dd9c511361 100644 --- a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java +++ b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java @@ -1,10 +1,10 @@ package com.baeldung.springbootsecurity.basic_auth; -import com.baeldung.springbootsecurity.basic_auth.SpringBootSecurityApplication; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.boot.context.embedded.LocalServerPort; +import org.springframework.boot.web.server.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.HttpStatus; @@ -18,7 +18,6 @@ import java.net.URL; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT, classes = SpringBootSecurityApplication.class) public class BasicAuthConfigurationIntegrationTest { @@ -50,8 +49,6 @@ public class BasicAuthConfigurationIntegrationTest { ResponseEntity response = restTemplate.getForEntity(base.toString(), String.class); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); - assertTrue(response - .getBody() - .contains("Unauthorized")); + Assert.assertNull(response.getBody()); } } diff --git a/spring-boot/README.MD b/spring-boot/README.MD index 28123687fd..7d270c9c25 100644 --- a/spring-boot/README.MD +++ b/spring-boot/README.MD @@ -28,7 +28,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Spring Boot Exit Codes](http://www.baeldung.com/spring-boot-exit-codes) - [Guide to the Favicon in Spring Boot](http://www.baeldung.com/spring-boot-favicon) - [Spring Shutdown Callbacks](http://www.baeldung.com/spring-shutdown-callbacks) -- [Spring Boot Integration Testing with Embedded MongoDB](http://www.baeldung.com/spring-boot-embedded-mongodb) - [Container Configuration in Spring Boot 2](http://www.baeldung.com/embeddedservletcontainercustomizer-configurableembeddedservletcontainer-spring-boot) - [Introduction to Chaos Monkey](https://www.baeldung.com/spring-boot-chaos-monkey) - [Spring Component Scanning](https://www.baeldung.com/spring-component-scanning) @@ -36,3 +35,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Display Auto-Configuration Report in Spring Boot](https://www.baeldung.com/spring-boot-auto-configuration-report) - [Injecting Git Information Into Spring](https://www.baeldung.com/spring-git-information) - [Validation in Spring Boot](https://www.baeldung.com/spring-boot-bean-validation) +- [Entity To DTO Conversion for a Spring REST API](https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application) +- [Guide to Creating and Running a Jar File in Java](https://www.baeldung.com/java-create-jar) diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml index 2e463e0189..ed2d8259df 100644 --- a/spring-boot/pom.xml +++ b/spring-boot/pom.xml @@ -15,16 +15,7 @@ - - - org.springframework.boot - spring-boot-starter-data-mongodb - - - de.flapdoodle.embed - de.flapdoodle.embed.mongo - test - + org.junit.jupiter diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java new file mode 100644 index 0000000000..01be08d6ae --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java @@ -0,0 +1,59 @@ +package com.baeldung.environmentpostprocessor; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.baeldung.environmentpostprocessor.service.PriceCalculationService; + +@SpringBootApplication +public class PriceCalculationApplication implements CommandLineRunner { + + @Autowired + PriceCalculationService priceCalculationService; + + private static final Logger logger = LoggerFactory.getLogger(PriceCalculationApplication.class); + + public static void main(String[] args) { + SpringApplication.run(PriceCalculationApplication.class, args); + } + + @Override + public void run(String... args) throws Exception { + + List params = Arrays.stream(args) + .collect(Collectors.toList()); + if (verifyArguments(params)) { + double singlePrice = Double.valueOf(params.get(0)); + int quantity = Integer.valueOf(params.get(1)); + priceCalculationService.productTotalPrice(singlePrice, quantity); + } else { + logger.error("Invalid arguments " + params.toString()); + } + + } + + private boolean verifyArguments(List args) { + boolean successful = true; + if (args.size() != 2) { + successful = false; + return successful; + } + try { + double singlePrice = Double.valueOf(args.get(0)); + int quantity = Integer.valueOf(args.get(1)); + } catch (NumberFormatException e) { + successful = false; + } + return successful; + + } + +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java new file mode 100644 index 0000000000..ca6d6cc28f --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java @@ -0,0 +1,81 @@ +package com.baeldung.environmentpostprocessor; + +import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +@Order(Ordered.LOWEST_PRECEDENCE) +public class PriceCalculationEnvironmentPostProcessor implements EnvironmentPostProcessor { + + private static final Logger logger = LoggerFactory.getLogger(PriceCalculationEnvironmentPostProcessor.class); + + private static final String PREFIX = "com.baeldung.environmentpostprocessor."; + private static final String CALCUATION_MODE = "calculation_mode"; + private static final String GROSS_CALCULATION_TAX_RATE = "gross_calculation_tax_rate"; + private static final String CALCUATION_MODE_DEFAULT_VALUE = "NET"; + private static final double GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE = 0; + + List names = Arrays.asList(CALCUATION_MODE, GROSS_CALCULATION_TAX_RATE); + + private static Map defaults = new LinkedHashMap<>(); + static { + defaults.put(CALCUATION_MODE, CALCUATION_MODE_DEFAULT_VALUE); + defaults.put(GROSS_CALCULATION_TAX_RATE, GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + } + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + + PropertySource system = environment.getPropertySources() + .get(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); + + Map prefixed = new LinkedHashMap<>(); + + if (!hasOurPriceProperties(system)) { + // Baeldung-internal code so this doesn't break other examples + logger.warn("System environment variables [calculation_mode,gross_calculation_tax_rate] not detected, fallback to default value [calcuation_mode={},gross_calcuation_tax_rate={}]", CALCUATION_MODE_DEFAULT_VALUE, + GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + prefixed = names.stream() + .collect(Collectors.toMap(this::rename, this::getDefaultValue)); + environment.getPropertySources() + .addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new MapPropertySource("prefixer", prefixed)); + return; + } + + prefixed = names.stream() + .collect(Collectors.toMap(this::rename, system::getProperty)); + environment.getPropertySources() + .addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new MapPropertySource("prefixer", prefixed)); + + } + + private Object getDefaultValue(String key) { + return defaults.get(key); + } + + private String rename(String key) { + return PREFIX + key.replaceAll("\\_", "."); + } + + private boolean hasOurPriceProperties(PropertySource system) { + if (system.containsProperty(CALCUATION_MODE) && system.containsProperty(GROSS_CALCULATION_TAX_RATE)) { + return true; + } else + return false; + } + +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java new file mode 100644 index 0000000000..c884f043a0 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java @@ -0,0 +1,32 @@ +package com.baeldung.environmentpostprocessor.autoconfig; + +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; + +import com.baeldung.environmentpostprocessor.calculator.GrossPriceCalculator; +import com.baeldung.environmentpostprocessor.calculator.NetPriceCalculator; +import com.baeldung.environmentpostprocessor.calculator.PriceCalculator; + +@Configuration +@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) +public class PriceCalculationAutoConfig { + + @Bean + @ConditionalOnProperty(name = "com.baeldung.environmentpostprocessor.calculation.mode", havingValue = "NET") + @ConditionalOnMissingBean + public PriceCalculator getNetPriceCalculator() { + return new NetPriceCalculator(); + } + + @Bean + @ConditionalOnProperty(name = "com.baeldung.environmentpostprocessor.calculation.mode", havingValue = "GROSS") + @ConditionalOnMissingBean + public PriceCalculator getGrossPriceCalculator() { + return new GrossPriceCalculator(); + } + +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java new file mode 100644 index 0000000000..f8f797bd66 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java @@ -0,0 +1,23 @@ +package com.baeldung.environmentpostprocessor.calculator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; + +public class GrossPriceCalculator implements PriceCalculator { + + private static final Logger logger = LoggerFactory.getLogger(GrossPriceCalculator.class); + + @Value("${com.baeldung.environmentpostprocessor.gross.calculation.tax.rate}") + double taxRate; + + @Override + public double calculate(double singlePrice, int quantity) { + logger.info("Gross based price calculation with input parameters [singlePrice = {},quantity= {} ], {} percent tax applied.", singlePrice, quantity, taxRate * 100); + double netPrice = singlePrice * quantity; + double result = Math.round(netPrice * (1 + taxRate)); + logger.info("Calcuation result is {}", result); + return result; + } + +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java new file mode 100644 index 0000000000..263dff6247 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java @@ -0,0 +1,17 @@ +package com.baeldung.environmentpostprocessor.calculator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetPriceCalculator implements PriceCalculator { + + private static final Logger logger = LoggerFactory.getLogger(GrossPriceCalculator.class); + + @Override + public double calculate(double singlePrice, int quantity) { + logger.info("Net based price calculation with input parameters [singlePrice = {},quantity= {} ], NO tax applied.", singlePrice, quantity); + double result = Math.round(singlePrice * quantity); + logger.info("Calcuation result is {}", result); + return result; + } +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java new file mode 100644 index 0000000000..9d7bef93a4 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java @@ -0,0 +1,5 @@ +package com.baeldung.environmentpostprocessor.calculator; + +public interface PriceCalculator { + public double calculate(double singlePrice, int quantity); +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java new file mode 100644 index 0000000000..0e4eb39506 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java @@ -0,0 +1,17 @@ +package com.baeldung.environmentpostprocessor.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baeldung.environmentpostprocessor.calculator.PriceCalculator; + +@Service +public class PriceCalculationService { + + @Autowired + PriceCalculator priceCalculator; + + public double productTotalPrice(double singlePrice, int quantity) { + return priceCalculator.calculate(singlePrice, quantity); + } +} diff --git a/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot/src/main/resources/META-INF/spring.factories index e3d3aa4c8e..d8a01bbf82 100644 --- a/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot/src/main/resources/META-INF/spring.factories @@ -1 +1,7 @@ -org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer \ No newline at end of file +org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.baeldung.environmentpostprocessor.autoconfig.PriceCalculationAutoConfig + +org.springframework.boot.env.EnvironmentPostProcessor=\ +com.baeldung.environmentpostprocessor.PriceCalculationEnvironmentPostProcessor + diff --git a/spring-boot/src/main/resources/application.properties b/spring-boot/src/main/resources/application.properties index 00c251d823..918fe5ea67 100644 --- a/spring-boot/src/main/resources/application.properties +++ b/spring-boot/src/main/resources/application.properties @@ -72,6 +72,3 @@ chaos.monkey.watcher.service=true chaos.monkey.watcher.repository=false #Component watcher active chaos.monkey.watcher.component=false - -spring.jackson.date-format=yyyy-MM-dd HH:mm:ss -spring.jackson.time-zone=Europe/Zagreb diff --git a/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java b/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java new file mode 100644 index 0000000000..54af217346 --- /dev/null +++ b/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java @@ -0,0 +1,26 @@ +package com.baeldung.environmentpostprocessor; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.environmentpostprocessor.service.PriceCalculationService; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PriceCalculationApplication.class) +public class PriceCalculationEnvironmentPostProcessorLiveTest { + + @Autowired + PriceCalculationService pcService; + + @Test + public void whenSetNetEnvironmentVariablebyDefault_thenNoTaxApplied() { + double total = pcService.productTotalPrice(100, 4); + assertEquals(400.0, total, 0); + } + +} diff --git a/spring-boot/src/test/java/com/baeldung/validation/tests/UserControllerIntegrationTest.java b/spring-boot/src/test/java/com/baeldung/validation/application/UserControllerIntegrationTest.java similarity index 96% rename from spring-boot/src/test/java/com/baeldung/validation/tests/UserControllerIntegrationTest.java rename to spring-boot/src/test/java/com/baeldung/validation/application/UserControllerIntegrationTest.java index 265c4ec22c..77a230ee6c 100644 --- a/spring-boot/src/test/java/com/baeldung/validation/tests/UserControllerIntegrationTest.java +++ b/spring-boot/src/test/java/com/baeldung/validation/application/UserControllerIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.validation.tests; +package com.baeldung.validation.application; import com.baeldung.validation.application.controllers.UserController; import com.baeldung.validation.application.repositories.UserRepository; diff --git a/spring-cloud-data-flow/apache-spark-job/pom.xml b/spring-cloud-data-flow/apache-spark-job/pom.xml new file mode 100644 index 0000000000..390b7ebdc6 --- /dev/null +++ b/spring-cloud-data-flow/apache-spark-job/pom.xml @@ -0,0 +1,36 @@ + + + + spring-cloud-data-flow + com.baeldung + 0.0.1-SNAPSHOT + + 4.0.0 + + apache-spark-job + + + org.springframework.cloud + spring-cloud-task-core + 2.0.0.RELEASE + + + org.apache.spark + spark-core_2.10 + 1.6.2 + + + log4j + log4j + + + org.slf4j + slf4j-log4j12 + + + + + + \ No newline at end of file diff --git a/spring-cloud-data-flow/apache-spark-job/src/main/java/com/baeldung/spring/cloud/PiApproximation.java b/spring-cloud-data-flow/apache-spark-job/src/main/java/com/baeldung/spring/cloud/PiApproximation.java new file mode 100644 index 0000000000..dfead21728 --- /dev/null +++ b/spring-cloud-data-flow/apache-spark-job/src/main/java/com/baeldung/spring/cloud/PiApproximation.java @@ -0,0 +1,39 @@ +package com.baeldung.spring.cloud; + +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaRDD; +import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.api.java.function.Function; +import org.apache.spark.api.java.function.Function2; +import org.apache.spark.rdd.RDD; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class PiApproximation { + public static void main(String[] args) { + SparkConf conf = new SparkConf().setAppName("BaeldungPIApproximation"); + JavaSparkContext context = new JavaSparkContext(conf); + int slices = args.length >= 1 ? Integer.valueOf(args[0]) : 2; + int n = (100000L * slices) > Integer.MAX_VALUE ? Integer.MAX_VALUE : 100000 * slices; + + List xs = IntStream.rangeClosed(0, n) + .mapToObj(element -> Integer.valueOf(element)) + .collect(Collectors.toList()); + + JavaRDD dataSet = context.parallelize(xs, slices); + + JavaRDD pointsInsideTheCircle = dataSet.map(integer -> { + double x = Math.random() * 2 - 1; + double y = Math.random() * 2 - 1; + return (x*x + y*y ) < 1 ? 1: 0; + }); + + int count = pointsInsideTheCircle.reduce((integer, integer2) -> integer + integer2); + + System.out.println("The pi was estimated as:" + count / n); + + context.stop(); + } +} diff --git a/spring-cloud-data-flow/etl/customer-mongodb-sink/pom.xml b/spring-cloud-data-flow/etl/customer-mongodb-sink/pom.xml index c8b609fd70..456caf480c 100644 --- a/spring-cloud-data-flow/etl/customer-mongodb-sink/pom.xml +++ b/spring-cloud-data-flow/etl/customer-mongodb-sink/pom.xml @@ -60,22 +60,11 @@ - - - spring-milestones - Spring Milestones - http://repo.spring.io/milestone - - false - - - - UTF-8 UTF-8 1.8 - Greenwich.M3 + Greenwich.RELEASE diff --git a/spring-cloud-data-flow/etl/customer-transform/pom.xml b/spring-cloud-data-flow/etl/customer-transform/pom.xml index 5b2eb05fc8..b7376f7bd4 100644 --- a/spring-cloud-data-flow/etl/customer-transform/pom.xml +++ b/spring-cloud-data-flow/etl/customer-transform/pom.xml @@ -52,22 +52,11 @@ - - - spring-milestones - Spring Milestones - http://repo.spring.io/milestone - - false - - - - UTF-8 UTF-8 1.8 - Greenwich.M3 + Greenwich.RELEASE diff --git a/spring-cloud-data-flow/pom.xml b/spring-cloud-data-flow/pom.xml index daf8ebd2c8..36a780c28d 100644 --- a/spring-cloud-data-flow/pom.xml +++ b/spring-cloud-data-flow/pom.xml @@ -20,6 +20,7 @@ log-sink batch-job etl + apache-spark-job diff --git a/spring-cloud/README.md b/spring-cloud/README.md index fede3cc12d..5139cdca20 100644 --- a/spring-cloud/README.md +++ b/spring-cloud/README.md @@ -17,4 +17,5 @@ - [Dockerizing a Spring Boot Application](http://www.baeldung.com/dockerizing-spring-boot-application) - [Instance Profile Credentials using Spring Cloud](http://www.baeldung.com/spring-cloud-instance-profiles) - [Running Spring Boot Applications With Minikube](http://www.baeldung.com/spring-boot-minikube) +- [Introduction to Spring Cloud OpenFeign](https://www.baeldung.com/spring-cloud-openfeign) diff --git a/spring-cloud/pom.xml b/spring-cloud/pom.xml index baf86a4386..bf70e0284c 100644 --- a/spring-cloud/pom.xml +++ b/spring-cloud/pom.xml @@ -32,6 +32,7 @@ spring-cloud-zuul-eureka-integration spring-cloud-contract spring-cloud-kubernetes + spring-cloud-kubernetes-2 spring-cloud-archaius spring-cloud-functions spring-cloud-vault diff --git a/spring-cloud/spring-cloud-bootstrap/discovery/pom.xml b/spring-cloud/spring-cloud-bootstrap/discovery/pom.xml index 735d3745d7..09bea4864a 100644 --- a/spring-cloud/spring-cloud-bootstrap/discovery/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/discovery/pom.xml @@ -50,6 +50,6 @@ - Brixton.SR7 + Edgware.SR5 \ No newline at end of file diff --git a/spring-cloud/spring-cloud-functions/pom.xml b/spring-cloud/spring-cloud-functions/pom.xml index 9396ad0a55..4d03e07e89 100644 --- a/spring-cloud/spring-cloud-functions/pom.xml +++ b/spring-cloud/spring-cloud-functions/pom.xml @@ -11,19 +11,12 @@ jar - org.springframework.boot - spring-boot-starter-parent - 2.0.4.RELEASE - + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../../parent-boot-2 - - UTF-8 - UTF-8 - 1.8 - 1.0.1.RELEASE - 2.0.2 - @@ -89,4 +82,13 @@ + + UTF-8 + UTF-8 + 1.8 + 1.0.1.RELEASE + 2.0.2 + 2.0.4.RELEASE + + diff --git a/spring-cloud/spring-cloud-functions/src/test/java/com/baeldung/spring/cloudfunction/aws/CloudFunctionApplicationTests.java b/spring-cloud/spring-cloud-functions/src/test/java/com/baeldung/spring/cloudfunction/aws/CloudFunctionApplicationUnitTest.java similarity index 96% rename from spring-cloud/spring-cloud-functions/src/test/java/com/baeldung/spring/cloudfunction/aws/CloudFunctionApplicationTests.java rename to spring-cloud/spring-cloud-functions/src/test/java/com/baeldung/spring/cloudfunction/aws/CloudFunctionApplicationUnitTest.java index 6039debe3f..e7b3fc8498 100644 --- a/spring-cloud/spring-cloud-functions/src/test/java/com/baeldung/spring/cloudfunction/aws/CloudFunctionApplicationTests.java +++ b/spring-cloud/spring-cloud-functions/src/test/java/com/baeldung/spring/cloudfunction/aws/CloudFunctionApplicationUnitTest.java @@ -12,7 +12,7 @@ import static org.assertj.core.api.Java6Assertions.assertThat; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class CloudFunctionApplicationTests { +public class CloudFunctionApplicationUnitTest { @LocalServerPort private int port; diff --git a/spring-cloud/spring-cloud-gateway/README.MD b/spring-cloud/spring-cloud-gateway/README.MD index 48fbf41b8e..d945ae949c 100644 --- a/spring-cloud/spring-cloud-gateway/README.MD +++ b/spring-cloud/spring-cloud-gateway/README.MD @@ -1,2 +1,2 @@ ### Relevant Articles: -- [Explore the new Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway) +- [Exploring the new Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway) diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/.gitignore b/spring-cloud/spring-cloud-kubernetes-2/client-service/.gitignore new file mode 100644 index 0000000000..2af7cefb0a --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/.gitignore @@ -0,0 +1,24 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/Dockerfile b/spring-cloud/spring-cloud-kubernetes-2/client-service/Dockerfile new file mode 100644 index 0000000000..bd8cf2918f --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:8-jdk-alpine +VOLUME /tmp +COPY target/client-service-1.0-SNAPSHOT.jar app.jar +ENV JAVA_OPTS="" +ENTRYPOINT exec java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999 -jar /app.jar \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/client-config.yaml b/spring-cloud/spring-cloud-kubernetes-2/client-service/client-config.yaml new file mode 100644 index 0000000000..329c01582e --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/client-config.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: client-service +data: + application.properties: |- + bean.message=Testing reload ! Message from backend is: %s
Services : %s + diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/client-service-deployment.yaml b/spring-cloud/spring-cloud-kubernetes-2/client-service/client-service-deployment.yaml new file mode 100644 index 0000000000..8867aecc33 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/client-service-deployment.yaml @@ -0,0 +1,33 @@ +kind: Service +apiVersion: v1 +metadata: + name: client-service +spec: + selector: + app: client-service + ports: + - protocol: TCP + port: 8080 + nodePort: 30083 + type: NodePort +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: client-service +spec: + selector: + matchLabels: + app: client-service + replicas: 1 + template: + metadata: + labels: + app: client-service + spec: + containers: + - name: client-service + image: client-service:latest + imagePullPolicy: Never + ports: + - containerPort: 8080 \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/pom.xml b/spring-cloud/spring-cloud-kubernetes-2/client-service/pom.xml new file mode 100644 index 0000000000..908a545242 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/pom.xml @@ -0,0 +1,96 @@ + + + 4.0.0 + client-service + client-service + 1.0-SNAPSHOT + + + com.baeldung.spring.cloud + spring-cloud-kubernetes-2 + 1.0-SNAPSHOT + + + + 1.8 + Finchley.SR2 + 1.0.0.RELEASE + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + + + org.springframework.cloud + spring-cloud-kubernetes-dependencies + ${spring.cloud.k8s.version} + pom + import + + + + + + + org.springframework.cloud + spring-cloud-kubernetes-discovery + + + org.springframework.cloud + spring-cloud-starter-kubernetes-config + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + org.springframework.cloud + spring-cloud-starter-kubernetes-ribbon + + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.spring.cloud.kubernetes.client.Application + JAR + + + + + repackage + + + + + + + + diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/Application.java b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/Application.java new file mode 100644 index 0000000000..24e562c79b --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/Application.java @@ -0,0 +1,27 @@ +package com.baeldung.spring.cloud.kubernetes.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.netflix.ribbon.RibbonClient; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableCircuitBreaker +@RibbonClient(name = "travel-agency-service", configuration = RibbonConfiguration.class) +public class Application { + + @LoadBalanced + @Bean + RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientConfig.java b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientConfig.java new file mode 100644 index 0000000000..4bc8fbe327 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientConfig.java @@ -0,0 +1,19 @@ +package com.baeldung.spring.cloud.kubernetes.client; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "bean") +public class ClientConfig { + + private String message = "Message from backend is: %s
Services : %s"; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientController.java b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientController.java new file mode 100755 index 0000000000..952bccc3a8 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/ClientController.java @@ -0,0 +1,54 @@ +package com.baeldung.spring.cloud.kubernetes.client; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.http.ResponseEntity; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import java.net.UnknownHostException; +import java.util.List; + +@RestController +public class ClientController { + + @Autowired + private DiscoveryClient discoveryClient; + + @Autowired + private ClientConfig config; + + @Autowired + private TravelAgencyService travelAgencyService; + + @RequestMapping("/deals") + public String getDeals() { + return travelAgencyService.getDeals(); + } + + @GetMapping + public String load() { + + RestTemplate restTemplate = new RestTemplate(); + String resourceUrl = "http://travel-agency-service:8080"; + ResponseEntity response = restTemplate.getForEntity(resourceUrl, String.class); + + String serviceList = ""; + if (discoveryClient != null) { + List services = this.discoveryClient.getServices(); + + for (String service : services) { + + List instances = this.discoveryClient.getInstances(service); + + serviceList += ("[" + service + " : " + ((!CollectionUtils.isEmpty(instances)) ? instances.size() : 0) + " instances ]"); + } + } + + return String.format(config.getMessage(), response.getBody(), serviceList); + } +} diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/RibbonConfiguration.java b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/RibbonConfiguration.java new file mode 100755 index 0000000000..2b81c78be4 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/RibbonConfiguration.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 to the original authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.baeldung.spring.cloud.kubernetes.client; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.AvailabilityFilteringRule; +import com.netflix.loadbalancer.IPing; +import com.netflix.loadbalancer.IRule; +import com.netflix.loadbalancer.PingUrl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; + +public class RibbonConfiguration { + + @Autowired + IClientConfig ribbonClientConfig; + + /** + * PingUrl will ping a URL to check the status of each server. + * Say Hello has, as you’ll recall, a method mapped to the /path; that means that Ribbon will get an HTTP 200 response when it pings a running Backend Server + * + * @param config Client configuration + * @return The URL to be used for the Ping + */ + @Bean + public IPing ribbonPing(IClientConfig config) { + return new PingUrl(); + } + + /** + * AvailabilityFilteringRule will use Ribbon’s built-in circuit breaker functionality to filter out any servers in an “open-circuit” state: + * if a ping fails to connect to a given server, or if it gets a read failure for the server, Ribbon will consider that server “dead” until it begins to respond normally. + * + * @param config Client configuration + * @return The Load Balancer rule + */ + @Bean + public IRule ribbonRule(IClientConfig config) { + return new AvailabilityFilteringRule(); + } +} diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/TravelAgencyService.java b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/TravelAgencyService.java new file mode 100644 index 0000000000..5ce6d7b8a1 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/java/com/baeldung/spring/cloud/kubernetes/client/TravelAgencyService.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.cloud.kubernetes.client; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +public class TravelAgencyService { + + private final RestTemplate restTemplate; + + public TravelAgencyService(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + @HystrixCommand(fallbackMethod = "getFallbackName", commandProperties = { + @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000") }) + public String getDeals() { + return this.restTemplate.getForObject("http://travel-agency-service:8080/deals", String.class); + } + + private String getFallbackName() { + return "Fallback"; + } +} diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/resources/application.yaml b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/resources/application.yaml new file mode 100644 index 0000000000..f966fdd7a5 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/resources/application.yaml @@ -0,0 +1,16 @@ +spring: + application.name: client-service + cloud.kubernetes.reload.enabled: true +server.port: 8080 +management: + endpoint: + restart: + enabled: true + health: + enabled: true + info: + enabled: true +ribbon: + http: + client: + enabled: true \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/resources/logback.xml b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/client-service/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/test/java/org/baeldung/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..a6a978a354 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/client-service/src/test/java/org/baeldung/SpringContextIntegrationTest.java @@ -0,0 +1,17 @@ +package org.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.spring.cloud.kubernetes.client.Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class) +public class SpringContextIntegrationTest { + + @Test + public void contextLoads() { + } +} diff --git a/spring-cloud/spring-cloud-kubernetes-2/deployment-all.sh b/spring-cloud/spring-cloud-kubernetes-2/deployment-all.sh new file mode 100755 index 0000000000..9c088b7422 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/deployment-all.sh @@ -0,0 +1,34 @@ +### build the repository +mvn clean install + +### set docker env +eval $(minikube docker-env) + +### build the docker images on minikube +cd travel-agency-service +docker build -t travel-agency-service . +cd ../client-service +docker build -t client-service . +cd .. + +### secret and mongodb +kubectl delete -f secret.yaml +kubectl delete -f mongo-deployment.yaml + +kubectl create -f secret.yaml +kubectl create -f mongo-deployment.yaml + +### travel-agency-service +kubectl delete -f travel-agency-service/travel-agency-deployment.yaml +kubectl create -f travel-agency-service/travel-agency-deployment.yaml + + +### client-service +kubectl delete configmap client-service +kubectl delete -f client-service/client-service-deployment.yaml + +kubectl create -f client-service/client-config.yaml +kubectl create -f client-service/client-service-deployment.yaml + +# Check that the pods are running +kubectl get pods \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/mongo-deployment.yaml b/spring-cloud/spring-cloud-kubernetes-2/mongo-deployment.yaml new file mode 100644 index 0000000000..3d40581578 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/mongo-deployment.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: mongo + name: mongodb-service +spec: + type: NodePort + ports: + - name: "http" + port: 27017 + protocol: TCP + targetPort: 27017 + selector: + service: mongo +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: mongo +spec: + replicas: 1 + template: + metadata: + labels: + service: mongo + name: mongodb-service + spec: + containers: + - args: + - mongod + - --smallfiles + image: mongo:latest + name: mongo + env: + - name: MONGO_INITDB_ROOT_USERNAME + valueFrom: + secretKeyRef: + name: db-secret + key: username + - name: MONGO_INITDB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: db-secret + key: password diff --git a/spring-cloud/spring-cloud-kubernetes-2/pom.xml b/spring-cloud/spring-cloud-kubernetes-2/pom.xml new file mode 100644 index 0000000000..d501e8102f --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + com.baeldung.spring.cloud + spring-cloud-kubernetes-2 + 1.0-SNAPSHOT + spring-cloud-kubernetes-2 + pom + + + 2.0.6.RELEASE + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + client-service + travel-agency-service + + + diff --git a/spring-cloud/spring-cloud-kubernetes-2/secret.yaml b/spring-cloud/spring-cloud-kubernetes-2/secret.yaml new file mode 100644 index 0000000000..a813c35be7 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/secret.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: db-secret +data: + username: dXNlcg== + password: cDQ1NXcwcmQ= diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/Dockerfile b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/Dockerfile new file mode 100755 index 0000000000..30b66d5eff --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:8-jdk-alpine +VOLUME /tmp +COPY target/travel-agency-service-1.0-SNAPSHOT.jar app.jar +ENV JAVA_OPTS="" +ENTRYPOINT exec java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999 -jar /app.jar \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/pom.xml b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/pom.xml new file mode 100755 index 0000000000..a375264533 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + travel-agency-service + 1.0-SNAPSHOT + + + com.baeldung.spring.cloud + spring-cloud-kubernetes-2 + 1.0-SNAPSHOT + + + + 1.8 + Finchley.SR2 + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + + + ch.qos.logback + logback-classic + 1.2.3 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-actuator + + + org.springframework.boot + spring-boot-actuator-autoconfigure + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.spring.cloud.kubernetes.travelagency.Application + JAR + + + + + repackage + + + + + + + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/Application.java b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/Application.java new file mode 100755 index 0000000000..bfc7356176 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/Application.java @@ -0,0 +1,23 @@ +package com.baeldung.spring.cloud.kubernetes.travelagency; + +import com.baeldung.spring.cloud.kubernetes.travelagency.controller.TravelAgencyController; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application implements CommandLineRunner { + + private static final Log log = LogFactory.getLog(TravelAgencyController.class); + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + public void run(String... args) throws Exception { + log.info("Travel Agency Started! "); + } + +} diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/controller/TravelAgencyController.java b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/controller/TravelAgencyController.java new file mode 100644 index 0000000000..42f001616a --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/controller/TravelAgencyController.java @@ -0,0 +1,55 @@ +package com.baeldung.spring.cloud.kubernetes.travelagency.controller; + +import com.baeldung.spring.cloud.kubernetes.travelagency.model.TravelDeal; +import com.baeldung.spring.cloud.kubernetes.travelagency.repository.TravelDealRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; +import java.util.Random; +import static org.springframework.web.bind.annotation.RequestMethod.GET; + +@RestController +public class TravelAgencyController { + + @Autowired + private TravelDealRepository travelDealRepository; + + private static final Log log = LogFactory.getLog(TravelAgencyController.class); + + @RequestMapping(method = GET, path = "/deals") + public String deals() { + log.info("Client is requesting new deals!"); + + List travelDealList = travelDealRepository.findAll(); + if (!travelDealList.isEmpty()) { + int randomDeal = new Random().nextInt(travelDealList.size()); + return travelDealList.get(randomDeal) + .toString(); + } else { + return "NO DEALS"; + } + } + + @RequestMapping(method = GET, path = "/") + @ResponseBody + public String get() throws UnknownHostException { + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Host: ") + .append(InetAddress.getLocalHost() + .getHostName()) + .append("
"); + stringBuilder.append("IP: ") + .append(InetAddress.getLocalHost() + .getHostAddress()) + .append("
"); + stringBuilder.append("Type: ") + .append("Travel Agency") + .append("
"); + return stringBuilder.toString(); + } +} diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/model/TravelDeal.java b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/model/TravelDeal.java new file mode 100644 index 0000000000..2cd2bf2d45 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/model/TravelDeal.java @@ -0,0 +1,92 @@ +package com.baeldung.spring.cloud.kubernetes.travelagency.model; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +import java.math.BigInteger; +import java.util.Date; + +@Document(collection = "travel_deal") +public class TravelDeal { + + @Id + private BigInteger id; + + private String destination; + + private String description; + + @Field("deal_price") + private double dealPrice; + + @Field("old_price") + private double oldPrice; + + @Field("departure_date") + private Date departureDate; + + @Field("arrival_date") + private Date arrivalDate; + + public BigInteger getId() { + return id; + } + + public void setId(BigInteger id) { + this.id = id; + } + + public String getDestination() { + return destination; + } + + public void setDestination(String destination) { + this.destination = destination; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public double getDealPrice() { + return dealPrice; + } + + public void setDealPrice(double dealPrice) { + this.dealPrice = dealPrice; + } + + public double getOldPrice() { + return oldPrice; + } + + public void setOldPrice(double oldPrice) { + this.oldPrice = oldPrice; + } + + public Date getDepartureDate() { + return departureDate; + } + + public void setDepartureDate(Date departureDate) { + this.departureDate = departureDate; + } + + public Date getArrivalDate() { + return arrivalDate; + } + + public void setArrivalDate(Date arrivalDate) { + this.arrivalDate = arrivalDate; + } + + @Override + public String toString() { + return "TravelDeal{" + "id=" + id + ", destination='" + destination + '\'' + ", description='" + description + '\'' + ", dealPrice=" + dealPrice + ", oldPrice=" + oldPrice + ", departureDate=" + departureDate + ", arrivalDate=" + arrivalDate + '}'; + } +} diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/repository/TravelDealRepository.java b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/repository/TravelDealRepository.java new file mode 100644 index 0000000000..20c1e3b67a --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/java/com/baeldung/spring/cloud/kubernetes/travelagency/repository/TravelDealRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.cloud.kubernetes.travelagency.repository; + +import java.util.List; + +import com.baeldung.spring.cloud.kubernetes.travelagency.model.TravelDeal; +import org.springframework.data.mongodb.repository.MongoRepository; + +public interface TravelDealRepository extends MongoRepository { + + public List findByDestination(String destination); + +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/resources/application.properties b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/resources/application.properties new file mode 100644 index 0000000000..ffe78f0917 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/resources/application.properties @@ -0,0 +1,14 @@ +spring.application.name=travel-agency-service +server.port=8080 +spring.cloud.kubernetes.reload.enabled=true +spring.cloud.kubernetes.secrets.name=db-secret +spring.data.mongodb.host=mongodb-service +spring.data.mongodb.port=27017 +spring.data.mongodb.database=admin +spring.data.mongodb.username=${MONGO_USERNAME} +spring.data.mongodb.password=${MONGO_PASSWORD} +management.endpoint.health.enabled=true +management.endpoint.info.enabled=true +management.endpoint.restart.enabled=true +com.baeldung.spring.cloud.kubernetes.services=debug + diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/resources/logback-spring.xml b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/resources/logback-spring.xml new file mode 100644 index 0000000000..49aeda8f9f --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/resources/logback-spring.xml @@ -0,0 +1,17 @@ + + + + + + logstash:5000 + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/resources/logback.xml b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/resources/logback.xml new file mode 100644 index 0000000000..37492be5bf --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + + + + + + + diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/travel-agency-config.yaml b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/travel-agency-config.yaml new file mode 100644 index 0000000000..93a67e3777 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/travel-agency-config.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: travel-agency-service +data: + application.properties: |- + bean.message=Testing reload ! Message from backend is: %s
Services : %s + diff --git a/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/travel-agency-deployment.yaml b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/travel-agency-deployment.yaml new file mode 100644 index 0000000000..a41f13bf61 --- /dev/null +++ b/spring-cloud/spring-cloud-kubernetes-2/travel-agency-service/travel-agency-deployment.yaml @@ -0,0 +1,44 @@ +kind: Service +apiVersion: v1 +metadata: + name: travel-agency-service +spec: + selector: + app: travel-agency-service + ports: + - protocol: TCP + port: 8080 + nodePort: 30081 + type: NodePort +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: travel-agency-service +spec: + selector: + matchLabels: + app: travel-agency-service + replicas: 2 + template: + metadata: + labels: + app: travel-agency-service + spec: + containers: + - name: travel-agency-service + image: travel-agency-service:latest + imagePullPolicy: Never + ports: + - containerPort: 8080 + env: + - name: MONGO_USERNAME + valueFrom: + secretKeyRef: + name: db-secret + key: username + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: db-secret + key: password \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/liveness-example/pom.xml b/spring-cloud/spring-cloud-kubernetes/liveness-example/pom.xml index 9254718c81..012a81bd8d 100644 --- a/spring-cloud/spring-cloud-kubernetes/liveness-example/pom.xml +++ b/spring-cloud/spring-cloud-kubernetes/liveness-example/pom.xml @@ -4,13 +4,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 liveness-example + liveness-example 1.0-SNAPSHOT - org.springframework.boot - spring-boot-starter-parent - 1.5.17.RELEASE - + parent-boot-1 + com.baeldung + 0.0.1-SNAPSHOT + ../../../parent-boot-1 @@ -44,6 +45,7 @@ UTF-8 UTF-8 1.8 + 1.5.17.RELEASE \ No newline at end of file diff --git a/spring-cloud/spring-cloud-kubernetes/readiness-example/pom.xml b/spring-cloud/spring-cloud-kubernetes/readiness-example/pom.xml index e22bb0a9fe..2b2e57a19c 100644 --- a/spring-cloud/spring-cloud-kubernetes/readiness-example/pom.xml +++ b/spring-cloud/spring-cloud-kubernetes/readiness-example/pom.xml @@ -4,13 +4,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 readiness-example + readiness-example 1.0-SNAPSHOT - org.springframework.boot - spring-boot-starter-parent - 1.5.17.RELEASE - + parent-boot-1 + com.baeldung + 0.0.1-SNAPSHOT + ../../../parent-boot-1 @@ -44,6 +45,7 @@ UTF-8 UTF-8 1.8 + 1.5.17.RELEASE \ No newline at end of file diff --git a/spring-cloud/spring-cloud-openfeign/pom.xml b/spring-cloud/spring-cloud-openfeign/pom.xml new file mode 100644 index 0000000000..002a333749 --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + com.baeldung.cloud + openfeign + 0.0.1-SNAPSHOT + openfeign + OpenFeign project for Spring Boot + + + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + 2.0.1.RELEASE + Finchley.SR2 + + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + io.github.openfeign + feign-okhttp + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/ExampleApplication.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/ExampleApplication.java new file mode 100644 index 0000000000..c7f07f6667 --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/ExampleApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.cloud.openfeign; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; + +@SpringBootApplication +@EnableFeignClients +public class ExampleApplication { + + public static void main(String[] args) { + SpringApplication.run(ExampleApplication.class, args); + } + +} + diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/JSONPlaceHolderClient.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/JSONPlaceHolderClient.java new file mode 100644 index 0000000000..bdbe6efeeb --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/JSONPlaceHolderClient.java @@ -0,0 +1,25 @@ +package com.baeldung.cloud.openfeign.client; + +import com.baeldung.cloud.openfeign.config.ClientConfiguration; +import com.baeldung.cloud.openfeign.hystrix.JSONPlaceHolderFallback; +import com.baeldung.cloud.openfeign.model.Post; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import java.util.List; + +@FeignClient(value = "jplaceholder", + url = "https://jsonplaceholder.typicode.com/", + configuration = ClientConfiguration.class, + fallback = JSONPlaceHolderFallback.class) +public interface JSONPlaceHolderClient { + + @RequestMapping(method = RequestMethod.GET, value = "/posts") + List getPosts(); + + + @RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json") + Post getPostById(@PathVariable("postId") Long postId); +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/ClientConfiguration.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/ClientConfiguration.java new file mode 100644 index 0000000000..0b16134e92 --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/ClientConfiguration.java @@ -0,0 +1,37 @@ +package com.baeldung.cloud.openfeign.config; + +import feign.Logger; +import feign.RequestInterceptor; +import feign.codec.ErrorDecoder; +import feign.okhttp.OkHttpClient; +import org.apache.http.entity.ContentType; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ClientConfiguration { + + @Bean + public Logger.Level feignLoggerLevel() { + return Logger.Level.FULL; + } + + @Bean + public ErrorDecoder errorDecoder() { + return new ErrorDecoder.Default(); + } + + @Bean + public OkHttpClient client() { + return new OkHttpClient(); + } + + @Bean + public RequestInterceptor requestInterceptor() { + return requestTemplate -> { + requestTemplate.header("user", "ajeje"); + requestTemplate.header("password", "brazof"); + requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType()); + }; + } +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/CustomErrorDecoder.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/CustomErrorDecoder.java new file mode 100644 index 0000000000..4d32cf083f --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/CustomErrorDecoder.java @@ -0,0 +1,21 @@ +package com.baeldung.cloud.openfeign.config; + +import com.baeldung.cloud.openfeign.exception.BadRequestException; +import com.baeldung.cloud.openfeign.exception.NotFoundException; +import feign.Response; +import feign.codec.ErrorDecoder; + +public class CustomErrorDecoder implements ErrorDecoder { + @Override + public Exception decode(String methodKey, Response response) { + + switch (response.status()){ + case 400: + return new BadRequestException(); + case 404: + return new NotFoundException(); + default: + return new Exception("Generic error"); + } + } +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/exception/BadRequestException.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/exception/BadRequestException.java new file mode 100644 index 0000000000..50200957ad --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/exception/BadRequestException.java @@ -0,0 +1,21 @@ +package com.baeldung.cloud.openfeign.exception; + +public class BadRequestException extends Exception { + + public BadRequestException() { + } + + public BadRequestException(String message) { + super(message); + } + + public BadRequestException(Throwable cause) { + super(cause); + } + + @Override + public String toString() { + return "BadRequestException: "+getMessage(); + } + +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/exception/NotFoundException.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/exception/NotFoundException.java new file mode 100644 index 0000000000..28d0e95e9a --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/exception/NotFoundException.java @@ -0,0 +1,21 @@ +package com.baeldung.cloud.openfeign.exception; + +public class NotFoundException extends Exception { + + public NotFoundException() { + } + + public NotFoundException(String message) { + super(message); + } + + public NotFoundException(Throwable cause) { + super(cause); + } + + @Override + public String toString() { + return "NotFoundException: "+getMessage(); + } + +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/hystrix/JSONPlaceHolderFallback.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/hystrix/JSONPlaceHolderFallback.java new file mode 100644 index 0000000000..1aa3112320 --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/hystrix/JSONPlaceHolderFallback.java @@ -0,0 +1,22 @@ +package com.baeldung.cloud.openfeign.hystrix; + +import com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient; +import com.baeldung.cloud.openfeign.model.Post; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; + +@Component +public class JSONPlaceHolderFallback implements JSONPlaceHolderClient { + + @Override + public List getPosts() { + return Collections.emptyList(); + } + + @Override + public Post getPostById(Long postId) { + return null; + } +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Post.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Post.java new file mode 100644 index 0000000000..cab9629653 --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Post.java @@ -0,0 +1,41 @@ +package com.baeldung.cloud.openfeign.model; + +public class Post { + + private String userId; + private Long id; + private String title; + private String body; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/JSONPlaceHolderService.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/JSONPlaceHolderService.java new file mode 100644 index 0000000000..16e9b1dbde --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/JSONPlaceHolderService.java @@ -0,0 +1,12 @@ +package com.baeldung.cloud.openfeign.service; + +import com.baeldung.cloud.openfeign.model.Post; + +import java.util.List; + +public interface JSONPlaceHolderService { + + List getPosts(); + + Post getPostById(Long id); +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/impl/JSONPlaceHolderServiceImpl.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/impl/JSONPlaceHolderServiceImpl.java new file mode 100644 index 0000000000..30348db3c2 --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/impl/JSONPlaceHolderServiceImpl.java @@ -0,0 +1,26 @@ +package com.baeldung.cloud.openfeign.service.impl; + +import com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient; +import com.baeldung.cloud.openfeign.model.Post; +import com.baeldung.cloud.openfeign.service.JSONPlaceHolderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class JSONPlaceHolderServiceImpl implements JSONPlaceHolderService { + + @Autowired + private JSONPlaceHolderClient jsonPlaceHolderClient; + + @Override + public List getPosts() { + return jsonPlaceHolderClient.getPosts(); + } + + @Override + public Post getPostById(Long id) { + return jsonPlaceHolderClient.getPostById(id); + } +} diff --git a/spring-cloud/spring-cloud-openfeign/src/main/resources/application.properties b/spring-cloud/spring-cloud-openfeign/src/main/resources/application.properties new file mode 100644 index 0000000000..41bbbde2c3 --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.application.name= openfeign +logging.level.com.baeldung.cloud.openfeign.client: DEBUG +feign.hystrix.enabled=true diff --git a/spring-cloud/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenfeignUnitTest.java b/spring-cloud/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenfeignUnitTest.java new file mode 100644 index 0000000000..72d2baa5d7 --- /dev/null +++ b/spring-cloud/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenfeignUnitTest.java @@ -0,0 +1,43 @@ +package com.baeldung.cloud.openfeign; + +import com.baeldung.cloud.openfeign.model.Post; +import com.baeldung.cloud.openfeign.service.JSONPlaceHolderService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class OpenfeignUnitTest { + + @Autowired + private JSONPlaceHolderService jsonPlaceHolderService; + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } + + @Test + public void whenGetPosts_thenListPostSizeGreaterThanZero() { + + List posts = jsonPlaceHolderService.getPosts(); + + assertFalse(posts.isEmpty()); + } + + @Test + public void whenGetPostWithId_thenPostExist() { + + Post post = jsonPlaceHolderService.getPostById(1L); + + assertNotNull(post); + } + +} diff --git a/spring-cloud/spring-cloud-vault/pom.xml b/spring-cloud/spring-cloud-vault/pom.xml index abfb0d06f3..3466f657be 100644 --- a/spring-cloud/spring-cloud-vault/pom.xml +++ b/spring-cloud/spring-cloud-vault/pom.xml @@ -65,22 +65,11 @@ - - - spring-milestones - Spring Milestones - http://repo.spring.io/milestone - - false - - - - UTF-8 UTF-8 1.8 - Greenwich.M3 + Greenwich.RELEASE diff --git a/spring-cloud/spring-cloud-zuul/pom.xml b/spring-cloud/spring-cloud-zuul/pom.xml index 97e67f16d8..08990357d6 100644 --- a/spring-cloud/spring-cloud-zuul/pom.xml +++ b/spring-cloud/spring-cloud-zuul/pom.xml @@ -10,11 +10,11 @@ Demo project for Spring Boot - org.springframework.boot - spring-boot-starter-parent - 2.0.6.RELEASE - - + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../../parent-boot-2 + @@ -72,6 +72,7 @@ UTF-8 1.8 Finchley.SR1 + 2.0.6.RELEASE diff --git a/spring-cloud/spring-cloud-zuul/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java b/spring-cloud/spring-cloud-zuul/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerUnitTest.java similarity index 99% rename from spring-cloud/spring-cloud-zuul/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java rename to spring-cloud/spring-cloud-zuul/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerUnitTest.java index d51f881112..d23ec836f9 100644 --- a/spring-cloud/spring-cloud-zuul/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java +++ b/spring-cloud/spring-cloud-zuul/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerUnitTest.java @@ -26,7 +26,7 @@ import org.springframework.test.context.junit4.SpringRunner; @AutoConfigureTestDatabase @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class GreetingControllerTest { +public class GreetingControllerUnitTest { private static final String SIMPLE_GREETING = "/greeting/simple"; private static final String ADVANCED_GREETING = "/greeting/advanced"; diff --git a/spring-core/README.md b/spring-core/README.md index dcc15a4cb9..d542fa8ed1 100644 --- a/spring-core/README.md +++ b/spring-core/README.md @@ -23,3 +23,4 @@ - [Unsatisfied Dependency in Spring](https://www.baeldung.com/spring-unsatisfied-dependency) - [What is a Spring Bean?](https://www.baeldung.com/spring-bean) - [Spring PostConstruct and PreDestroy Annotations](https://www.baeldung.com/spring-postconstruct-predestroy) +- [Guice vs Spring – Dependency Injection](https://www.baeldung.com/guice-spring-dependency-injection) diff --git a/spring-core/pom.xml b/spring-core/pom.xml index 46f777c020..d348d742e7 100644 --- a/spring-core/pom.xml +++ b/spring-core/pom.xml @@ -82,7 +82,6 @@ 1 20.0 2.6 - 1.16.12 2.5 1.5.2.RELEASE 1.10.19 diff --git a/spring-data-rest/pom.xml b/spring-data-rest/pom.xml index 772d6f2553..e563a6a3b5 100644 --- a/spring-data-rest/pom.xml +++ b/spring-data-rest/pom.xml @@ -2,8 +2,8 @@ 4.0.0 - com.baeldung spring-data-rest + 1.0 spring-data-rest jar @@ -40,11 +40,7 @@ org.xerial sqlite-jdbc - ${sqlite.version} - @@ -53,8 +49,6 @@ com.baeldung.SpringDataRestApplication - 3.25.2 - 2.1.0.RELEASE diff --git a/spring-data-rest/src/test/java/com/baeldung/projection/SpringDataProjectionLiveTest.java b/spring-data-rest/src/test/java/com/baeldung/projection/SpringDataProjectionLiveTest.java index ad219ccd53..274ae3bc1d 100644 --- a/spring-data-rest/src/test/java/com/baeldung/projection/SpringDataProjectionLiveTest.java +++ b/spring-data-rest/src/test/java/com/baeldung/projection/SpringDataProjectionLiveTest.java @@ -37,7 +37,7 @@ public class SpringDataProjectionLiveTest { @Before public void setup() { - if (bookRepo.findById(1L) == null) { + if (!bookRepo.findById(1L).isPresent()) { Book book = new Book("Animal Farm"); book.setIsbn("978-1943138425"); book = bookRepo.save(book); diff --git a/spring-dispatcher-servlet/pom.xml b/spring-dispatcher-servlet/pom.xml index 2eeb37eef0..eb0fdfea46 100644 --- a/spring-dispatcher-servlet/pom.xml +++ b/spring-dispatcher-servlet/pom.xml @@ -54,7 +54,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson-databind.version} + ${jackson.version} commons-fileupload diff --git a/spring-ehcache/README.md b/spring-ehcache/README.md index 749441375e..ecf96cd7c7 100644 --- a/spring-ehcache/README.md +++ b/spring-ehcache/README.md @@ -3,5 +3,5 @@ A simple example of using ehcache with spring-boot. ### Relevant Articles: -- [Spring Boot Ehcache Example](http://www.baeldung.com/spring-ehcache) +- [Spring Boot Ehcache Example](https://www.baeldung.com/spring-boot-ehcache) diff --git a/spring-integration/pom.xml b/spring-integration/pom.xml index 11a1e617aa..367d25de98 100644 --- a/spring-integration/pom.xml +++ b/spring-integration/pom.xml @@ -110,7 +110,6 @@ 1.1.4.RELEASE 1.4.7 1.1.1 - 4.12 2.10 1.5.0 diff --git a/spring-jms/README.md b/spring-jms/README.md index b942cc72a0..55e74f18ff 100644 --- a/spring-jms/README.md +++ b/spring-jms/README.md @@ -1,2 +1,2 @@ ### Relevant Articles: -- [An Introduction To Spring JMS](http://www.baeldung.com/spring-jms) +- [Getting Started with Spring JMS](http://www.baeldung.com/spring-jms) diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsErrorHandler.java b/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsErrorHandler.java new file mode 100644 index 0000000000..220b2744f3 --- /dev/null +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsErrorHandler.java @@ -0,0 +1,17 @@ +package com.baeldung.spring.jms; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.ErrorHandler; + +public class SampleJmsErrorHandler implements ErrorHandler { + + private static final Logger LOG = LoggerFactory.getLogger(SampleJmsErrorHandler.class); + + @Override + public void handleError(Throwable t) { + LOG.warn("In default jms error handler..."); + LOG.error("Error Message : {}", t.getMessage()); + } + +} diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsMessageSender.java b/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsMessageSender.java index 927762f05b..d3f09618fb 100644 --- a/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsMessageSender.java +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/SampleJmsMessageSender.java @@ -26,4 +26,8 @@ public class SampleJmsMessageSender { public void sendMessage(final Employee employee) { this.jmsTemplate.convertAndSend(employee); } + + public void sendTextMessage(String msg) { + this.jmsTemplate.send(queue, s -> s.createTextMessage(msg)); + } } diff --git a/spring-jms/src/main/java/com/baeldung/spring/jms/SampleListener.java b/spring-jms/src/main/java/com/baeldung/spring/jms/SampleListener.java index f35c22e144..87627c47e7 100644 --- a/spring-jms/src/main/java/com/baeldung/spring/jms/SampleListener.java +++ b/spring-jms/src/main/java/com/baeldung/spring/jms/SampleListener.java @@ -27,6 +27,9 @@ public class SampleListener implements MessageListener { try { String msg = ((TextMessage) message).getText(); System.out.println("Received message: " + msg); + if (msg == null) { + throw new IllegalArgumentException("Null value received..."); + } } catch (JMSException ex) { throw new RuntimeException(ex); } @@ -37,4 +40,5 @@ public class SampleListener implements MessageListener { Map map = (Map) this.jmsTemplate.receiveAndConvert(); return new Employee((String) map.get("name"), (Integer) map.get("age")); } + } diff --git a/spring-jms/src/main/resources/applicationContext.xml b/spring-jms/src/main/resources/applicationContext.xml index 28bf848e59..97a90e0bf2 100644 --- a/spring-jms/src/main/resources/applicationContext.xml +++ b/spring-jms/src/main/resources/applicationContext.xml @@ -1,51 +1,48 @@ - - - - - - - - - - + + + + + + - - - + + + - + + + + + + + - - - + + + + + - - - - + + + + + - + - - - - - - - - - - - - - + + + + + + + diff --git a/spring-jms/src/test/java/com/baeldung/spring/jms/DefaultTextMessageSenderIntegrationTest.java b/spring-jms/src/test/java/com/baeldung/spring/jms/DefaultTextMessageSenderIntegrationTest.java index f87d26b144..f23ead4d69 100644 --- a/spring-jms/src/test/java/com/baeldung/spring/jms/DefaultTextMessageSenderIntegrationTest.java +++ b/spring-jms/src/test/java/com/baeldung/spring/jms/DefaultTextMessageSenderIntegrationTest.java @@ -8,12 +8,14 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; public class DefaultTextMessageSenderIntegrationTest { private static SampleJmsMessageSender messageProducer; + private static SampleListener messageListener; @SuppressWarnings("resource") @BeforeClass public static void setUp() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:EmbeddedActiveMQ.xml", "classpath:applicationContext.xml"); messageProducer = (SampleJmsMessageSender) applicationContext.getBean("SampleJmsMessageSender"); + messageListener = (SampleListener) applicationContext.getBean("messageListener"); } @Test @@ -21,4 +23,9 @@ public class DefaultTextMessageSenderIntegrationTest { messageProducer.simpleSend(); } + @Test + public void testSendTextMessage() { + messageProducer.sendTextMessage(null); + } + } diff --git a/spring-katharsis/README.md b/spring-katharsis/README.md index cf2a001760..2082de2dda 100644 --- a/spring-katharsis/README.md +++ b/spring-katharsis/README.md @@ -6,4 +6,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: -- [JSON API in a Java Web Application](http://www.baeldung.com/json-api-java-spring-web-app) +- [JSON API in a Spring Application](http://www.baeldung.com/json-api-java-spring-web-app) diff --git a/spring-mvc-forms-jsp/pom.xml b/spring-mvc-forms-jsp/pom.xml index 5536314086..e0539c3216 100644 --- a/spring-mvc-forms-jsp/pom.xml +++ b/spring-mvc-forms-jsp/pom.xml @@ -61,7 +61,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson-databind.version} + ${jackson.version} org.springframework.boot diff --git a/spring-mvc-java/README.md b/spring-mvc-java/README.md index 851a3689ab..497b0f4c1f 100644 --- a/spring-mvc-java/README.md +++ b/spring-mvc-java/README.md @@ -29,6 +29,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [A Quick Example of Spring Websockets’ @SendToUser Annotation](http://www.baeldung.com/spring-websockets-sendtouser) - [Using Spring ResponseEntity to Manipulate the HTTP Response](http://www.baeldung.com/spring-response-entity) - [Using Spring @ResponseStatus to Set HTTP Status Code](http://www.baeldung.com/spring-response-status) -- [Bootstrap a Web Application with Spring 5](https://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration) - [Spring MVC Tutorial](https://www.baeldung.com/spring-mvc-tutorial) - [Working with Date Parameters in Spring](https://www.baeldung.com/spring-date-parameters) diff --git a/spring-mvc-java/pom.xml b/spring-mvc-java/pom.xml index 552f62d9f7..853d8db64c 100644 --- a/spring-mvc-java/pom.xml +++ b/spring-mvc-java/pom.xml @@ -40,7 +40,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson-databind.version} + ${jackson.version} diff --git a/spring-mvc-simple/README.md b/spring-mvc-simple/README.md index 755e0932fc..cd4ad5aba2 100644 --- a/spring-mvc-simple/README.md +++ b/spring-mvc-simple/README.md @@ -8,3 +8,4 @@ - [Guide to Spring Email](http://www.baeldung.com/spring-email) - [Request Method Not Supported (405) in Spring](https://www.baeldung.com/spring-request-method-not-supported-405) - [Spring @RequestParam Annotation](https://www.baeldung.com/spring-request-param) +- [Validating RequestParams and PathVariables in Spring](https://www.baeldung.com/spring-validate-requestparam-pathvariable) diff --git a/spring-mvc-simple/pom.xml b/spring-mvc-simple/pom.xml index 8c2661cc27..b9ed3a3e81 100644 --- a/spring-mvc-simple/pom.xml +++ b/spring-mvc-simple/pom.xml @@ -17,7 +17,7 @@ org.springframework spring-oxm - ${spring-oxm.version} + ${spring.version} com.sun.mail @@ -181,7 +181,6 @@ 1.4.9 5.1.0 20180130 - 5.0.2.RELEASE 3.0.8 diff --git a/spring-mvc-xml/README.md b/spring-mvc-xml/README.md index 3199118281..dbc6125424 100644 --- a/spring-mvc-xml/README.md +++ b/spring-mvc-xml/README.md @@ -8,7 +8,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: -- [Servlet Session Timeout](http://www.baeldung.com/servlet-session-timeout) +- [Java Session Timeout](http://www.baeldung.com/servlet-session-timeout) - [Returning Image/Media Data with Spring MVC](http://www.baeldung.com/spring-mvc-image-media-data) - [Geolocation by IP in Java](http://www.baeldung.com/geolocation-by-ip-with-maxmind) - [Guide to JavaServer Pages (JSP)](http://www.baeldung.com/jsp) diff --git a/spring-mvc-xml/src/main/java/com/baeldung/spring/controller/ConstraintViolationExceptionHandler.java b/spring-mvc-xml/src/main/java/com/baeldung/spring/controller/ConstraintViolationExceptionHandler.java new file mode 100644 index 0000000000..645b36c2a5 --- /dev/null +++ b/spring-mvc-xml/src/main/java/com/baeldung/spring/controller/ConstraintViolationExceptionHandler.java @@ -0,0 +1,21 @@ +package com.baeldung.spring.controller; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import javax.validation.ConstraintViolationException; + +@ControllerAdvice +public class ConstraintViolationExceptionHandler extends ResponseEntityExceptionHandler { + + @ExceptionHandler(value = {ConstraintViolationException.class}) + protected ResponseEntity handleConstraintViolation(ConstraintViolationException e, WebRequest request) { + return handleExceptionInternal(e, e.getMessage(), new HttpHeaders(), HttpStatus.BAD_REQUEST, request); + } +} + diff --git a/spring-mvc-xml/src/main/java/com/baeldung/spring/controller/RequestAndPathVariableValidationController.java b/spring-mvc-xml/src/main/java/com/baeldung/spring/controller/RequestAndPathVariableValidationController.java new file mode 100644 index 0000000000..b77598c113 --- /dev/null +++ b/spring-mvc-xml/src/main/java/com/baeldung/spring/controller/RequestAndPathVariableValidationController.java @@ -0,0 +1,31 @@ +package com.baeldung.spring.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.validation.annotation.Validated; +import javax.validation.constraints.*; + +@Controller +@RequestMapping("/public/api/1") +@Validated +public class RequestAndPathVariableValidationController { + + @GetMapping("/name-for-day") + public String getNameOfDayByNumberRequestParam(@RequestParam @Min(1) @Max(7) Integer dayOfWeek) { + return dayOfWeek + ""; + } + + @GetMapping("/name-for-day/{dayOfWeek}") + public String getNameOfDayByPathVariable(@PathVariable("dayOfWeek") @Min(1) @Max(7) Integer dayOfWeek) { + return dayOfWeek + ""; + } + + @GetMapping("/valid-name") + public void validStringRequestParam(@RequestParam @NotBlank @Size(max = 10) @Pattern(regexp = "^[A-Z][a-zA-Z0-9]+$") String name) { + + } + +} diff --git a/spring-mvc-xml/src/test/java/com/baeldung/spring/controller/RequestAndPathVariableValidationControllerIntegrationTest.java b/spring-mvc-xml/src/test/java/com/baeldung/spring/controller/RequestAndPathVariableValidationControllerIntegrationTest.java new file mode 100644 index 0000000000..318a15d8f7 --- /dev/null +++ b/spring-mvc-xml/src/test/java/com/baeldung/spring/controller/RequestAndPathVariableValidationControllerIntegrationTest.java @@ -0,0 +1,72 @@ +package com.baeldung.spring.controller; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import com.baeldung.spring.ClientWebConfig; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = ClientWebConfig.class) +@WebAppConfiguration +public class RequestAndPathVariableValidationControllerIntegrationTest { + + private MockMvc mockMvc; + + @Autowired + private WebApplicationContext webApplicationContext; + + @Before + public void setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); + } + + @Test + public void getNameOfDayByNumberRequestParam_whenGetWithProperRequestParam_thenReturn200() throws Exception { + mockMvc.perform(get("/public/api/1/name-for-day").param("dayOfWeek", Integer.toString(5))) + .andExpect(status().isOk()); + } + + @Test + public void getNameOfDayByNumberRequestParam_whenGetWithRequestParamOutOfRange_thenReturn400() throws Exception { + mockMvc.perform(get("/public/api/1/name-for-day").param("dayOfWeek", Integer.toString(15))) + .andExpect(status().isBadRequest()); + } + + @Test + public void getNameOfDayByPathVariable_whenGetWithProperRequestParam_thenReturn200() throws Exception { + mockMvc.perform(get("/public/api/1/name-for-day/{dayOfWeek}", Integer.toString(5))).andExpect(status().isOk()); + } + + @Test + public void getNameOfDayByPathVariable_whenGetWithRequestParamOutOfRange_thenReturn400() throws Exception { + mockMvc.perform(get("/public/api/1/name-for-day/{dayOfWeek}", Integer.toString(15))) + .andExpect(status().isBadRequest()); + } + + @Test + public void validStringRequestParam_whenGetWithProperRequestParam_thenReturn200() throws Exception { + mockMvc.perform(get("/public/api/1/valid-name").param("name", "John")).andExpect(status().isOk()); + } + + @Test + public void validStringRequestParam_whenGetWithTooLongRequestParam_thenReturn400() throws Exception { + mockMvc.perform(get("/public/api/1/valid-name").param("name", "asdfghjklqw")) + .andExpect(status().isBadRequest()); + } + + @Test + public void validStringRequestParam_whenGetWithLowerCaseRequestParam_thenReturn400() throws Exception { + mockMvc.perform(get("/public/api/1/valid-name").param("name", "john")).andExpect(status().isBadRequest()); + } +} diff --git a/spring-remoting/README.md b/spring-remoting/README.md index 7d344a3f27..0898b9b002 100644 --- a/spring-remoting/README.md +++ b/spring-remoting/README.md @@ -4,7 +4,7 @@ - [Intro to Spring Remoting with HTTP Invokers](http://www.baeldung.com/spring-remoting-http-invoker) - [Spring Remoting with Hessian and Burlap](http://www.baeldung.com/spring-remoting-hessian-burlap) - [Spring Remoting with AMQP](http://www.baeldung.com/spring-remoting-amqp) -- [Spring Remoting with JMS](http://www.baeldung.com/spring-remoting-jms) +- [Spring Remoting with JMS and ActiveMQ](http://www.baeldung.com/spring-remoting-jms) - [Spring Remoting with RMI](http://www.baeldung.com/spring-remoting-rmi) ### Overview diff --git a/spring-remoting/remoting-hessian-burlap/remoting-hessian-burlap-client/pom.xml b/spring-remoting/remoting-hessian-burlap/remoting-hessian-burlap-client/pom.xml index 104712c3d7..ec237ca815 100644 --- a/spring-remoting/remoting-hessian-burlap/remoting-hessian-burlap-client/pom.xml +++ b/spring-remoting/remoting-hessian-burlap/remoting-hessian-burlap-client/pom.xml @@ -3,8 +3,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - spring-remoting-hessian-burlap-client - spring-remoting-hessian-burlap-client + remoting-hessian-burlap-client + remoting-hessian-burlap-client remoting-hessian-burlap diff --git a/spring-rest-full/README.md b/spring-rest-full/README.md index b8b9034a0b..e0d3a70626 100644 --- a/spring-rest-full/README.md +++ b/spring-rest-full/README.md @@ -8,12 +8,10 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Articles: -- [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring) - [Integration Testing with the Maven Cargo plugin](http://www.baeldung.com/integration-testing-with-the-maven-cargo-plugin) - [Introduction to Spring Data JPA](http://www.baeldung.com/the-persistence-layer-with-spring-data-jpa) - [Project Configuration with Spring](http://www.baeldung.com/project-configuration-with-spring) - [Metrics for your Spring REST API](http://www.baeldung.com/spring-rest-api-metrics) -- [Bootstrap a Web Application with Spring 4](http://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration) - [Spring Security Expressions - hasRole Example](https://www.baeldung.com/spring-security-expressions-basic) diff --git a/spring-rest-full/pom.xml b/spring-rest-full/pom.xml index ddc7e042b5..ee6e5dbe3e 100644 --- a/spring-rest-full/pom.xml +++ b/spring-rest-full/pom.xml @@ -158,11 +158,6 @@ com.fasterxml.jackson.core jackson-databind - - com.thoughtworks.xstream - xstream - ${xstream.version} - diff --git a/spring-rest-full/src/main/java/org/baeldung/spring/Application.java b/spring-rest-full/src/main/java/org/baeldung/spring/Application.java index 9a3f473b8b..950e2085a6 100644 --- a/spring-rest-full/src/main/java/org/baeldung/spring/Application.java +++ b/spring-rest-full/src/main/java/org/baeldung/spring/Application.java @@ -8,11 +8,9 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.support.SpringBootServletInitializer; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.context.request.RequestContextListener; -import org.springframework.web.filter.ShallowEtagHeaderFilter; /** * Main Application Class - uses Spring Boot. Just run this as a normal Java @@ -40,8 +38,4 @@ public class Application extends SpringBootServletInitializer { SpringApplication.run(Application.class, args); } - @Bean - public ShallowEtagHeaderFilter shallowEtagHeaderFilter() { - return new ShallowEtagHeaderFilter(); - } } \ No newline at end of file diff --git a/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java b/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java index 9cb028bfdb..caaf422410 100644 --- a/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java +++ b/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java @@ -6,10 +6,8 @@ import javax.servlet.http.HttpServletResponse; import org.baeldung.persistence.model.Foo; import org.baeldung.persistence.service.IFooService; -import org.baeldung.web.hateoas.event.ResourceCreatedEvent; import org.baeldung.web.util.RestPreconditions; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; @@ -26,9 +24,6 @@ import com.google.common.base.Preconditions; @RequestMapping(value = "/auth/foos") public class FooController { - @Autowired - private ApplicationEventPublisher eventPublisher; - @Autowired private IFooService service; @@ -71,9 +66,6 @@ public class FooController { public Foo create(@RequestBody final Foo resource, final HttpServletResponse response) { Preconditions.checkNotNull(resource); final Foo foo = service.create(resource); - final Long idOfCreatedResource = foo.getId(); - - eventPublisher.publishEvent(new ResourceCreatedEvent(this, response, idOfCreatedResource)); return foo; } diff --git a/spring-rest-full/src/main/java/org/baeldung/web/error/RestResponseEntityExceptionHandler.java b/spring-rest-full/src/main/java/org/baeldung/web/error/RestResponseEntityExceptionHandler.java deleted file mode 100644 index c0639acef4..0000000000 --- a/spring-rest-full/src/main/java/org/baeldung/web/error/RestResponseEntityExceptionHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.baeldung.web.error; - -import org.baeldung.web.exception.MyResourceNotFoundException; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; - -@ControllerAdvice -public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { - - public RestResponseEntityExceptionHandler() { - super(); - } - - @ExceptionHandler(value = { MyResourceNotFoundException.class }) - protected ResponseEntity handleNotFound(final RuntimeException ex, final WebRequest request) { - final String bodyOfResponse = "This should be application specific"; - return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request); - } - -} diff --git a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/event/ResourceCreatedEvent.java b/spring-rest-full/src/main/java/org/baeldung/web/hateoas/event/ResourceCreatedEvent.java deleted file mode 100644 index efc04299bc..0000000000 --- a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/event/ResourceCreatedEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.baeldung.web.hateoas.event; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.context.ApplicationEvent; - -public class ResourceCreatedEvent extends ApplicationEvent { - private final HttpServletResponse response; - private final long idOfNewResource; - - public ResourceCreatedEvent(final Object source, final HttpServletResponse response, final long idOfNewResource) { - super(source); - - this.response = response; - this.idOfNewResource = idOfNewResource; - } - - // API - - public HttpServletResponse getResponse() { - return response; - } - - public long getIdOfNewResource() { - return idOfNewResource; - } - -} diff --git a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/listener/ResourceCreatedDiscoverabilityListener.java b/spring-rest-full/src/main/java/org/baeldung/web/hateoas/listener/ResourceCreatedDiscoverabilityListener.java deleted file mode 100644 index 0b308712cb..0000000000 --- a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/listener/ResourceCreatedDiscoverabilityListener.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.baeldung.web.hateoas.listener; - -import java.net.URI; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.http.HttpHeaders; -import org.baeldung.web.hateoas.event.ResourceCreatedEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.stereotype.Component; -import org.springframework.web.servlet.support.ServletUriComponentsBuilder; - -import com.google.common.base.Preconditions; - -@Component -class ResourceCreatedDiscoverabilityListener implements ApplicationListener { - - @Override - public void onApplicationEvent(final ResourceCreatedEvent resourceCreatedEvent) { - Preconditions.checkNotNull(resourceCreatedEvent); - - final HttpServletResponse response = resourceCreatedEvent.getResponse(); - final long idOfNewResource = resourceCreatedEvent.getIdOfNewResource(); - - addLinkHeaderOnResourceCreation(response, idOfNewResource); - } - - void addLinkHeaderOnResourceCreation(final HttpServletResponse response, final long idOfNewResource) { - // final String requestUrl = request.getRequestURL().toString(); - // final URI uri = new UriTemplate("{requestUrl}/{idOfNewResource}").expand(requestUrl, idOfNewResource); - - final URI uri = ServletUriComponentsBuilder.fromCurrentRequestUri().path("/{idOfNewResource}").buildAndExpand(idOfNewResource).toUri(); - response.setHeader(HttpHeaders.LOCATION, uri.toASCIIString()); - } - -} \ No newline at end of file diff --git a/spring-rest-full/src/main/java/org/baeldung/web/util/LinkUtil.java b/spring-rest-full/src/main/java/org/baeldung/web/util/LinkUtil.java deleted file mode 100644 index b2137aeeff..0000000000 --- a/spring-rest-full/src/main/java/org/baeldung/web/util/LinkUtil.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.baeldung.web.util; - -import javax.servlet.http.HttpServletResponse; - -/** - * Provides some constants and utility methods to build a Link Header to be stored in the {@link HttpServletResponse} object - */ -public final class LinkUtil { - - public static final String REL_COLLECTION = "collection"; - public static final String REL_NEXT = "next"; - public static final String REL_PREV = "prev"; - public static final String REL_FIRST = "first"; - public static final String REL_LAST = "last"; - - private LinkUtil() { - throw new AssertionError(); - } - - // - - /** - * Creates a Link Header to be stored in the {@link HttpServletResponse} to provide Discoverability features to the user - * - * @param uri - * the base uri - * @param rel - * the relative path - * - * @return the complete url - */ - public static String createLinkHeader(final String uri, final String rel) { - return "<" + uri + ">; rel=\"" + rel + "\""; - } - -} diff --git a/spring-rest-full/src/main/webapp/WEB-INF/web.xml b/spring-rest-full/src/main/webapp/WEB-INF/web.xml index 85bc72469e..5f90c3519f 100644 --- a/spring-rest-full/src/main/webapp/WEB-INF/web.xml +++ b/spring-rest-full/src/main/webapp/WEB-INF/web.xml @@ -23,15 +23,6 @@ org.springframework.web.context.ContextLoaderListener - - etagFilter - org.springframework.web.filter.ShallowEtagHeaderFilter - - - etagFilter - /* - - api diff --git a/spring-rest-full/src/test/java/org/baeldung/TestSuiteLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/TestSuiteLiveTest.java deleted file mode 100644 index 76215bb6e3..0000000000 --- a/spring-rest-full/src/test/java/org/baeldung/TestSuiteLiveTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.baeldung; - -import org.baeldung.persistence.PersistenceTestSuite; -import org.baeldung.web.LiveTestSuiteLiveTest; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@RunWith(Suite.class) -@Suite.SuiteClasses({ -// @formatter:off - PersistenceTestSuite.class - ,LiveTestSuiteLiveTest.class -}) // -public class TestSuiteLiveTest { - -} diff --git a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java deleted file mode 100644 index d64807d97f..0000000000 --- a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.baeldung.common.web; - -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.io.Serializable; - -import org.junit.Ignore; -import org.junit.Test; - -import com.google.common.net.HttpHeaders; - -import io.restassured.RestAssured; -import io.restassured.response.Response; - -public abstract class AbstractBasicLiveTest extends AbstractLiveTest { - - public AbstractBasicLiveTest(final Class clazzToSet) { - super(clazzToSet); - } - - // tests - - @Test - public void givenResourceExists_whenRetrievingResource_thenEtagIsAlsoReturned() { - // Given - final String uriOfResource = createAsUri(); - - // When - final Response findOneResponse = RestAssured.given() - .header("Accept", "application/json") - .get(uriOfResource); - - // Then - assertNotNull(findOneResponse.getHeader(HttpHeaders.ETAG)); - } - - @Test - public void givenResourceWasRetrieved_whenRetrievingAgainWithEtag_thenNotModifiedReturned() { - // Given - final String uriOfResource = createAsUri(); - final Response findOneResponse = RestAssured.given() - .header("Accept", "application/json") - .get(uriOfResource); - final String etagValue = findOneResponse.getHeader(HttpHeaders.ETAG); - - // When - final Response secondFindOneResponse = RestAssured.given() - .header("Accept", "application/json") - .headers("If-None-Match", etagValue) - .get(uriOfResource); - - // Then - assertTrue(secondFindOneResponse.getStatusCode() == 304); - } - - @Test - @Ignore("No Update operation yet") - public void givenResourceWasRetrievedThenModified_whenRetrievingAgainWithEtag_thenResourceIsReturned() { - // Given - final String uriOfResource = createAsUri(); - final Response findOneResponse = RestAssured.given() - .header("Accept", "application/json") - .get(uriOfResource); - final String etagValue = findOneResponse.getHeader(HttpHeaders.ETAG); - - // existingResource.setName(randomAlphabetic(6)); - // getApi().update(existingResource.setName("randomString")); - - // When - final Response secondFindOneResponse = RestAssured.given() - .header("Accept", "application/json") - .headers("If-None-Match", etagValue) - .get(uriOfResource); - - // Then - assertTrue(secondFindOneResponse.getStatusCode() == 200); - } - - @Test - @Ignore("Not Yet Implemented By Spring - https://jira.springsource.org/browse/SPR-10164") - public void givenResourceExists_whenRetrievedWithIfMatchIncorrectEtag_then412IsReceived() { - // Given - final String uriOfResource = createAsUri(); - - // When - final Response findOneResponse = RestAssured.given() - .header("Accept", "application/json") - .headers("If-Match", randomAlphabetic(8)) - .get(uriOfResource); - - // Then - assertTrue(findOneResponse.getStatusCode() == 412); - } - - // find - one - - // find - all -} diff --git a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractLiveTest.java deleted file mode 100644 index 5aa0f5a768..0000000000 --- a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractLiveTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.baeldung.common.web; - -import static org.baeldung.Consts.APPLICATION_PORT; -import io.restassured.RestAssured; -import io.restassured.response.Response; - -import java.io.Serializable; - -import org.baeldung.test.IMarshaller; -import org.springframework.beans.factory.annotation.Autowired; - -import com.google.common.base.Preconditions; -import com.google.common.net.HttpHeaders; - -public abstract class AbstractLiveTest { - - protected final Class clazz; - - @Autowired - protected IMarshaller marshaller; - - public AbstractLiveTest(final Class clazzToSet) { - super(); - - Preconditions.checkNotNull(clazzToSet); - clazz = clazzToSet; - } - - // template method - - public abstract void create(); - - public abstract String createAsUri(); - - protected final void create(final T resource) { - createAsUri(resource); - } - - protected final String createAsUri(final T resource) { - final Response response = createAsResponse(resource); - Preconditions.checkState(response.getStatusCode() == 201, "create operation: " + response.getStatusCode()); - - final String locationOfCreatedResource = response.getHeader(HttpHeaders.LOCATION); - Preconditions.checkNotNull(locationOfCreatedResource); - return locationOfCreatedResource; - } - - final Response createAsResponse(final T resource) { - Preconditions.checkNotNull(resource); - - final String resourceAsString = marshaller.encode(resource); - return RestAssured.given() - .contentType(marshaller.getMime()) - .body(resourceAsString) - .post(getURL()); - } - - // - - protected String getURL() { - return "http://localhost:" + APPLICATION_PORT + "/spring-rest-full/auth/foos"; - } - -} diff --git a/spring-rest-full/src/test/java/org/baeldung/spring/ConfigIntegrationTest.java b/spring-rest-full/src/test/java/org/baeldung/spring/ConfigIntegrationTest.java deleted file mode 100644 index 77603da0dd..0000000000 --- a/spring-rest-full/src/test/java/org/baeldung/spring/ConfigIntegrationTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.baeldung.spring; - -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; - -@Configuration -@ComponentScan("org.baeldung.test") -public class ConfigIntegrationTest extends WebMvcConfigurerAdapter { - - public ConfigIntegrationTest() { - super(); - } - - // API - -} \ No newline at end of file diff --git a/spring-rest-full/src/test/java/org/baeldung/test/IMarshaller.java b/spring-rest-full/src/test/java/org/baeldung/test/IMarshaller.java deleted file mode 100644 index 1eefbe8789..0000000000 --- a/spring-rest-full/src/test/java/org/baeldung/test/IMarshaller.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.baeldung.test; - -import java.util.List; - -public interface IMarshaller { - - String encode(final T entity); - - T decode(final String entityAsString, final Class clazz); - - List decodeList(final String entitiesAsString, final Class clazz); - - String getMime(); - -} diff --git a/spring-rest-full/src/test/java/org/baeldung/test/JacksonMarshaller.java b/spring-rest-full/src/test/java/org/baeldung/test/JacksonMarshaller.java deleted file mode 100644 index 912ad89ed7..0000000000 --- a/spring-rest-full/src/test/java/org/baeldung/test/JacksonMarshaller.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.baeldung.test; - -import java.io.IOException; -import java.util.List; - -import org.baeldung.persistence.model.Foo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.MediaType; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Preconditions; - -public final class JacksonMarshaller implements IMarshaller { - private final Logger logger = LoggerFactory.getLogger(JacksonMarshaller.class); - - private final ObjectMapper objectMapper; - - public JacksonMarshaller() { - super(); - - objectMapper = new ObjectMapper(); - } - - // API - - @Override - public final String encode(final T resource) { - Preconditions.checkNotNull(resource); - String entityAsJSON = null; - try { - entityAsJSON = objectMapper.writeValueAsString(resource); - } catch (final IOException ioEx) { - logger.error("", ioEx); - } - - return entityAsJSON; - } - - @Override - public final T decode(final String resourceAsString, final Class clazz) { - Preconditions.checkNotNull(resourceAsString); - - T entity = null; - try { - entity = objectMapper.readValue(resourceAsString, clazz); - } catch (final IOException ioEx) { - logger.error("", ioEx); - } - - return entity; - } - - @SuppressWarnings("unchecked") - @Override - public final List decodeList(final String resourcesAsString, final Class clazz) { - Preconditions.checkNotNull(resourcesAsString); - - List entities = null; - try { - if (clazz.equals(Foo.class)) { - entities = objectMapper.readValue(resourcesAsString, new TypeReference>() { - // ... - }); - } else { - entities = objectMapper.readValue(resourcesAsString, List.class); - } - } catch (final IOException ioEx) { - logger.error("", ioEx); - } - - return entities; - } - - @Override - public final String getMime() { - return MediaType.APPLICATION_JSON.toString(); - } - -} diff --git a/spring-rest-full/src/test/java/org/baeldung/test/TestMarshallerFactory.java b/spring-rest-full/src/test/java/org/baeldung/test/TestMarshallerFactory.java deleted file mode 100644 index 11273276cd..0000000000 --- a/spring-rest-full/src/test/java/org/baeldung/test/TestMarshallerFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.baeldung.test; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; -import org.springframework.core.env.Environment; -import org.springframework.stereotype.Component; - -@Component -@Profile("test") -public class TestMarshallerFactory implements FactoryBean { - - @Autowired - private Environment env; - - public TestMarshallerFactory() { - super(); - } - - // API - - @Override - public IMarshaller getObject() { - final String testMime = env.getProperty("test.mime"); - if (testMime != null) { - switch (testMime) { - case "json": - return new JacksonMarshaller(); - case "xml": - return new XStreamMarshaller(); - default: - throw new IllegalStateException(); - } - } - - return new JacksonMarshaller(); - } - - @Override - public Class getObjectType() { - return IMarshaller.class; - } - - @Override - public boolean isSingleton() { - return true; - } -} \ No newline at end of file diff --git a/spring-rest-full/src/test/java/org/baeldung/web/FooLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/web/FooLiveTest.java deleted file mode 100644 index 65564a6845..0000000000 --- a/spring-rest-full/src/test/java/org/baeldung/web/FooLiveTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.baeldung.web; - -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; - -import org.baeldung.common.web.AbstractBasicLiveTest; -import org.baeldung.persistence.model.Foo; -import org.baeldung.spring.ConfigIntegrationTest; -import org.junit.runner.RunWith; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.AnnotationConfigContextLoader; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ConfigIntegrationTest.class }, loader = AnnotationConfigContextLoader.class) -@ActiveProfiles("test") -public class FooLiveTest extends AbstractBasicLiveTest { - - public FooLiveTest() { - super(Foo.class); - } - - // API - - @Override - public final void create() { - create(new Foo(randomAlphabetic(6))); - } - - @Override - public final String createAsUri() { - return createAsUri(new Foo(randomAlphabetic(6))); - } - -} diff --git a/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java deleted file mode 100644 index 663935e72f..0000000000 --- a/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.baeldung.web; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@RunWith(Suite.class) -@Suite.SuiteClasses({ -// @formatter:off - FooLiveTest.class -}) // -public class LiveTestSuiteLiveTest { - -} diff --git a/spring-rest-simple/README.md b/spring-rest-simple/README.md index 179e556202..882d0ac301 100644 --- a/spring-rest-simple/README.md +++ b/spring-rest-simple/README.md @@ -3,6 +3,5 @@ - [Guide to UriComponentsBuilder in Spring](http://www.baeldung.com/spring-uricomponentsbuilder) - [Returning Custom Status Codes from Spring Controllers](http://www.baeldung.com/spring-mvc-controller-custom-http-status-code) - [Spring RequestMapping](http://www.baeldung.com/spring-requestmapping) -- [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring) - [Spring and Apache FileUpload](http://www.baeldung.com/spring-apache-file-upload) - [Test a REST API with curl](http://www.baeldung.com/curl-rest) diff --git a/spring-rest-simple/src/main/java/org/baeldung/web/controller/FooController.java b/spring-rest-simple/src/main/java/org/baeldung/web/controller/FooController.java index e8cb218258..c68d586667 100644 --- a/spring-rest-simple/src/main/java/org/baeldung/web/controller/FooController.java +++ b/spring-rest-simple/src/main/java/org/baeldung/web/controller/FooController.java @@ -2,12 +2,21 @@ package org.baeldung.web.controller; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import java.util.List; + import org.baeldung.web.dto.Foo; import org.baeldung.web.dto.FooProtos; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +import com.google.common.collect.Lists; @Controller public class FooController { @@ -16,6 +25,12 @@ public class FooController { super(); } + @RequestMapping(method = RequestMethod.GET, value = "/foos") + @ResponseBody + public List findListOfFoo() { + return Lists.newArrayList(new Foo(1, randomAlphabetic(4))); + } + // API - read @RequestMapping(method = RequestMethod.GET, value = "/foos/{id}") @@ -32,6 +47,27 @@ public class FooController { public Foo updateFoo(@PathVariable("id") final String id, @RequestBody final Foo foo) { return foo; } + + @RequestMapping(method = RequestMethod.PATCH, value = "/foos/{id}") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public Foo patchFoo(@PathVariable("id") final String id, @RequestBody final Foo foo) { + return foo; + } + + @RequestMapping(method = RequestMethod.POST, value = "/foos") + @ResponseStatus(HttpStatus.CREATED) + @ResponseBody + public Foo postFoo(@RequestBody final Foo foo) { + return foo; + } + + @RequestMapping(method = RequestMethod.HEAD, value = "/foos") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public Foo headFoo() { + return new Foo(1, randomAlphabetic(4)); + } @RequestMapping(method = RequestMethod.GET, value = "/foos/{id}", produces = { "application/x-protobuf" }) @ResponseBody diff --git a/spring-rest-simple/src/test/java/org/baeldung/web/test/RestTemplateBasicLiveTest.java b/spring-rest-simple/src/test/java/org/baeldung/web/test/RestTemplateBasicLiveTest.java new file mode 100644 index 0000000000..e213d0255f --- /dev/null +++ b/spring-rest-simple/src/test/java/org/baeldung/web/test/RestTemplateBasicLiveTest.java @@ -0,0 +1,269 @@ +package org.baeldung.web.test; + +import static org.apache.commons.codec.binary.Base64.encodeBase64; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.Set; + +import org.baeldung.web.dto.Foo; +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RequestCallback; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.google.common.base.Charsets; + +public class RestTemplateBasicLiveTest { + + private RestTemplate restTemplate; + private static final String fooResourceUrl = "http://localhost:8082/spring-rest/foos"; + + @Before + public void beforeTest() { + restTemplate = new RestTemplate(); + // restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter())); + } + + // GET + + @Test + public void givenResourceUrl_whenSendGetForRequestEntity_thenStatusOk() throws IOException { + final ResponseEntity response = restTemplate.getForEntity(fooResourceUrl + "/1", Foo.class); + + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenResourceUrl_whenSendGetForRequestEntity_thenBodyCorrect() throws IOException { + final RestTemplate template = new RestTemplate(); + final ResponseEntity response = template.getForEntity(fooResourceUrl + "/1", String.class); + + final ObjectMapper mapper = new XmlMapper(); + final JsonNode root = mapper.readTree(response.getBody()); + final JsonNode name = root.path("name"); + assertThat(name.asText(), notNullValue()); + } + + @Test + public void givenResourceUrl_whenRetrievingResource_thenCorrect() throws IOException { + final Foo foo = restTemplate.getForObject(fooResourceUrl + "/1", Foo.class); + + assertThat(foo.getName(), notNullValue()); + assertThat(foo.getId(), is(1L)); + } + + // HEAD, OPTIONS + + @Test + public void givenFooService_whenCallHeadForHeaders_thenReceiveAllHeadersForThatResource() { + final HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl); + assertTrue(httpHeaders.getContentType() + .includes(MediaType.APPLICATION_JSON)); + } + + // POST + + @Test + public void givenFooService_whenPostForObject_thenCreatedObjectIsReturned() { + final HttpEntity request = new HttpEntity<>(new Foo("bar")); + final Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.class); + assertThat(foo, notNullValue()); + assertThat(foo.getName(), is("bar")); + } + + @Test + public void givenFooService_whenPostForLocation_thenCreatedLocationIsReturned() { + final HttpEntity request = new HttpEntity<>(new Foo("bar")); + final URI location = restTemplate.postForLocation(fooResourceUrl, request); + assertThat(location, notNullValue()); + } + + @Test + public void givenFooService_whenPostResource_thenResourceIsCreated() { + final Foo foo = new Foo("bar"); + final ResponseEntity response = restTemplate.postForEntity(fooResourceUrl, foo, Foo.class); + + assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); + final Foo fooResponse = response.getBody(); + assertThat(fooResponse, notNullValue()); + assertThat(fooResponse.getName(), is("bar")); + } + + @Test + public void givenFooService_whenCallOptionsForAllow_thenReceiveValueOfAllowHeader() { + final Set optionsForAllow = restTemplate.optionsForAllow(fooResourceUrl); + final HttpMethod[] supportedMethods = { HttpMethod.GET, HttpMethod.POST, HttpMethod.HEAD }; + + assertTrue(optionsForAllow.containsAll(Arrays.asList(supportedMethods))); + } + + // PUT + + @Test + public void givenFooService_whenPutExistingEntity_thenItIsUpdated() { + final HttpHeaders headers = prepareBasicAuthHeaders(); + final HttpEntity request = new HttpEntity<>(new Foo("bar"), headers); + + // Create Resource + final ResponseEntity createResponse = restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class); + + // Update Resource + final Foo updatedInstance = new Foo("newName"); + updatedInstance.setId(createResponse.getBody() + .getId()); + final String resourceUrl = fooResourceUrl + '/' + createResponse.getBody() + .getId(); + final HttpEntity requestUpdate = new HttpEntity<>(updatedInstance, headers); + restTemplate.exchange(resourceUrl, HttpMethod.PUT, requestUpdate, Void.class); + + // Check that Resource was updated + final ResponseEntity updateResponse = restTemplate.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class); + final Foo foo = updateResponse.getBody(); + assertThat(foo.getName(), is(updatedInstance.getName())); + } + + @Test + public void givenFooService_whenPutExistingEntityWithCallback_thenItIsUpdated() { + final HttpHeaders headers = prepareBasicAuthHeaders(); + final HttpEntity request = new HttpEntity<>(new Foo("bar"), headers); + + // Create entity + ResponseEntity response = restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class); + assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); + + // Update entity + final Foo updatedInstance = new Foo("newName"); + updatedInstance.setId(response.getBody() + .getId()); + final String resourceUrl = fooResourceUrl + '/' + response.getBody() + .getId(); + restTemplate.execute(resourceUrl, HttpMethod.PUT, requestCallback(updatedInstance), clientHttpResponse -> null); + + // Check that entity was updated + response = restTemplate.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class); + final Foo foo = response.getBody(); + assertThat(foo.getName(), is(updatedInstance.getName())); + } + + // PATCH + + @Test + public void givenFooService_whenPatchExistingEntity_thenItIsUpdated() { + final HttpHeaders headers = prepareBasicAuthHeaders(); + final HttpEntity request = new HttpEntity<>(new Foo("bar"), headers); + + // Create Resource + final ResponseEntity createResponse = restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class); + + // Update Resource + final Foo updatedResource = new Foo("newName"); + updatedResource.setId(createResponse.getBody() + .getId()); + final String resourceUrl = fooResourceUrl + '/' + createResponse.getBody() + .getId(); + final HttpEntity requestUpdate = new HttpEntity<>(updatedResource, headers); + final ClientHttpRequestFactory requestFactory = getSimpleClientHttpRequestFactory(); + final RestTemplate template = new RestTemplate(requestFactory); + template.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter())); + template.patchForObject(resourceUrl, requestUpdate, Void.class); + + // Check that Resource was updated + final ResponseEntity updateResponse = restTemplate.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class); + final Foo foo = updateResponse.getBody(); + assertThat(foo.getName(), is(updatedResource.getName())); + } + + // DELETE + + @Test + public void givenFooService_whenCallDelete_thenEntityIsRemoved() { + final Foo foo = new Foo("remove me"); + final ResponseEntity response = restTemplate.postForEntity(fooResourceUrl, foo, Foo.class); + assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); + + final String entityUrl = fooResourceUrl + "/" + response.getBody() + .getId(); + restTemplate.delete(entityUrl); + try { + restTemplate.getForEntity(entityUrl, Foo.class); + fail(); + } catch (final HttpClientErrorException ex) { + assertThat(ex.getStatusCode(), is(HttpStatus.NOT_FOUND)); + } + } + + @Test + public void givenFooService_whenFormSubmit_thenResourceIsCreated() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + MultiValueMap map= new LinkedMultiValueMap<>(); + map.add("id", "1"); + + HttpEntity> request = new HttpEntity<>(map, headers); + + ResponseEntity response = restTemplate.postForEntity( fooResourceUrl+"/form", request , String.class); + + assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); + final String fooResponse = response.getBody(); + assertThat(fooResponse, notNullValue()); + assertThat(fooResponse, is("1")); + } + + private HttpHeaders prepareBasicAuthHeaders() { + final HttpHeaders headers = new HttpHeaders(); + final String encodedLogPass = getBase64EncodedLogPass(); + headers.add(HttpHeaders.AUTHORIZATION, "Basic " + encodedLogPass); + return headers; + } + + private String getBase64EncodedLogPass() { + final String logPass = "user1:user1Pass"; + final byte[] authHeaderBytes = encodeBase64(logPass.getBytes(Charsets.US_ASCII)); + return new String(authHeaderBytes, Charsets.US_ASCII); + } + + private RequestCallback requestCallback(final Foo updatedInstance) { + return clientHttpRequest -> { + final ObjectMapper mapper = new ObjectMapper(); + mapper.writeValue(clientHttpRequest.getBody(), updatedInstance); + clientHttpRequest.getHeaders() + .add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + clientHttpRequest.getHeaders() + .add(HttpHeaders.AUTHORIZATION, "Basic " + getBase64EncodedLogPass()); + }; + } + + // Simply setting restTemplate timeout using ClientHttpRequestFactory + + ClientHttpRequestFactory getSimpleClientHttpRequestFactory() { + final int timeout = 5; + final HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(); + clientHttpRequestFactory.setConnectTimeout(timeout * 1000); + return clientHttpRequestFactory; + } + +} diff --git a/spring-rest-simple/src/test/java/org/baeldung/web/test/TestRestTemplateBasicLiveTest.java b/spring-rest-simple/src/test/java/org/baeldung/web/test/TestRestTemplateBasicLiveTest.java new file mode 100644 index 0000000000..b920ed38da --- /dev/null +++ b/spring-rest-simple/src/test/java/org/baeldung/web/test/TestRestTemplateBasicLiveTest.java @@ -0,0 +1,122 @@ +package org.baeldung.web.test; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import okhttp3.Request; +import okhttp3.RequestBody; + +public class TestRestTemplateBasicLiveTest { + + private RestTemplate restTemplate; + + private static final String FOO_RESOURCE_URL = "http://localhost:" + 8082 + "/spring-rest/foos"; + private static final String URL_SECURED_BY_AUTHENTICATION = "http://httpbin.org/basic-auth/user/passwd"; + private static final String BASE_URL = "http://localhost:" + 8082 + "/spring-rest"; + + @Before + public void beforeTest() { + restTemplate = new RestTemplate(); + } + + // GET + @Test + public void givenTestRestTemplate_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate(); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenRestTemplateWrapper_whenSendGetForEntity_thenStatusOk() { + RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); + restTemplateBuilder.configure(restTemplate); + TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenRestTemplateBuilderWrapper_whenSendGetForEntity_thenStatusOk() { + RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); + restTemplateBuilder.build(); + TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenRestTemplateWrapperWithCredentials_whenSendGetForEntity_thenStatusOk() { + RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); + restTemplateBuilder.configure(restTemplate); + TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder, "user", "passwd"); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION, + String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenTestRestTemplateWithCredentials_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd"); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION, + String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenTestRestTemplateWithBasicAuth_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate(); + ResponseEntity response = testRestTemplate.withBasicAuth("user", "passwd"). + getForEntity(URL_SECURED_BY_AUTHENTICATION, String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenTestRestTemplateWithCredentialsAndEnabledCookies_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd", TestRestTemplate. + HttpClientOption.ENABLE_COOKIES); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION, + String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + // HEAD + @Test + public void givenFooService_whenCallHeadForHeaders_thenReceiveAllHeaders() { + TestRestTemplate testRestTemplate = new TestRestTemplate(); + final HttpHeaders httpHeaders = testRestTemplate.headForHeaders(FOO_RESOURCE_URL); + assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON)); + } + + // POST + @Test + public void givenService_whenPostForObject_thenCreatedObjectIsReturned() { + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd"); + final RequestBody body = RequestBody.create(okhttp3.MediaType.parse("text/html; charset=utf-8"), + "{\"id\":1,\"name\":\"Jim\"}"); + final Request request = new Request.Builder().url(BASE_URL + "/users/detail").post(body).build(); + testRestTemplate.postForObject(URL_SECURED_BY_AUTHENTICATION, request, String.class); + } + + // PUT + @Test + public void givenService_whenPutForObject_thenCreatedObjectIsReturned() { + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd"); + final RequestBody body = RequestBody.create(okhttp3.MediaType.parse("text/html; charset=utf-8"), + "{\"id\":1,\"name\":\"Jim\"}"); + final Request request = new Request.Builder().url(BASE_URL + "/users/detail").post(body).build(); + testRestTemplate.put(URL_SECURED_BY_AUTHENTICATION, request, String.class); + } + +} diff --git a/spring-rest/README.md b/spring-rest/README.md index 4921ab012c..9a2c1fd96c 100644 --- a/spring-rest/README.md +++ b/spring-rest/README.md @@ -5,7 +5,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: - [Spring @RequestMapping](http://www.baeldung.com/spring-requestmapping) -- [Http Message Converters with the Spring Framework](http://www.baeldung.com/spring-httpmessageconverter-rest) - [Returning Custom Status Codes from Spring Controllers](http://www.baeldung.com/spring-mvc-controller-custom-http-status-code) - [A Guide to OkHttp](http://www.baeldung.com/guide-to-okhttp) - [Binary Data Formats in a Spring REST API](http://www.baeldung.com/spring-rest-api-with-binary-data-formats) diff --git a/spring-rest/pom.xml b/spring-rest/pom.xml index 5c88697cef..36934af101 100644 --- a/spring-rest/pom.xml +++ b/spring-rest/pom.xml @@ -52,10 +52,6 @@ org.springframework spring-webmvc - - org.springframework - spring-oxm - commons-fileupload commons-fileupload @@ -86,12 +82,6 @@ jackson-dataformat-xml - - com.thoughtworks.xstream - xstream - ${xstream.version} - - com.google.guava @@ -281,7 +271,6 @@ 1.4 3.1.0 3.5 - 1.4.9 20.0 diff --git a/spring-rest/src/main/java/com/baeldung/produceimage/README.md b/spring-rest/src/main/java/com/baeldung/produceimage/README.md index acd546598d..4aeadea546 100644 --- a/spring-rest/src/main/java/com/baeldung/produceimage/README.md +++ b/spring-rest/src/main/java/com/baeldung/produceimage/README.md @@ -1,3 +1,3 @@ ### Relevant articles -- [Returning an Image or a File with Spring](http://www.baeldung.com/spring-controller-return-image-file) +- [Download an Image or a File with Spring MVC](http://www.baeldung.com/spring-controller-return-image-file) diff --git a/spring-rest/src/main/java/com/baeldung/sampleapp/config/WebConfig.java b/spring-rest/src/main/java/com/baeldung/sampleapp/config/WebConfig.java index d5209a520b..dc4fb9c695 100644 --- a/spring-rest/src/main/java/com/baeldung/sampleapp/config/WebConfig.java +++ b/spring-rest/src/main/java/com/baeldung/sampleapp/config/WebConfig.java @@ -8,8 +8,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.http.converter.xml.MarshallingHttpMessageConverter; -import org.springframework.oxm.xstream.XStreamMarshaller; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -33,22 +31,12 @@ public class WebConfig implements WebMvcConfigurer { .dateFormat(new SimpleDateFormat("dd-MM-yyyy hh:mm")); messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build())); // messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build())); - - // messageConverters.add(createXmlHttpMessageConverter()); + // messageConverters.add(new MappingJackson2HttpMessageConverter()); // messageConverters.add(new ProtobufHttpMessageConverter()); } - private HttpMessageConverter createXmlHttpMessageConverter() { - final MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter(); - - final XStreamMarshaller xstreamMarshaller = new XStreamMarshaller(); - xmlConverter.setMarshaller(xstreamMarshaller); - xmlConverter.setUnmarshaller(xstreamMarshaller); - - return xmlConverter; - } */ } diff --git a/spring-rest/src/main/java/com/baeldung/sampleapp/web/dto/Foo.java b/spring-rest/src/main/java/com/baeldung/sampleapp/web/dto/Foo.java index 186df8e678..de1d76ed92 100644 --- a/spring-rest/src/main/java/com/baeldung/sampleapp/web/dto/Foo.java +++ b/spring-rest/src/main/java/com/baeldung/sampleapp/web/dto/Foo.java @@ -1,8 +1,5 @@ package com.baeldung.sampleapp.web.dto; -import com.thoughtworks.xstream.annotations.XStreamAlias; - -@XStreamAlias("Foo") public class Foo { private long id; private String name; diff --git a/spring-rest/src/main/webapp/WEB-INF/api-servlet.xml b/spring-rest/src/main/webapp/WEB-INF/api-servlet.xml index ddb9c91792..3d83ebf6c9 100644 --- a/spring-rest/src/main/webapp/WEB-INF/api-servlet.xml +++ b/spring-rest/src/main/webapp/WEB-INF/api-servlet.xml @@ -10,21 +10,11 @@ - - - diff --git a/spring-resttemplate/README.md b/spring-resttemplate/README.md index 1c8ddf73f9..353e9f955e 100644 --- a/spring-resttemplate/README.md +++ b/spring-resttemplate/README.md @@ -4,7 +4,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: -- [Spring RestTemplate Tutorial](http://www.baeldung.com/rest-template) +- [The Guide to RestTemplate](http://www.baeldung.com/rest-template) - [Exploring the Spring Boot TestRestTemplate](http://www.baeldung.com/spring-boot-testresttemplate) - [Spring RestTemplate Error Handling](http://www.baeldung.com/spring-rest-template-error-handling) - [Configure a RestTemplate with RestTemplateBuilder](http://www.baeldung.com/spring-rest-template-builder) diff --git a/spring-resttemplate/pom.xml b/spring-resttemplate/pom.xml index 9a0978f120..06d4eed9fc 100644 --- a/spring-resttemplate/pom.xml +++ b/spring-resttemplate/pom.xml @@ -25,6 +25,10 @@ org.springframework.boot spring-boot-devtools + + org.springframework.boot + spring-boot-starter-web + org.springframework.boot spring-boot-starter-test diff --git a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/RestTemplateConfigurationApplication.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/RestTemplateConfigurationApplication.java similarity index 89% rename from spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/RestTemplateConfigurationApplication.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/RestTemplateConfigurationApplication.java index 76fc346aca..9a361e92c9 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/RestTemplateConfigurationApplication.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/RestTemplateConfigurationApplication.java @@ -1,4 +1,4 @@ -package org.baeldung.resttemplate.configuration; +package org.baeldung.resttemplate; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; diff --git a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/FooController.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/FooController.java new file mode 100644 index 0000000000..a9d400b199 --- /dev/null +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/FooController.java @@ -0,0 +1,124 @@ +package org.baeldung.resttemplate.configuration; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import java.net.URI; +import java.util.Collection; +import java.util.Map; + +import org.baeldung.resttemplate.web.dto.Foo; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +@Controller +public class FooController { + + private Map fooRepository = Maps.newHashMap(ImmutableMap.of(1L, new Foo(1L, randomAlphabetic(4)))); + + public FooController() { + super(); + } + + @RequestMapping(method = RequestMethod.GET, value = "/foos") + @ResponseBody + public Collection findListOfFoo() { + return fooRepository.values(); + } + + // API - read + + @RequestMapping(method = RequestMethod.GET, value = "/foos/{id}") + @ResponseBody + public Foo findById(@PathVariable final long id) throws HttpClientErrorException { + Foo foo = fooRepository.get(id); + + if (foo == null) { + throw new HttpClientErrorException(HttpStatus.NOT_FOUND); + } else { + return foo; + } + } + + // API - write + + @RequestMapping(method = RequestMethod.PUT, value = "/foos/{id}") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public Foo updateFoo(@PathVariable("id") final long id, @RequestBody final Foo foo) { + fooRepository.put(id, foo); + return foo; + } + + @RequestMapping(method = RequestMethod.PATCH, value = "/foos/{id}") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public Foo patchFoo(@PathVariable("id") final long id, @RequestBody final Foo foo) { + fooRepository.put(id, foo); + return foo; + } + + @RequestMapping(method = RequestMethod.POST, value = "/foos") + @ResponseStatus(HttpStatus.CREATED) + @ResponseBody + public ResponseEntity postFoo(@RequestBody final Foo foo) { + + fooRepository.put(foo.getId(), foo); + final URI location = ServletUriComponentsBuilder + .fromCurrentServletMapping() + .path("/foos/{id}") + .build() + .expand(foo.getId()) + .toUri(); + + final HttpHeaders headers = new HttpHeaders(); + headers.setLocation(location); + + final ResponseEntity entity = new ResponseEntity(foo, headers, HttpStatus.CREATED); + return entity; + } + + @RequestMapping(method = RequestMethod.HEAD, value = "/foos") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public Foo headFoo() { + return new Foo(1, randomAlphabetic(4)); + } + + @RequestMapping(method = RequestMethod.POST, value = "/foos/new") + @ResponseStatus(HttpStatus.CREATED) + @ResponseBody + public Foo createFoo(@RequestBody final Foo foo) { + fooRepository.put(foo.getId(), foo); + return foo; + } + + @RequestMapping(method = RequestMethod.DELETE, value = "/foos/{id}") + @ResponseStatus(HttpStatus.OK) + @ResponseBody + public long deleteFoo(@PathVariable final long id) { + fooRepository.remove(id); + return id; + } + + @RequestMapping(method = RequestMethod.POST, value = "/foos/form") + @ResponseStatus(HttpStatus.CREATED) + @ResponseBody + public String submitFoo(@RequestParam("id") String id) { + return id; + } + +} diff --git a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/SpringConfig.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/SpringConfig.java index 4e121185b1..966d5bcaa1 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/SpringConfig.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/configuration/SpringConfig.java @@ -7,6 +7,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; +import org.springframework.web.client.RestTemplate; @Configuration @EnableAutoConfiguration @@ -25,4 +26,8 @@ public class SpringConfig { return new RestTemplateBuilder(customRestTemplateCustomizer()); } + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } } diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/dto/Foo.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/dto/Foo.java similarity index 93% rename from spring-resttemplate/src/main/java/org/baeldung/web/dto/Foo.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/dto/Foo.java index 240b368b50..ed0a42c429 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/dto/Foo.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/dto/Foo.java @@ -1,4 +1,4 @@ -package org.baeldung.web.dto; +package org.baeldung.resttemplate.web.dto; import com.thoughtworks.xstream.annotations.XStreamAlias; diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/exception/NotFoundException.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/exception/NotFoundException.java similarity index 55% rename from spring-resttemplate/src/main/java/org/baeldung/web/exception/NotFoundException.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/exception/NotFoundException.java index 5b4d80a659..3e606e9314 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/exception/NotFoundException.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/exception/NotFoundException.java @@ -1,4 +1,4 @@ -package org.baeldung.web.exception; +package org.baeldung.resttemplate.web.exception; public class NotFoundException extends RuntimeException { } diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/handler/RestTemplateResponseErrorHandler.java similarity index 82% rename from spring-resttemplate/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/handler/RestTemplateResponseErrorHandler.java index b1b87e89a5..214de38746 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/handler/RestTemplateResponseErrorHandler.java @@ -1,13 +1,14 @@ -package org.baeldung.web.handler; +package org.baeldung.resttemplate.web.handler; -import org.baeldung.web.exception.NotFoundException; +import java.io.IOException; + +import org.baeldung.resttemplate.web.exception.NotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.ResponseErrorHandler; -import java.io.IOException; - @Component public class RestTemplateResponseErrorHandler implements ResponseErrorHandler { @@ -31,6 +32,7 @@ public class RestTemplateResponseErrorHandler .getStatusCode() .series() == HttpStatus.Series.SERVER_ERROR) { //Handle SERVER_ERROR + throw new HttpClientErrorException(httpResponse.getStatusCode()); } else if (httpResponse .getStatusCode() .series() == HttpStatus.Series.CLIENT_ERROR) { diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/model/Bar.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Bar.java similarity index 87% rename from spring-resttemplate/src/main/java/org/baeldung/web/model/Bar.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Bar.java index 474e2070a5..cf5279697f 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/model/Bar.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Bar.java @@ -1,4 +1,4 @@ -package org.baeldung.web.model; +package org.baeldung.resttemplate.web.model; public class Bar { private String id; diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/model/Employee.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Employee.java similarity index 95% rename from spring-resttemplate/src/main/java/org/baeldung/web/model/Employee.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Employee.java index 7cab4a0430..a9b84a77b4 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/model/Employee.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/model/Employee.java @@ -1,4 +1,4 @@ -package org.baeldung.web.model; +package org.baeldung.resttemplate.web.model; import java.util.Date; import java.util.Objects; diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/service/BarConsumerService.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/BarConsumerService.java similarity index 78% rename from spring-resttemplate/src/main/java/org/baeldung/web/service/BarConsumerService.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/BarConsumerService.java index 0bf24bd480..54a66ea591 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/service/BarConsumerService.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/BarConsumerService.java @@ -1,7 +1,7 @@ -package org.baeldung.web.service; +package org.baeldung.resttemplate.web.service; -import org.baeldung.web.handler.RestTemplateResponseErrorHandler; -import org.baeldung.web.model.Bar; +import org.baeldung.resttemplate.web.handler.RestTemplateResponseErrorHandler; +import org.baeldung.resttemplate.web.model.Bar; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.stereotype.Service; diff --git a/spring-resttemplate/src/main/java/org/baeldung/web/service/EmployeeService.java b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/EmployeeService.java similarity index 89% rename from spring-resttemplate/src/main/java/org/baeldung/web/service/EmployeeService.java rename to spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/EmployeeService.java index 91614e90ad..c6562fbc94 100644 --- a/spring-resttemplate/src/main/java/org/baeldung/web/service/EmployeeService.java +++ b/spring-resttemplate/src/main/java/org/baeldung/resttemplate/web/service/EmployeeService.java @@ -1,6 +1,6 @@ -package org.baeldung.web.service; +package org.baeldung.resttemplate.web.service; -import org.baeldung.web.model.Employee; +import org.baeldung.resttemplate.web.model.Employee; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-resttemplate/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-resttemplate/src/test/java/org/baeldung/SpringContextIntegrationTest.java index 3a5a20cfeb..3c762b894b 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/SpringContextIntegrationTest.java @@ -1,6 +1,6 @@ package org.baeldung; -import org.baeldung.resttemplate.configuration.RestTemplateConfigurationApplication; +import org.baeldung.resttemplate.RestTemplateConfigurationApplication; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; diff --git a/spring-resttemplate/src/test/java/org/baeldung/client/RestTemplateBasicLiveTest.java b/spring-resttemplate/src/test/java/org/baeldung/client/RestTemplateBasicLiveTest.java index 143aa079d5..a54c124d5f 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/client/RestTemplateBasicLiveTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/client/RestTemplateBasicLiveTest.java @@ -14,7 +14,8 @@ import java.net.URI; import java.util.Arrays; import java.util.Set; -import org.baeldung.web.dto.Foo; +import org.baeldung.resttemplate.web.dto.Foo; +import org.baeldung.resttemplate.web.handler.RestTemplateResponseErrorHandler; import org.junit.Before; import org.junit.Test; import org.springframework.http.HttpEntity; @@ -34,6 +35,7 @@ import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.google.common.base.Charsets; public class RestTemplateBasicLiveTest { @@ -44,6 +46,7 @@ public class RestTemplateBasicLiveTest { @Before public void beforeTest() { restTemplate = new RestTemplate(); + restTemplate.setErrorHandler(new RestTemplateResponseErrorHandler()); // restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter())); } @@ -61,7 +64,7 @@ public class RestTemplateBasicLiveTest { final RestTemplate template = new RestTemplate(); final ResponseEntity response = template.getForEntity(fooResourceUrl + "/1", String.class); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = new XmlMapper(); final JsonNode root = mapper.readTree(response.getBody()); final JsonNode name = root.path("name"); assertThat(name.asText(), notNullValue()); @@ -97,7 +100,7 @@ public class RestTemplateBasicLiveTest { @Test public void givenFooService_whenPostForLocation_thenCreatedLocationIsReturned() { final HttpEntity request = new HttpEntity<>(new Foo("bar")); - final URI location = restTemplate.postForLocation(fooResourceUrl, request); + final URI location = restTemplate.postForLocation(fooResourceUrl, request, Foo.class); assertThat(location, notNullValue()); } @@ -211,7 +214,7 @@ public class RestTemplateBasicLiveTest { restTemplate.getForEntity(entityUrl, Foo.class); fail(); } catch (final HttpClientErrorException ex) { - assertThat(ex.getStatusCode(), is(HttpStatus.NOT_FOUND)); + assertThat(ex.getStatusCode(), is(HttpStatus.INTERNAL_SERVER_ERROR)); } } @@ -221,7 +224,7 @@ public class RestTemplateBasicLiveTest { headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); MultiValueMap map= new LinkedMultiValueMap<>(); - map.add("id", "1"); + map.add("id", "10"); HttpEntity> request = new HttpEntity<>(map, headers); @@ -230,7 +233,7 @@ public class RestTemplateBasicLiveTest { assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); final String fooResponse = response.getBody(); assertThat(fooResponse, notNullValue()); - assertThat(fooResponse, is("1")); + assertThat(fooResponse, is("10")); } private HttpHeaders prepareBasicAuthHeaders() { diff --git a/spring-resttemplate/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java b/spring-resttemplate/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java index e303c75a28..967c4a6188 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java @@ -4,6 +4,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; +import org.baeldung.resttemplate.web.dto.Foo; import org.junit.Before; import org.junit.Test; import org.springframework.boot.test.web.client.TestRestTemplate; @@ -34,7 +35,7 @@ public class TestRestTemplateBasicLiveTest { @Test public void givenTestRestTemplate_whenSendGetForEntity_thenStatusOk() { TestRestTemplate testRestTemplate = new TestRestTemplate(); - ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", Foo.class); assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); } @@ -43,7 +44,7 @@ public class TestRestTemplateBasicLiveTest { RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); restTemplateBuilder.configure(restTemplate); TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder); - ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", Foo.class); assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); } @@ -52,7 +53,7 @@ public class TestRestTemplateBasicLiveTest { RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); restTemplateBuilder.build(); TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder); - ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", Foo.class); assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); } diff --git a/spring-resttemplate/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java b/spring-resttemplate/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java index 2dfa81f441..60069cea71 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java @@ -1,7 +1,8 @@ package org.baeldung.web.handler; -import org.baeldung.web.exception.NotFoundException; -import org.baeldung.web.model.Bar; +import org.baeldung.resttemplate.web.exception.NotFoundException; +import org.baeldung.resttemplate.web.handler.RestTemplateResponseErrorHandler; +import org.baeldung.resttemplate.web.model.Bar; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceMockRestServiceServerUnitTest.java b/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceMockRestServiceServerUnitTest.java index a45af318f1..f93ba71666 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceMockRestServiceServerUnitTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceMockRestServiceServerUnitTest.java @@ -7,7 +7,8 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat import java.net.URI; import org.baeldung.SpringTestConfig; -import org.baeldung.web.model.Employee; +import org.baeldung.resttemplate.web.model.Employee; +import org.baeldung.resttemplate.web.service.EmployeeService; import org.junit.Assert; import org.junit.Before; import org.junit.Test; diff --git a/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceUnitTest.java b/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceUnitTest.java index 23cd9a8fd2..f4b391573a 100644 --- a/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceUnitTest.java +++ b/spring-resttemplate/src/test/java/org/baeldung/web/service/EmployeeServiceUnitTest.java @@ -1,6 +1,7 @@ package org.baeldung.web.service; -import org.baeldung.web.model.Employee; +import org.baeldung.resttemplate.web.model.Employee; +import org.baeldung.resttemplate.web.service.EmployeeService; import org.junit.Assert; import org.junit.Before; import org.junit.Test; diff --git a/spring-security-angular/README.md b/spring-security-angular/README.md index 80312c4bab..49cd8dd62d 100644 --- a/spring-security-angular/README.md +++ b/spring-security-angular/README.md @@ -1,2 +1,3 @@ ### Relevant Articles: - [Spring Security Login Page with Angular](https://www.baeldung.com/spring-security-login-angular) +- [Fixing 401s with CORS Preflights and Spring Security](https://www.baeldung.com/spring-security-cors-preflight) diff --git a/spring-security-client/pom.xml b/spring-security-client/pom.xml new file mode 100644 index 0000000000..96ac837a09 --- /dev/null +++ b/spring-security-client/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + spring-security-client + spring-security-client + pom + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + .. + + + + spring-security-jsp-authentication + spring-security-jsp-authorize + spring-security-jsp-config + spring-security-mvc + spring-security-thymeleaf-authentication + spring-security-thymeleaf-authorize + spring-security-thymeleaf-config + + diff --git a/spring-security-core/README.md b/spring-security-core/README.md index f7b3f6dffe..b38dc061b4 100644 --- a/spring-security-core/README.md +++ b/spring-security-core/README.md @@ -7,6 +7,6 @@ mvn clean install ``` ### Relevant Articles: -- [Intro to @PreFilter and @PostFilter in Spring Security](http://www.baeldung.com/spring-security-prefilter-postfilter) +- [Spring Security – @PreFilter and @PostFilter](http://www.baeldung.com/spring-security-prefilter-postfilter) - [Spring Boot Authentication Auditing Support](http://www.baeldung.com/spring-boot-authentication-audit) - [Introduction to Spring Method Security](http://www.baeldung.com/spring-security-method-security) diff --git a/spring-security-mvc-custom/pom.xml b/spring-security-mvc-custom/pom.xml index 12520a0d01..7c60a8e18a 100644 --- a/spring-security-mvc-custom/pom.xml +++ b/spring-security-mvc-custom/pom.xml @@ -21,17 +21,17 @@ org.springframework.security spring-security-web - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-config - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-taglibs - ${org.springframework.security.version} + ${spring-security.version} @@ -117,7 +117,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson-databind.version} + ${jackson.version} @@ -144,7 +144,7 @@ org.springframework.security spring-security-test - ${org.springframework.security.version} + ${spring-security.version} test @@ -192,9 +192,6 @@ - - 5.0.6.RELEASE - 3.1.0 1.2 @@ -202,7 +199,7 @@ 19.0 3.5 - 2.9.7 + 2.9.7 2.6 diff --git a/spring-security-mvc-jsonview/README.md b/spring-security-mvc-jsonview/README.md new file mode 100644 index 0000000000..35c806e856 --- /dev/null +++ b/spring-security-mvc-jsonview/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Filtering Jackson JSON Output Based on Spring Security Role](https://www.baeldung.com/spring-security-role-filter-json) diff --git a/spring-security-mvc-jsonview/pom.xml b/spring-security-mvc-jsonview/pom.xml index 7f1129128f..b6d3e7e399 100644 --- a/spring-security-mvc-jsonview/pom.xml +++ b/spring-security-mvc-jsonview/pom.xml @@ -38,17 +38,17 @@ org.springframework.security spring-security-web - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-config - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-taglibs - ${org.springframework.security.version} + ${spring-security.version} @@ -133,7 +133,7 @@ org.springframework.security spring-security-test - ${org.springframework.security.version} + ${spring-security.version} test @@ -206,9 +206,6 @@ - - 5.0.5.RELEASE - 3.1.0 1.2 diff --git a/spring-security-mvc-ldap/README.md b/spring-security-mvc-ldap/README.md index fe6a667c40..ac080c138d 100644 --- a/spring-security-mvc-ldap/README.md +++ b/spring-security-mvc-ldap/README.md @@ -6,7 +6,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Article: - [Spring Security - security none, filters none, access permitAll](http://www.baeldung.com/security-none-filters-none-access-permitAll) -- [Spring Security Basic Authentication](http://www.baeldung.com/spring-security-basic-authentication) - [Intro to Spring Security LDAP](http://www.baeldung.com/spring-security-ldap) ### Notes diff --git a/spring-security-mvc-login/pom.xml b/spring-security-mvc-login/pom.xml index bbdff6fc2f..048297bbd4 100644 --- a/spring-security-mvc-login/pom.xml +++ b/spring-security-mvc-login/pom.xml @@ -21,17 +21,17 @@ org.springframework.security spring-security-web - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-config - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-taglibs - ${org.springframework.security.version} + ${spring-security.version} @@ -116,7 +116,7 @@ org.springframework.security spring-security-test - ${org.springframework.security.version} + ${spring-security.version} test @@ -175,7 +175,6 @@ - 5.0.5.RELEASE 3.1.0 diff --git a/spring-security-mvc-session/README.md b/spring-security-mvc-session/README.md index fc44209640..ce40ed5f5f 100644 --- a/spring-security-mvc-session/README.md +++ b/spring-security-mvc-session/README.md @@ -7,7 +7,7 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Articles: - [HttpSessionListener Example – Monitoring](http://www.baeldung.com/httpsessionlistener_with_metrics) -- [Spring Security Session Management](http://www.baeldung.com/spring-security-session) +- [Control the Session with Spring Security](http://www.baeldung.com/spring-security-session) ### Build the Project diff --git a/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/config/WebSocketMessageBrokerConfig.java b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/config/WebSocketMessageBrokerConfig.java new file mode 100644 index 0000000000..f1fb6549ed --- /dev/null +++ b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/config/WebSocketMessageBrokerConfig.java @@ -0,0 +1,67 @@ +package com.baeldung.springsockets.config; + +import java.util.List; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.converter.MessageConverter; +import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; +import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler; +import org.springframework.messaging.simp.config.ChannelRegistration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; + +@Configuration +@EnableWebSocketMessageBroker +public class WebSocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/ws"); + } + + @Override + public void configureMessageBroker(MessageBrokerRegistry config) { + config.setApplicationDestinationPrefixes("/app"); + config.enableSimpleBroker("/topic"); + } + + @Override + public void configureWebSocketTransport(WebSocketTransportRegistration registry) { + // TODO Auto-generated method stub + + } + + @Override + public void configureClientInboundChannel(ChannelRegistration registration) { + // TODO Auto-generated method stub + + } + + @Override + public void configureClientOutboundChannel(ChannelRegistration registration) { + // TODO Auto-generated method stub + + } + + @Override + public void addArgumentResolvers(List argumentResolvers) { + // TODO Auto-generated method stub + + } + + @Override + public void addReturnValueHandlers(List returnValueHandlers) { + // TODO Auto-generated method stub + + } + + @Override + public boolean configureMessageConverters(List messageConverters) { + // TODO Auto-generated method stub + return false; + } + +} \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/RestAPIController.java b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/RestAPIController.java new file mode 100644 index 0000000000..a8d3d5ffae --- /dev/null +++ b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/RestAPIController.java @@ -0,0 +1,17 @@ +package com.baeldung.springsockets.controllers; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping(path = "/rest") +public class RestAPIController { + + @GetMapping(path = "/{name}", produces = "application/json") + public String getGreeting(@PathVariable("name") String name) { + return "{\"greeting\" : \"Hello, " + name + "!\"}"; + } + +} diff --git a/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/WebSocketController.java b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/WebSocketController.java new file mode 100644 index 0000000000..26a67e4236 --- /dev/null +++ b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/controllers/WebSocketController.java @@ -0,0 +1,20 @@ +package com.baeldung.springsockets.controllers; + +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.messaging.handler.annotation.SendTo; +import org.springframework.stereotype.Controller; +import org.springframework.web.util.HtmlUtils; + +import com.baeldung.springsockets.models.Greeting; +import com.baeldung.springsockets.models.Message; + +@Controller +public class WebSocketController { + + @MessageMapping("/hello") + @SendTo("/topic/greetings") + public Greeting greeting(Message message) throws Exception { + return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!"); + } + +} \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Greeting.java b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Greeting.java new file mode 100644 index 0000000000..b6122ac1e7 --- /dev/null +++ b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Greeting.java @@ -0,0 +1,18 @@ +package com.baeldung.springsockets.models; + +public class Greeting { + + private String content; + + public Greeting() { + } + + public Greeting(String content) { + this.content = content; + } + + public String getContent() { + return content; + } + +} diff --git a/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Message.java b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Message.java new file mode 100644 index 0000000000..4dd002606a --- /dev/null +++ b/spring-security-mvc-socket/src/main/java/com/baeldung/springsockets/models/Message.java @@ -0,0 +1,22 @@ +package com.baeldung.springsockets.models; + +public class Message { + + private String name; + + public Message() { + } + + public Message(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/resources/static/rest.html b/spring-security-mvc-socket/src/main/resources/static/rest.html new file mode 100644 index 0000000000..476d053eea --- /dev/null +++ b/spring-security-mvc-socket/src/main/resources/static/rest.html @@ -0,0 +1,39 @@ + + + + Demo for RESTful Service for Comparison to WebSocket + + + + + + + +
+
+
+
+
+ + +
+ +
+
+
+
+
+ + + + + + + + +
Greetings
+
+
+
+ + \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/resources/static/rest.js b/spring-security-mvc-socket/src/main/resources/static/rest.js new file mode 100644 index 0000000000..403cc63585 --- /dev/null +++ b/spring-security-mvc-socket/src/main/resources/static/rest.js @@ -0,0 +1,21 @@ +var request = new XMLHttpRequest() + +function sendName() { + request.open('GET', 'http://localhost:8080/rest/'+$("#name").val(), true) + request.onload = function () { + var data = JSON.parse(this.response) + showGreeting(data.greeting) + } + request.send() +} + +function showGreeting(message) { + $("#greetings").append("" + message + ""); +} + +$(function () { + $("form").on('submit', function (e) { + e.preventDefault(); + }); + $( "#send" ).click(function() { sendName(); }); +}); \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/resources/static/ws.html b/spring-security-mvc-socket/src/main/resources/static/ws.html new file mode 100644 index 0000000000..638b8c0857 --- /dev/null +++ b/spring-security-mvc-socket/src/main/resources/static/ws.html @@ -0,0 +1,39 @@ + + + + Demo for WebSocket for Comparison to RESTful Service + + + + + + + +
+
+
+
+
+ + +
+ +
+
+
+
+
+ + + + + + + + +
Greetings
+
+
+
+ + \ No newline at end of file diff --git a/spring-security-mvc-socket/src/main/resources/static/ws.js b/spring-security-mvc-socket/src/main/resources/static/ws.js new file mode 100644 index 0000000000..538faf4e61 --- /dev/null +++ b/spring-security-mvc-socket/src/main/resources/static/ws.js @@ -0,0 +1,26 @@ +var stompClient = null; + +function connect() { + stompClient = Stomp.client('ws://localhost:8080/ws'); + stompClient.connect({}, function (frame) { + stompClient.subscribe('/topic/greetings', function (response) { + showGreeting(JSON.parse(response.body).content); + }); + }); +} + +function sendName() { + stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()})); +} + +function showGreeting(message) { + $("#greetings").append("" + message + ""); +} + +$(function () { + connect(); + $("form").on('submit', function (e) { + e.preventDefault(); + }); + $( "#send" ).click(function() { sendName(); }); +}); \ No newline at end of file diff --git a/spring-security-rest-basic-auth/README.md b/spring-security-rest-basic-auth/README.md index f92fcfe36b..30da3afbcf 100644 --- a/spring-security-rest-basic-auth/README.md +++ b/spring-security-rest-basic-auth/README.md @@ -6,8 +6,8 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Articles: -- [RestTemplate with Basic Authentication in Spring](http://www.baeldung.com/how-to-use-resttemplate-with-basic-authentication-in-spring) +- [Basic Authentication with the RestTemplate](http://www.baeldung.com/how-to-use-resttemplate-with-basic-authentication-in-spring) - [HttpClient Timeout](http://www.baeldung.com/httpclient-timeout) - [HttpClient with SSL](http://www.baeldung.com/httpclient-ssl) -- [Writing a Custom Filter in Spring Security](http://www.baeldung.com/spring-security-custom-filter) +- [A Custom Filter in the Spring Security Filter Chain](http://www.baeldung.com/spring-security-custom-filter) - [Spring Security Basic Authentication](http://www.baeldung.com/spring-security-basic-authentication) diff --git a/spring-security-rest-basic-auth/pom.xml b/spring-security-rest-basic-auth/pom.xml index 61a144db0c..ca5c4c38e6 100644 --- a/spring-security-rest-basic-auth/pom.xml +++ b/spring-security-rest-basic-auth/pom.xml @@ -96,7 +96,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson-databind.version} + ${jackson.version} diff --git a/spring-security-rest/pom.xml b/spring-security-rest/pom.xml index 37c743e896..24f1c5807a 100644 --- a/spring-security-rest/pom.xml +++ b/spring-security-rest/pom.xml @@ -21,12 +21,12 @@ org.springframework.security spring-security-web - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-config - ${org.springframework.security.version} + ${spring-security.version} @@ -144,7 +144,7 @@ org.springframework.security spring-security-test - ${org.springframework.security.version} + ${spring-security.version} test @@ -274,7 +274,6 @@ - 5.1.0.RELEASE 0.25.0.RELEASE diff --git a/spring-security-sso/pom.xml b/spring-security-sso/pom.xml index 707f516da2..ed8ad87a62 100644 --- a/spring-security-sso/pom.xml +++ b/spring-security-sso/pom.xml @@ -18,12 +18,15 @@ spring-security-sso-auth-server spring-security-sso-ui spring-security-sso-ui-2 + spring-security-sso-kerberos 3.1.0 2.3.3.RELEASE - 2.1.1.RELEASE + 2.1.1.RELEASE + 1.0.1.RELEASE + 2.0.0-M2 diff --git a/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/AuthServerConfig.java b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/AuthServerConfig.java index 07057c3875..0835f3d721 100644 --- a/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/AuthServerConfig.java +++ b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/AuthServerConfig.java @@ -30,7 +30,7 @@ public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { .authorizedGrantTypes("authorization_code") .scopes("user_info") .autoApprove(true) - .redirectUris("http://localhost:8082/ui/login","http://localhost:8083/ui2/login","http://localhost:8082/login") + .redirectUris("http://localhost:8082/ui/login","http://localhost:8083/ui2/login","http://localhost:8082/login","http://www.example.com/") // .accessTokenValiditySeconds(3600) ; // 1 hour } diff --git a/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/SecurityConfig.java b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/SecurityConfig.java index 5cebf4f4d2..2254de8e39 100644 --- a/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/SecurityConfig.java +++ b/spring-security-sso/spring-security-sso-auth-server/src/main/java/org/baeldung/config/SecurityConfig.java @@ -22,7 +22,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .authenticated() .and() .formLogin() - .permitAll(); + .permitAll() + .and().csrf().disable(); } // @formatter:on @Override diff --git a/spring-security-sso/spring-security-sso-auth-server/src/test/java/org/baeldung/UserInfoEndpointLiveTest.java b/spring-security-sso/spring-security-sso-auth-server/src/test/java/org/baeldung/UserInfoEndpointLiveTest.java new file mode 100644 index 0000000000..ffdb1df8fe --- /dev/null +++ b/spring-security-sso/spring-security-sso-auth-server/src/test/java/org/baeldung/UserInfoEndpointLiveTest.java @@ -0,0 +1,51 @@ +package org.baeldung; +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; + +import io.restassured.RestAssured; +import io.restassured.response.Response; + +public class UserInfoEndpointLiveTest { + + @Test + public void givenAccessToken_whenAccessUserInfoEndpoint_thenSuccess() { + String accessToken = obtainAccessTokenUsingAuthorizationCodeFlow("john","123"); + Response response = RestAssured.given().header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken).get("http://localhost:8081/auth/user/me"); + + assertEquals(HttpStatus.OK.value(), response.getStatusCode()); + assertEquals("john", response.jsonPath().get("name")); + } + + private String obtainAccessTokenUsingAuthorizationCodeFlow(String username, String password) { + final String authServerUri = "http://localhost:8081/auth"; + final String redirectUrl = "http://www.example.com/"; + final String authorizeUrl = authServerUri + "/oauth/authorize?response_type=code&client_id=SampleClientId&redirect_uri=" + redirectUrl; + final String tokenUrl = authServerUri + "/oauth/token"; + + // user login + Response response = RestAssured.given().formParams("username", username, "password", password).post(authServerUri + "/login"); + final String cookieValue = response.getCookie("JSESSIONID"); + + // get authorization code + RestAssured.given().cookie("JSESSIONID", cookieValue).get(authorizeUrl); + response = RestAssured.given().cookie("JSESSIONID", cookieValue).post(authorizeUrl); + assertEquals(HttpStatus.FOUND.value(), response.getStatusCode()); + final String location = response.getHeader(HttpHeaders.LOCATION); + final String code = location.substring(location.indexOf("code=") + 5); + + // get access token + Map params = new HashMap(); + params.put("grant_type", "authorization_code"); + params.put("code", code); + params.put("client_id", "SampleClientId"); + params.put("redirect_uri", redirectUrl); + response = RestAssured.given().auth().basic("SampleClientId", "secret").formParams(params).post(tokenUrl); + return response.jsonPath().getString("access_token"); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/.gitignore b/spring-security-sso/spring-security-sso-kerberos/.gitignore new file mode 100644 index 0000000000..a90740bb66 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/.gitignore @@ -0,0 +1,2 @@ +krb-test-workdir/ +/bin/ diff --git a/spring-security-sso/spring-security-sso-kerberos/pom.xml b/spring-security-sso/spring-security-sso-kerberos/pom.xml new file mode 100644 index 0000000000..5fb435a9b9 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + spring-security-sso-kerberos + + + org.baeldung + spring-security-sso + 1.0.0-SNAPSHOT + + + + + + ${basedir}/src/main/resources + true + + **/* + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.7 + + + @ + + false + + + + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.security.kerberos + spring-security-kerberos-web + ${spring-security-kerberos.version} + + + org.springframework.security.kerberos + spring-security-kerberos-client + ${spring-security-kerberos.version} + + + org.apache.directory.jdbm + apacheds-jdbm1 + ${apacheds-jdbm1.version} + + + org.springframework.security.kerberos + spring-security-kerberos-test + + + org.apache.directory.jdbm + apacheds-jdbm1 + + + org.slf4j + slf4j-log4j12 + + + ${spring-security-kerberos.version} + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java new file mode 100644 index 0000000000..a353961854 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java @@ -0,0 +1,20 @@ +package kerberos.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import java.nio.file.Paths; + +@SpringBootApplication +class KerberosClientApp { + + static { + System.setProperty("java.security.krb5.conf", + Paths.get(".\\krb-test-workdir\\krb5.conf").normalize().toAbsolutePath().toString()); + System.setProperty("sun.security.krb5.debug", "true"); + } + + public static void main(String[] args) { + SpringApplication.run(KerberosClientApp.class, args); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleService.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleService.java new file mode 100644 index 0000000000..4145cf0c1a --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleService.java @@ -0,0 +1,26 @@ +package kerberos.client; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +class SampleService { + + @Value("${app.access-url}") + private String endpoint; + + private RestTemplate restTemplate; + + public SampleService(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + void setRestTemplate(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + String getData() { + return restTemplate.getForObject(endpoint, String.class); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/AppConfig.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/AppConfig.java new file mode 100644 index 0000000000..5248f648f9 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/AppConfig.java @@ -0,0 +1,10 @@ +package kerberos.client.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@Configuration +@Import(KerberosConfig.class) +class AppConfig { + +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/KerberosConfig.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/KerberosConfig.java new file mode 100644 index 0000000000..9ab775e95d --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/config/KerberosConfig.java @@ -0,0 +1,22 @@ +package kerberos.client.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.kerberos.client.KerberosRestTemplate; +import org.springframework.web.client.RestTemplate; + +@Configuration +class KerberosConfig { + + @Value("${app.user-principal}") + private String principal; + + @Value("${app.keytab-location}") + private String keytabLocation; + + @Bean + public RestTemplate restTemplate() { + return new KerberosRestTemplate(keytabLocation, principal); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/KerberosMiniKdc.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/KerberosMiniKdc.java new file mode 100644 index 0000000000..60cf3ca1c2 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/KerberosMiniKdc.java @@ -0,0 +1,35 @@ +package kerberos.kdc; + +import org.apache.commons.io.FileUtils; +import org.springframework.security.kerberos.test.MiniKdc; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +class KerberosMiniKdc { + + private static final String KRB_WORK_DIR = ".\\spring-security-sso\\spring-security-sso-kerberos\\krb-test-workdir"; + + public static void main(String[] args) throws Exception { + + String[] config = MiniKdcConfigBuilder.builder() + .workDir(prepareWorkDir()) + .confDir("minikdc-krb5.conf") + .keytabName("example.keytab") + .principals("client/localhost", "HTTP/localhost") + .build(); + + MiniKdc.main(config); + } + + private static String prepareWorkDir() throws IOException { + Path dir = Paths.get(KRB_WORK_DIR); + File directory = dir.normalize().toFile(); + + FileUtils.deleteQuietly(directory); + FileUtils.forceMkdir(directory); + return dir.toString(); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/MiniKdcConfigBuilder.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/MiniKdcConfigBuilder.java new file mode 100644 index 0000000000..a9dd21a175 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/kdc/MiniKdcConfigBuilder.java @@ -0,0 +1,64 @@ +package kerberos.kdc; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Objects; + +class MiniKdcConfigBuilder { + + private String workDir; + private String confDir; + private String keytabName; + private Collection principals; + + private MiniKdcConfigBuilder() { + // desired + } + + static MiniKdcConfigBuilder builder() { + return new MiniKdcConfigBuilder(); + } + + MiniKdcConfigBuilder workDir(String workDir) { + this.workDir = workDir; + return this; + } + + MiniKdcConfigBuilder confDir(String cfg) { + try { + URL resource = Thread.currentThread().getContextClassLoader().getResource(cfg); + URI uri = Objects.requireNonNull(resource).toURI(); + this.confDir = Paths.get(uri).toString(); + } catch (URISyntaxException cause) { + throw new IllegalStateException("Could not resolve path for: " + cfg, cause); + } + return this; + } + + MiniKdcConfigBuilder keytabName(String keytabName) { + this.keytabName = Paths.get(workDir).resolve(keytabName).toString(); + return this; + } + + MiniKdcConfigBuilder principals(String... principals) { + this.principals = Arrays.asList(principals); + return this; + } + + String[] build() { + + Collection miniKdcConfig = new ArrayList<>(); + + miniKdcConfig.add(workDir); + miniKdcConfig.add(confDir); + miniKdcConfig.add(keytabName); + miniKdcConfig.addAll(principals); + + return miniKdcConfig.toArray(new String[0]); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/KerberizedServerApp.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/KerberizedServerApp.java new file mode 100644 index 0000000000..8286013605 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/KerberizedServerApp.java @@ -0,0 +1,22 @@ +package kerberos.server; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import java.nio.file.Paths; + +@SpringBootApplication +public class KerberizedServerApp { + + static { + System.setProperty("java.security.krb5.conf", + Paths.get(".\\spring-security-sso\\spring-security-sso-kerberos\\krb-test-workdir\\krb5.conf") + .normalize().toAbsolutePath().toString()); + System.setProperty("sun.security.krb5.debug", "true"); + } + + public static void main(String[] args) { + + SpringApplication.run(KerberizedServerApp.class, args); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/MvcConfig.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/MvcConfig.java new file mode 100644 index 0000000000..3ad07e407b --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/MvcConfig.java @@ -0,0 +1,18 @@ +package kerberos.server.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +class MvcConfig extends WebMvcConfigurerAdapter { + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/home").setViewName("home"); + registry.addViewController("/").setViewName("home"); + registry.addViewController("/hello").setViewName("hello"); + registry.addViewController("/login").setViewName("login"); + } + +} \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/WebSecurityConfig.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/WebSecurityConfig.java new file mode 100644 index 0000000000..5d241c5823 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/config/WebSecurityConfig.java @@ -0,0 +1,103 @@ +package kerberos.server.config; + +import kerberos.server.service.DummyUserDetailsService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.FileSystemResource; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider; +import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider; +import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient; +import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator; +import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter; +import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +@Configuration +@EnableWebSecurity +class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Value("${app.service-principal}") + private String servicePrincipal; + + @Value("${app.keytab-location}") + private String keytabLocation; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.exceptionHandling() + .authenticationEntryPoint(spnegoEntryPoint()) + .and() + .authorizeRequests().antMatchers("/", "/home").permitAll() + .anyRequest().authenticated() + .and() + .formLogin().loginPage("/login").permitAll() + .and() + .logout().permitAll() + .and() + .addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()), + BasicAuthenticationFilter.class); + } + + @Bean + public AuthenticationManager anAuthenticationManager() throws Exception { + return authenticationManager(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(kerberosAuthenticationProvider()) + .authenticationProvider(kerberosServiceAuthenticationProvider()); + } + + @Bean + public KerberosAuthenticationProvider kerberosAuthenticationProvider() { + KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider(); + SunJaasKerberosClient client = new SunJaasKerberosClient(); + client.setDebug(true); + provider.setKerberosClient(client); + provider.setUserDetailsService(dummyUserDetailsService()); + return provider; + } + + @Bean + public SpnegoEntryPoint spnegoEntryPoint() { + return new SpnegoEntryPoint("/login"); + } + + @Bean + public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter( + AuthenticationManager authenticationManager) { + SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter(); + filter.setAuthenticationManager(authenticationManager); + return filter; + } + + @Bean + public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() { + KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider(); + provider.setTicketValidator(sunJaasKerberosTicketValidator()); + provider.setUserDetailsService(dummyUserDetailsService()); + return provider; + } + + @Bean + public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() { + SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator(); + ticketValidator.setServicePrincipal(servicePrincipal); + ticketValidator.setKeyTabLocation(new FileSystemResource(keytabLocation)); + ticketValidator.setDebug(true); + return ticketValidator; + } + + @Bean + public DummyUserDetailsService dummyUserDetailsService() { + return new DummyUserDetailsService(); + } + +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/controller/SampleController.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/controller/SampleController.java new file mode 100644 index 0000000000..b1d3e6fb90 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/controller/SampleController.java @@ -0,0 +1,15 @@ +package kerberos.server.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/endpoint") +class SampleController { + + @GetMapping + String getIt() { + return "data from kerberized server"; + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/service/DummyUserDetailsService.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/service/DummyUserDetailsService.java new file mode 100644 index 0000000000..06942d8dc7 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/server/service/DummyUserDetailsService.java @@ -0,0 +1,16 @@ +package kerberos.server.service; + +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +public class DummyUserDetailsService implements UserDetailsService { + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + return new User(username, "notUsed", true, true, true, true, AuthorityUtils.createAuthorityList("ROLE_USER")); + } + +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/application.properties b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/application.properties new file mode 100644 index 0000000000..b36575460c --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/application.properties @@ -0,0 +1,6 @@ +# make sure the same data is configured in KerberosMiniKdc +# otherwise configuration/communication error will occur +app.service-principal=HTTP/localhost +app.user-principal=client/localhost +app.keytab-location=@project.basedir@\\krb-test-workdir\\example.keytab +app.access-url=http://localhost:8080/endpoint diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc-krb5.conf b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc-krb5.conf new file mode 100644 index 0000000000..ea1e9d1ceb --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc-krb5.conf @@ -0,0 +1,25 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +[libdefaults] +default_realm = {0} +udp_preference_limit = 1 + +[realms] +{0} = '{' + kdc = {1}:{2} + '}' \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc.ldiff b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc.ldiff new file mode 100644 index 0000000000..603ccb5fd9 --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/minikdc.ldiff @@ -0,0 +1,47 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +dn: ou=users,dc=${0},dc=${1} +objectClass: organizationalUnit +objectClass: top +ou: users + +dn: uid=krbtgt,ou=users,dc=${0},dc=${1} +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: KDC Service +sn: Service +uid: krbtgt +userPassword: secret +krb5PrincipalName: krbtgt/${2}.${3}@${2}.${3} +krb5KeyVersionNumber: 0 + +dn: uid=ldap,ou=users,dc=${0},dc=${1} +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: krb5principal +objectClass: krb5kdcentry +cn: LDAP +sn: Service +uid: ldap +userPassword: secret +krb5PrincipalName: ldap/${4}@${2}.${3} +krb5KeyVersionNumber: 0 \ No newline at end of file diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/hello.html b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/hello.html new file mode 100644 index 0000000000..71a756386b --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/hello.html @@ -0,0 +1,10 @@ + + + + Spring Security Kerberos Example + + +

Hello [[${#httpServletRequest.remoteUser}]]!

+ + diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/home.html b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/home.html new file mode 100644 index 0000000000..d8e37e443d --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/home.html @@ -0,0 +1,10 @@ + + + + Spring Security Kerberos Example + + +

Welcome!

+

Click here to see a greeting.

+ + diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/login.html b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/login.html new file mode 100644 index 0000000000..b96252192f --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/resources/templates/login.html @@ -0,0 +1,20 @@ + + + + Spring Security Kerberos Example + + +
+ Invalid username and password. +
+
+ You have been logged out. +
+
+
+
+
+
+ + diff --git a/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleServiceManualTest.java b/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleServiceManualTest.java new file mode 100644 index 0000000000..d0d9f0ae4b --- /dev/null +++ b/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleServiceManualTest.java @@ -0,0 +1,43 @@ +package kerberos.client; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * Procedure to run this manual test: + *
    + *
  1. Start {@code KerberosMiniKdc}
  2. + *
  3. Start {@code KerberizedServerApp}
  4. + *
  5. Run the test
  6. + *
+ */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@FixMethodOrder +public class SampleServiceManualTest { + + @Autowired + private SampleService sampleService; + + @Test + public void a_givenKerberizedRestTemplate_whenServiceCall_thenSuccess() { + assertNotNull(sampleService); + assertEquals("data from kerberized server", sampleService.getData()); + } + + @Test + public void b_givenRestTemplate_whenServiceCall_thenFail() { + sampleService.setRestTemplate(new RestTemplate()); + assertThrows(RestClientException.class, sampleService::getData); + } +} \ No newline at end of file diff --git a/spring-session/spring-session-jdbc/README.MD b/spring-session/spring-session-jdbc/README.md similarity index 55% rename from spring-session/spring-session-jdbc/README.MD rename to spring-session/spring-session-jdbc/README.md index 9293dfc953..94fd1cd3e7 100644 --- a/spring-session/spring-session-jdbc/README.MD +++ b/spring-session/spring-session-jdbc/README.md @@ -2,5 +2,3 @@ This module is for Spring Session with JDBC tutorial. Jira BAEL-1911 ### Relevant Articles: - -- [Spring Session with JDBC](http://www.baeldung.com/spring-session-jdbc) diff --git a/spring-session/spring-session-redis/README.md b/spring-session/spring-session-redis/README.md index 5e9304d778..5865913711 100644 --- a/spring-session/spring-session-redis/README.md +++ b/spring-session/spring-session-redis/README.md @@ -3,4 +3,3 @@ ## Spring Session Examples ### Relevant Articles: -- [Guide to Spring Session](http://www.baeldung.com/spring-session) diff --git a/spring-sleuth/src/main/java/com/baeldung/spring/session/SleuthService.java b/spring-sleuth/src/main/java/com/baeldung/spring/session/SleuthService.java index 511a6078f5..df5313580a 100644 --- a/spring-sleuth/src/main/java/com/baeldung/spring/session/SleuthService.java +++ b/spring-sleuth/src/main/java/com/baeldung/spring/session/SleuthService.java @@ -28,7 +28,7 @@ public class SleuthService { public void doSomeWorkNewSpan() throws InterruptedException { logger.info("I'm in the original span"); - Span newSpan = tracer.newTrace().name("newSpan").start(); + Span newSpan = tracer.nextSpan().name("newSpan").start(); try (SpanInScope ws = tracer.withSpanInScope(newSpan.start())) { Thread.sleep(1000L); logger.info("I'm in the new span doing some cool work that needs its own span"); diff --git a/spring-sleuth/src/main/resources/logback.xml b/spring-sleuth/src/main/resources/logback.xml index 7d900d8ea8..044adaaf1d 100644 --- a/spring-sleuth/src/main/resources/logback.xml +++ b/spring-sleuth/src/main/resources/logback.xml @@ -1,13 +1,20 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-soap/README.md b/spring-soap/README.md new file mode 100644 index 0000000000..8d96350e1e --- /dev/null +++ b/spring-soap/README.md @@ -0,0 +1,3 @@ +## Relevant articles: + +- [Creating a SOAP Web Service with Spring](https://www.baeldung.com/spring-boot-soap-web-service) diff --git a/spring-soap/pom.xml b/spring-soap/pom.xml index 2865a4c3bc..ba05eddf5d 100644 --- a/spring-soap/pom.xml +++ b/spring-soap/pom.xml @@ -2,19 +2,20 @@ 4.0.0 - - com.baeldung spring-soap + spring-soap 1.0.0 - org.springframework.boot - spring-boot-starter-parent - 2.1.2.RELEASE + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 1.8 + 2.1.2.RELEASE diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java index 3a3e632c51..55e1397823 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java @@ -64,11 +64,11 @@ public class ForkJoinStateMachineConfiguration extends StateMachineConfigurerAda @Bean public Guard mediumGuard() { - return (ctx) -> false; + return ctx -> false; } @Bean public Guard highGuard() { - return (ctx) -> false; + return ctx -> false; } } \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java index 2f48a9dbb5..21b37381df 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java @@ -50,11 +50,11 @@ public class JunctionStateMachineConfiguration extends StateMachineConfigurerAda @Bean public Guard mediumGuard() { - return (ctx) -> false; + return ctx -> false; } @Bean public Guard highGuard() { - return (ctx) -> false; + return ctx -> false; } } \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java index d1b1ce001c..0c392c2c35 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java @@ -18,7 +18,7 @@ import java.util.logging.Logger; @EnableStateMachine public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapter { - public static final Logger LOGGER = Logger.getLogger(SimpleStateMachineConfiguration.class.getName()); + private static final Logger LOGGER = Logger.getLogger(SimpleStateMachineConfiguration.class.getName()); @Override public void configure(StateMachineConfigurationConfigurer config) throws Exception { @@ -80,7 +80,7 @@ public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapt @Bean public Guard simpleGuard() { - return (ctx) -> { + return ctx -> { int approvalCount = (int) ctx .getExtendedState() .getVariables() diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java index 47a274404e..09e8946810 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java @@ -7,10 +7,10 @@ import java.util.logging.Logger; public class StateMachineListener extends StateMachineListenerAdapter { - public static final Logger LOGGER = Logger.getLogger(StateMachineListener.class.getName()); + private static final Logger LOGGER = Logger.getLogger(StateMachineListener.class.getName()); @Override public void stateChanged(State from, State to) { - LOGGER.info(String.format("Transitioned from %s to %s%n", from == null ? "none" : from.getId(), to.getId())); + LOGGER.info(() -> String.format("Transitioned from %s to %s%n", from == null ? "none" : from.getId(), to.getId())); } } diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java index b34d5c47c6..66acad901c 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java @@ -1,18 +1,15 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.config.ForkJoinStateMachineConfiguration; -import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.annotation.Resource; import java.util.Arrays; import static org.junit.Assert.assertEquals; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java index 3d7c0be828..00a9c9a08c 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java @@ -1,18 +1,15 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.config.HierarchicalStateMachineConfiguration; -import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.annotation.Resource; import java.util.Arrays; import static org.junit.Assert.assertEquals; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java index 93de23fad3..f0ee757522 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java @@ -1,20 +1,16 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration; -import com.baeldung.spring.statemachine.config.SimpleEnumStateMachineConfiguration; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.annotation.Resource; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = JunctionStateMachineConfiguration.class) public class JunctionStateMachineIntegrationTest { diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java index 9074ece001..d345cd0dfc 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java @@ -3,19 +3,15 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewEvents; import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewStates; import com.baeldung.spring.statemachine.config.SimpleEnumStateMachineConfiguration; -import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.annotation.Resource; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderIntegrationTest.java index c1de8b8958..e5431d9d83 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderIntegrationTest.java @@ -1,11 +1,11 @@ package com.baeldung.spring.statemachine; -import static org.junit.Assert.assertEquals; - import org.junit.Test; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.config.StateMachineBuilder; +import static org.junit.Assert.assertEquals; + public class StateMachineBuilderIntegrationTest { @Test diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java index 25df7c8cd3..aab07225a3 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java @@ -1,22 +1,17 @@ package com.baeldung.spring.statemachine; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - +import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; - -import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.junit4.SpringRunner; -import javax.annotation.Resource; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SimpleStateMachineConfiguration.class) @@ -42,7 +37,7 @@ public class StateMachineIntegrationTest { } @Test - public void whenSimpleStringMachineActionState_thenActionExecuted() throws InterruptedException { + public void whenSimpleStringMachineActionState_thenActionExecuted() { stateMachine.sendEvent("E3"); assertEquals("S3", stateMachine.getState().getId()); diff --git a/spring-static-resources/pom.xml b/spring-static-resources/pom.xml index aedf88e384..fc2b3336bc 100644 --- a/spring-static-resources/pom.xml +++ b/spring-static-resources/pom.xml @@ -20,17 +20,17 @@ org.springframework.security spring-security-web - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-config - ${org.springframework.security.version} + ${spring-security.version} org.springframework.security spring-security-taglibs - ${org.springframework.security.version} + ${spring-security.version} @@ -196,9 +196,6 @@ - - 5.0.6.RELEASE - 1.8.9 2.3.2-b02 diff --git a/spring-zuul/pom.xml b/spring-zuul/pom.xml index d00a932168..fbbbdddbf7 100644 --- a/spring-zuul/pom.xml +++ b/spring-zuul/pom.xml @@ -38,22 +38,11 @@ - 2.1.0.RC3 + 2.1.0.RELEASE 3.5 2.6 - - - spring-milestones - Spring Milestones - http://repo.spring.io/milestone - - false - - - - \ No newline at end of file diff --git a/tensorflow-java/.gitignore b/tensorflow-java/.gitignore new file mode 100644 index 0000000000..eaea64ae48 --- /dev/null +++ b/tensorflow-java/.gitignore @@ -0,0 +1,6 @@ +/.settings +/model +/target +.classpath +.project +.springBeans \ No newline at end of file diff --git a/tensorflow-java/README.md b/tensorflow-java/README.md new file mode 100644 index 0000000000..aa9e9e56b9 --- /dev/null +++ b/tensorflow-java/README.md @@ -0,0 +1,3 @@ +## Relevant articles: + +- [TensorFlow for Java](https://www.baeldung.com/tensorflow-java) diff --git a/tensorflow-java/pom.xml b/tensorflow-java/pom.xml new file mode 100644 index 0000000000..e9d92157e8 --- /dev/null +++ b/tensorflow-java/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + com.baeldung + tensorflow-java + 1.0-SNAPSHOT + jar + http://maven.apache.org + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + 1.8 + 1.12.0 + 5.4.0 + + + + + org.tensorflow + tensorflow + ${tensorflow.version} + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowGraph.java b/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowGraph.java new file mode 100644 index 0000000000..a44ef4c4ee --- /dev/null +++ b/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowGraph.java @@ -0,0 +1,41 @@ +package org.baeldung.tensorflow; + +import org.tensorflow.DataType; +import org.tensorflow.Graph; +import org.tensorflow.Operation; +import org.tensorflow.Session; +import org.tensorflow.Tensor; + +public class TensorflowGraph { + + public static Graph createGraph() { + Graph graph = new Graph(); + Operation a = graph.opBuilder("Const", "a").setAttr("dtype", DataType.fromClass(Double.class)) + .setAttr("value", Tensor.create(3.0, Double.class)).build(); + Operation b = graph.opBuilder("Const", "b").setAttr("dtype", DataType.fromClass(Double.class)) + .setAttr("value", Tensor.create(2.0, Double.class)).build(); + Operation x = graph.opBuilder("Placeholder", "x").setAttr("dtype", DataType.fromClass(Double.class)).build(); + Operation y = graph.opBuilder("Placeholder", "y").setAttr("dtype", DataType.fromClass(Double.class)).build(); + Operation ax = graph.opBuilder("Mul", "ax").addInput(a.output(0)).addInput(x.output(0)).build(); + Operation by = graph.opBuilder("Mul", "by").addInput(b.output(0)).addInput(y.output(0)).build(); + graph.opBuilder("Add", "z").addInput(ax.output(0)).addInput(by.output(0)).build(); + return graph; + } + + public static Object runGraph(Graph graph, Double x, Double y) { + Object result; + try (Session sess = new Session(graph)) { + result = sess.runner().fetch("z").feed("x", Tensor.create(x, Double.class)) + .feed("y", Tensor.create(y, Double.class)).run().get(0).expect(Double.class) + .doubleValue(); + } + return result; + } + + public static void main(String[] args) { + Graph graph = TensorflowGraph.createGraph(); + Object result = TensorflowGraph.runGraph(graph, 3.0, 6.0); + System.out.println(result); + graph.close(); + } +} \ No newline at end of file diff --git a/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowSavedModel.java b/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowSavedModel.java new file mode 100644 index 0000000000..4259a787e8 --- /dev/null +++ b/tensorflow-java/src/main/java/org/baeldung/tensorflow/TensorflowSavedModel.java @@ -0,0 +1,14 @@ +package org.baeldung.tensorflow; + +import org.tensorflow.SavedModelBundle; +import org.tensorflow.Tensor; + +public class TensorflowSavedModel { + + public static void main(String[] args) { + SavedModelBundle model = SavedModelBundle.load("./model", "serve"); + Tensor tensor = model.session().runner().fetch("z").feed("x", Tensor.create(3, Integer.class)) + .feed("y", Tensor.create(3, Integer.class)).run().get(0).expect(Integer.class); + System.out.println(tensor.intValue()); + } +} \ No newline at end of file diff --git a/tensorflow-java/src/main/python/tensorflowGraph.py b/tensorflow-java/src/main/python/tensorflowGraph.py new file mode 100644 index 0000000000..ab7f8810ac --- /dev/null +++ b/tensorflow-java/src/main/python/tensorflowGraph.py @@ -0,0 +1,16 @@ +import tensorflow as tf +graph = tf.Graph() +builder = tf.saved_model.builder.SavedModelBuilder('./model') +writer = tf.summary.FileWriter('.') +with graph.as_default(): + a = tf.constant(2, name='a') + b = tf.constant(3, name='b') + x = tf.placeholder(tf.int32, name='x') + y = tf.placeholder(tf.int32, name='y') + z = tf.math.add(a*x, b*y, name='z') + writer.add_graph(tf.get_default_graph()) + writer.flush() + sess = tf.Session() + sess.run(z, feed_dict = {x: 2, y: 3}) + builder.add_meta_graph_and_variables(sess, [tf.saved_model.tag_constants.SERVING]) + builder.save() diff --git a/tensorflow-java/src/test/java/org/baeldung/tensorflow/TensorflowGraphUnitTest.java b/tensorflow-java/src/test/java/org/baeldung/tensorflow/TensorflowGraphUnitTest.java new file mode 100644 index 0000000000..51df6a4322 --- /dev/null +++ b/tensorflow-java/src/test/java/org/baeldung/tensorflow/TensorflowGraphUnitTest.java @@ -0,0 +1,21 @@ +package org.baeldung.tensorflow; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.Test; +import org.tensorflow.Graph; + +public class TensorflowGraphUnitTest { + + @Test + public void givenTensorflowGraphWhenRunInSessionReturnsExpectedResult() { + + Graph graph = TensorflowGraph.createGraph(); + Object result = TensorflowGraph.runGraph(graph, 3.0, 6.0); + assertEquals(21.0, result); + System.out.println(result); + graph.close(); + + } + +} diff --git a/testing-modules/groovy-spock/README.md b/testing-modules/groovy-spock/README.md index 18d26e8fc0..a98df27172 100644 --- a/testing-modules/groovy-spock/README.md +++ b/testing-modules/groovy-spock/README.md @@ -1,3 +1,4 @@ ### Relevant articles - [Introduction to Testing with Spock and Groovy](http://www.baeldung.com/groovy-spock) +- [Difference Between Stub, Mock, and Spy in the Spock Framework](https://www.baeldung.com/spock-stub-mock-spy) diff --git a/testing-modules/groovy-spock/pom.xml b/testing-modules/groovy-spock/pom.xml index 2a058e5358..d6097af208 100644 --- a/testing-modules/groovy-spock/pom.xml +++ b/testing-modules/groovy-spock/pom.xml @@ -48,9 +48,9 @@ - 1.0-groovy-2.4 + 1.3-RC1-groovy-2.4 2.4.7 1.5 - \ No newline at end of file + diff --git a/testing-modules/groovy-spock/report-2019-03-29.json b/testing-modules/groovy-spock/report-2019-03-29.json new file mode 100644 index 0000000000..85f0b261fb --- /dev/null +++ b/testing-modules/groovy-spock/report-2019-03-29.json @@ -0,0 +1,402 @@ +loadLogFile([{ + "package": "mocks", + "name": "ExampleSpockTest", + "start": 1553898111660, + "features": [ + { + "name": "should calculate character occurrences in given string", + "start": 1553898111662, + "end": 1553898111699, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898111709, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "mocks", + "name": "ItemServiceTest", + "start": 1553898111714, + "features": [ + { + "name": "should spy on EventPublisher method call", + "start": 1553898111714, + "output": [ + "I've published: item-id\n" + ], + "end": 1553898112250, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should return items", + "start": 1553898112250, + "end": 1553898112260, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should publish events about new non-empty saved offers", + "start": 1553898112260, + "end": 1553898112267, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should return different items for different ids lists", + "start": 1553898112267, + "end": 1553898112280, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should throw ExternalItemProviderException when ItemProvider fails", + "start": 1553898112281, + "end": 1553898112294, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should return different items on subsequent call", + "start": 1553898112294, + "narrative": "When method is called for the first time\nThen empty list is returned\nWhen method is called for the second time\nThen item with id=1 is returned\nWhen method is called for the thirdtime\nThen item with id=2 is returned", + "end": 1553898112298, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "should return items sorted by name", + "start": 1553898112299, + "end": 1553898112307, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898112310, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "FirstSpecification", + "name": "FirstSpecification", + "start": 1553898112314, + "features": [ + { + "name": "Should verify notify was called", + "start": 1553898112314, + "end": 1553898112324, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "Should return true value for mock", + "start": 1553898112325, + "end": 1553898112344, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "Should return default value for mock", + "start": 1553898112344, + "end": 1553898112347, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "numbers to the power of two", + "start": 1553898112347, + "end": 1553898112358, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "Should get an index out of bounds when removing a non-existent item", + "start": 1553898112358, + "end": 1553898112364, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "Should be able to remove from list", + "start": 1553898112364, + "end": 1553898112366, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "two plus two should equal four", + "start": 1553898112366, + "end": 1553898112368, + "result": "passed", + "attachments": [ + + ] + }, + { + "name": "one plus one should equal two", + "start": 1553898112368, + "end": 1553898112391, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898112394, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "IgnoreTest", + "start": 1553898112395, + "end": 1553898112395, + "result": "skipped" +}]) + +loadLogFile([{ + "package": "extensions", + "name": "RetryTest", + "start": 1553898112403, + "end": 1553898112405, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "This title is easy to read for humans", + "start": 1553898112407, + "end": 1553898112408, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "SeeTest", + "start": 1553898112409, + "end": 1553898112411, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "StepwiseTest", + "start": 1553898112422, + "end": 1553898112423, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "NarrativeDescriptionTest", + "start": 1553898112427, + "narrative": "as a user\n i want to save favourite items \n and then get the list of them", + "end": 1553898112433, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "SubjectTest", + "start": 1553898112434, + "end": 1553898112436, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "IgnoreRestTest", + "start": 1553898112437, + "end": 1553898112437, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "StackTraceTest", + "start": 1553898112438, + "features": [ + { + "name": "stacktrace", + "start": 1553898112438, + "exceptions": [ + "java.lang.RuntimeException: blabla\n\tat extensions.StackTraceTest.stacktrace(StackTraceTest.groovy:10)\n" + ], + "end": 1553898112455, + "result": "failed", + "attachments": [ + + ] + } + ], + "end": 1553898112470, + "result": "failed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "IgnoreIfTest", + "start": 1553898112471, + "end": 1553898112472, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "RequiresTest", + "start": 1553898112473, + "features": [ + { + "name": "I will run only on Windows", + "start": 1553898112474, + "end": 1553898112474, + "result": "skipped" + } + ], + "end": 1553898112476, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "IssueTest", + "start": 1553898112477, + "features": [ + { + "name": "I'm using Spock configuration file", + "start": 1553898112477, + "tags": [ + { + "name": "Bug LO-1000", + "key": "issue", + "value": "LO-1000", + "url": "http:\/\/jira.org\/issues\/LO-1000" + } + ], + "end": 1553898112489, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898112490, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "TimeoutTest", + "start": 1553898112491, + "features": [ + { + "name": "I will fail after 200 millis", + "start": 1553898112491, + "end": 1553898112514, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898112517, + "result": "passed", + "attachments": [ + + ] +}]) + +loadLogFile([{ + "package": "extensions", + "name": "RestoreSystemPropertiesTest", + "start": 1553898112518, + "features": [ + { + "name": "all environment variables will be saved before execution and restored after tests", + "start": 1553898112518, + "end": 1553898112532, + "result": "passed", + "attachments": [ + + ] + } + ], + "end": 1553898112539, + "result": "passed", + "attachments": [ + + ] +}]) + diff --git a/testing-modules/groovy-spock/src/main/java/mocks/EventPublisher.java b/testing-modules/groovy-spock/src/main/java/mocks/EventPublisher.java new file mode 100644 index 0000000000..290966db9f --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/EventPublisher.java @@ -0,0 +1,7 @@ +package mocks; + +public interface EventPublisher { + + void publish(String addedOfferId); + +} diff --git a/testing-modules/groovy-spock/src/main/java/mocks/ExternalItemProviderException.java b/testing-modules/groovy-spock/src/main/java/mocks/ExternalItemProviderException.java new file mode 100644 index 0000000000..e2ac43b7f4 --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/ExternalItemProviderException.java @@ -0,0 +1,5 @@ +package mocks; + +public class ExternalItemProviderException extends RuntimeException { + +} diff --git a/testing-modules/groovy-spock/src/main/java/mocks/Item.java b/testing-modules/groovy-spock/src/main/java/mocks/Item.java new file mode 100644 index 0000000000..e1608cfd23 --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/Item.java @@ -0,0 +1,36 @@ +package mocks; + +import java.util.Objects; + +public class Item { + private final String id; + private final String name; + + public Item(String id, String name) { + this.id = id; + this.name = name; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Item item = (Item) o; + return Objects.equals(id, item.id) && + Objects.equals(name, item.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + +} diff --git a/testing-modules/groovy-spock/src/main/java/mocks/ItemProvider.java b/testing-modules/groovy-spock/src/main/java/mocks/ItemProvider.java new file mode 100644 index 0000000000..a794c51f49 --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/ItemProvider.java @@ -0,0 +1,9 @@ +package mocks; + +import java.util.List; + +public interface ItemProvider { + + List getItems(List itemIds); + +} diff --git a/testing-modules/groovy-spock/src/main/java/mocks/ItemService.java b/testing-modules/groovy-spock/src/main/java/mocks/ItemService.java new file mode 100644 index 0000000000..3327a8b27c --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/ItemService.java @@ -0,0 +1,37 @@ +package mocks; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +public class ItemService { + private final ItemProvider itemProvider; + private final EventPublisher eventPublisher; + + + public ItemService(ItemProvider itemProvider, EventPublisher eventPublisher) { + this.itemProvider = itemProvider; + this.eventPublisher = eventPublisher; + } + + List getAllItemsSortedByName(List itemIds) { + List items; + try{ + items = itemProvider.getItems(itemIds); + } catch (RuntimeException ex) { + throw new ExternalItemProviderException(); + } + return items.stream() + .sorted(Comparator.comparing(Item::getName)) + .collect(Collectors.toList()); + } + + void saveItems(List itemIds) { + List notEmptyOfferIds = itemIds.stream() + .filter(itemId -> !itemId.isEmpty()) + .collect(Collectors.toList()); + // save in database + notEmptyOfferIds.forEach(eventPublisher::publish); + } + +} diff --git a/testing-modules/groovy-spock/src/main/java/mocks/LoggingEventPublisher.java b/testing-modules/groovy-spock/src/main/java/mocks/LoggingEventPublisher.java new file mode 100644 index 0000000000..c51fe1ff77 --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/LoggingEventPublisher.java @@ -0,0 +1,10 @@ +package mocks; + +public class LoggingEventPublisher implements EventPublisher { + + @Override + public void publish(String addedOfferId) { + System.out.println("I've published: " + addedOfferId); + } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/CustomTitleTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/CustomTitleTest.groovy new file mode 100644 index 0000000000..11a5fb0eb9 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/CustomTitleTest.groovy @@ -0,0 +1,20 @@ +package extensions + +import spock.lang.Narrative +import spock.lang.Specification +import spock.lang.Title + + +@Title("""This title is easy to read for humans""") +class CustomTitleTest extends Specification { + +} + +@Narrative(""" + as a user + i want to save favourite items + and then get the list of them +""") +class NarrativeDescriptionTest extends Specification { + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy new file mode 100644 index 0000000000..91da2ff1ec --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy @@ -0,0 +1,12 @@ +package extensions + +import spock.lang.IgnoreIf +import spock.lang.Specification + + +class IgnoreIfTest extends Specification { + + @IgnoreIf({System.getProperty("os.name").contains("windows")}) + def "I won't run on windows"() { } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreRestTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreRestTest.groovy new file mode 100644 index 0000000000..dead2c7393 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreRestTest.groovy @@ -0,0 +1,16 @@ +package extensions + +import spock.lang.IgnoreRest +import spock.lang.Specification + + +class IgnoreRestTest extends Specification { + + def "I won't run"() { } + + @IgnoreRest + def 'I will run'() { } + + def "I won't run too"() { } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreTest.groovy new file mode 100644 index 0000000000..9af5708ae2 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreTest.groovy @@ -0,0 +1,20 @@ +package extensions + +import spock.lang.Ignore +import spock.lang.Specification + +@Ignore +class IgnoreTest extends Specification { + + @Ignore + def "I won't be executed"() { + expect: + true + } + + def 'Example test'() { + expect: + true + } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/IssueTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/IssueTest.groovy new file mode 100644 index 0000000000..56e0f09bf1 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/IssueTest.groovy @@ -0,0 +1,25 @@ +package extensions + +import spock.lang.Issue +import spock.lang.Specification + + +class IssueTest extends Specification { + + + @Issue("http://jira.org/issues/LO-531") + def 'single issue'() { + } + + @Issue(["http://jira.org/issues/LO-531", "http://jira.org/issues/LO-123"]) + def 'multiple issues'() { + } + + @Issue("LO-1000") + def "I'm using Spock configuration file"() { + expect: + true + } + + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/PendingFeatureTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/PendingFeatureTest.groovy new file mode 100644 index 0000000000..59bd99ceb8 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/PendingFeatureTest.groovy @@ -0,0 +1,11 @@ +package extensions + +import spock.lang.PendingFeature + +class PendingFeatureTest { + + @PendingFeature + def 'test for not implemented yet feature'() { + + } +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/RequiresTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/RequiresTest.groovy new file mode 100644 index 0000000000..c384c3786b --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/RequiresTest.groovy @@ -0,0 +1,14 @@ +package extensions + +import spock.lang.Requires +import spock.lang.Specification + + +class RequiresTest extends Specification { + + @Requires({ System.getProperty("os.name").contains("windows") }) + def "I will run only on Windows"() { + expect: + true + } +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/RestoreSystemPropertiesTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/RestoreSystemPropertiesTest.groovy new file mode 100644 index 0000000000..824e88d84e --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/RestoreSystemPropertiesTest.groovy @@ -0,0 +1,18 @@ +package extensions + +import spock.lang.Specification +import spock.util.environment.RestoreSystemProperties + + +class RestoreSystemPropertiesTest extends Specification { + + @RestoreSystemProperties + def 'all environment variables will be saved before execution and restored after tests'() { + given: + System.setProperty('os.name', 'Mac OS') + + expect: + true + } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/RetryTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/RetryTest.groovy new file mode 100644 index 0000000000..a07ebae851 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/RetryTest.groovy @@ -0,0 +1,20 @@ +package extensions + +import spock.lang.Retry +import spock.lang.Specification + +@Retry +class RetryTest extends Specification { + + @Retry + def 'I will retry three times'() { } + + @Retry(exceptions = [RuntimeException]) + def 'I will retry only on RuntimeException'() { } + + @Retry(condition = { failure.message.contains('error') }) + def 'I will retry with a specific message'() { } + + @Retry(delay = 1000) + def 'I will retry after 1000 millis'() { } +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/SeeTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/SeeTest.groovy new file mode 100644 index 0000000000..50212ad136 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/SeeTest.groovy @@ -0,0 +1,20 @@ +package extensions + +import spock.lang.See +import spock.lang.Specification + + +class SeeTest extends Specification { + + + @See("https://example.org") + def 'Look at the reference'() { + + } + + @See(["https://example.org/first", "https://example.org/first"]) + def 'Look at the references'() { + + } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/StackTraceTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/StackTraceTest.groovy new file mode 100644 index 0000000000..00fa55e21e --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/StackTraceTest.groovy @@ -0,0 +1,13 @@ +package extensions + +import org.junit.Ignore +import spock.lang.Specification + + +class StackTraceTest extends Specification { + + def 'stkacktrace'() { +// expect: +// throw new RuntimeException("blabla") + } +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/StepwiseTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/StepwiseTest.groovy new file mode 100644 index 0000000000..1bf83ce84d --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/StepwiseTest.groovy @@ -0,0 +1,14 @@ +package extensions + +import spock.lang.Specification +import spock.lang.Stepwise + + +@Stepwise +class StepwiseTest extends Specification { + + def 'I will run as first'() { } + + def 'I will run as second'() { } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/SubjectTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/SubjectTest.groovy new file mode 100644 index 0000000000..8474df0f14 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/SubjectTest.groovy @@ -0,0 +1,13 @@ +package extensions + +import mocks.ItemService +import spock.lang.Specification +import spock.lang.Subject + + +class SubjectTest extends Specification { + + @Subject + ItemService itemService // initialization here... + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/TimeoutTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/TimeoutTest.groovy new file mode 100644 index 0000000000..0049d99806 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/TimeoutTest.groovy @@ -0,0 +1,24 @@ +package extensions + +import spock.lang.Specification +import spock.lang.Timeout + +import java.util.concurrent.TimeUnit + +@Timeout(5) +class TimeoutTest extends Specification { + + @Timeout(1) + def 'I have one second to finish'() { + + } + + def 'I will have 5 seconds timeout'() {} + + @Timeout(value = 200, unit = TimeUnit.SECONDS) + def 'I will fail after 200 millis'() { + expect: + true + } + +} diff --git a/testing-modules/groovy-spock/src/test/groovy/mocks/ItemServiceUnitTest.groovy b/testing-modules/groovy-spock/src/test/groovy/mocks/ItemServiceUnitTest.groovy new file mode 100644 index 0000000000..2ccb72f726 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/mocks/ItemServiceUnitTest.groovy @@ -0,0 +1,131 @@ +package mocks + +import spock.lang.Specification + +class ItemServiceUnitTest extends Specification { + + ItemProvider itemProvider + ItemService itemService + EventPublisher eventPublisher + + def setup() { + itemProvider = Stub(ItemProvider) + eventPublisher = Mock(EventPublisher) + itemService = new ItemService(itemProvider, eventPublisher) + } + + def 'should return items sorted by name'() { + given: + def ids = ['offer-id', 'offer-id-2'] + itemProvider.getItems(ids) >> [new Item('offer-id-2', 'Zname'), new Item('offer-id', 'Aname')] + + when: + List items = itemService.getAllItemsSortedByName(ids) + + then: + items.collect { it.name } == ['Aname', 'Zname'] + } + + def 'arguments constraints'() { + itemProvider.getItems(['offer-id']) + itemProvider.getItems(_) >> [] + itemProvider.getItems(*_) >> [] + itemProvider.getItems(!null) >> [] + itemProvider.getItems({ it.size > 0 }) >> [] + } + + def 'should return different items on subsequent call'() { + given: + itemProvider.getItems(_) >>> [ + [], + [new Item('1', 'name')], + [new Item('2', 'name')] + ] + + when: 'method is called for the first time' + List items = itemService.getAllItemsSortedByName(['not-important']) + + then: 'empty list is returned' + items == [] + + when: 'method is called for the second time' + items = itemService.getAllItemsSortedByName(['not-important']) + + then: 'item with id=1 is returned' + items == [new Item('1', 'name')] + + when: 'method is called for the thirdtime' + items = itemService.getAllItemsSortedByName(['not-important']) + + then: 'item with id=2 is returned' + items == [new Item('2', 'name')] + } + + def 'should throw ExternalItemProviderException when ItemProvider fails'() { + given: + itemProvider.getItems(_) >> { new RuntimeException()} + + when: + itemService.getAllItemsSortedByName([]) + + then: + thrown(ExternalItemProviderException) + } + + def 'chaining response'() { + itemProvider.getItems(_) >>> { new RuntimeException() } >> new SocketTimeoutException() >> [new Item('id', 'name')] + } + + def 'should return different items for different ids lists'() { + given: + def firstIds = ['first'] + def secondIds = ['second'] + itemProvider.getItems(firstIds) >> [new Item('first', 'Zname')] + itemProvider.getItems(secondIds) >> [new Item('second', 'Aname')] + + when: + def firstItems = itemService.getAllItemsSortedByName(firstIds) + def secondItems = itemService.getAllItemsSortedByName(secondIds) + + then: + firstItems.first().name == 'Zname' + secondItems.first().name == 'Aname' + } + + def 'should publish events about new non-empty saved offers'() { + given: + def offerIds = ['', 'a', 'b'] + + when: + itemService.saveItems(offerIds) + + then: + 2 * eventPublisher.publish({ it != null && !it.isEmpty()}) + } + + def 'should return items'() { + given: + itemProvider = Mock(ItemProvider) + itemProvider.getItems(['item-id']) >> [new Item('item-id', 'name')] + itemService = new ItemService(itemProvider, eventPublisher) + + when: + def items = itemService.getAllItemsSortedByName(['item-id']) + + then: + items == [new Item('item-id', 'name')] + } + + def 'should spy on EventPublisher method call'() { + given: + LoggingEventPublisher eventPublisher = Spy(LoggingEventPublisher) + itemService = new ItemService(itemProvider, eventPublisher) + + when: + itemService.saveItems(['item-id']) + + then: + 1 * eventPublisher.publish('item-id') + } + +} diff --git a/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy b/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy new file mode 100644 index 0000000000..ed94e61cbf --- /dev/null +++ b/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy @@ -0,0 +1,27 @@ +import extensions.TimeoutTest +import spock.lang.Issue + +runner { + filterStackTrace true + + report { + issueNamePrefix 'Bug ' + issueUrlPrefix 'http://jira.org/issues/' + } + + optimizeRunOrder true + +// exclude TimeoutTest +// exclude { +// baseClass TimeoutTest +// annotation Issue +// } + + report { + enabled true + logFileDir '.' + logFileName 'report.json' + logFileSuffix new Date().format('yyyy-MM-dd') + } + +} diff --git a/testing-modules/junit-5/README.md b/testing-modules/junit-5/README.md index 4ed01e7fa9..d686396a1d 100644 --- a/testing-modules/junit-5/README.md +++ b/testing-modules/junit-5/README.md @@ -3,12 +3,12 @@ - [A Guide to JUnit 5](http://www.baeldung.com/junit-5) - [A Guide to @RepeatedTest in Junit 5](http://www.baeldung.com/junit-5-repeated-test) - [Guide to Dynamic Tests in Junit 5](http://www.baeldung.com/junit5-dynamic-tests) -- [A Guied to JUnit 5 Extensions](http://www.baeldung.com/junit-5-extensions) +- [A Guide to JUnit 5 Extensions](http://www.baeldung.com/junit-5-extensions) - [Inject Parameters into JUnit Jupiter Unit Tests](http://www.baeldung.com/junit-5-parameters) - [Mockito and JUnit 5 – Using ExtendWith](http://www.baeldung.com/mockito-junit-5-extension) - [JUnit 5 – @RunWith](http://www.baeldung.com/junit-5-runwith) - [JUnit 5 @Test Annotation](http://www.baeldung.com/junit-5-test-annotation) -- [JUnit Assert an Exception is Thrown](http://www.baeldung.com/junit-assert-exception) +- [Assert an Exception is Thrown in JUnit 4 and 5](http://www.baeldung.com/junit-assert-exception) - [@Before vs @BeforeClass vs @BeforeEach vs @BeforeAll](http://www.baeldung.com/junit-before-beforeclass-beforeeach-beforeall) - [Migrating from JUnit 4 to JUnit 5](http://www.baeldung.com/junit-5-migration) - [JUnit5 Programmatic Extension Registration with @RegisterExtension](http://www.baeldung.com/junit-5-registerextension-annotation) @@ -17,3 +17,4 @@ - [Testing an Abstract Class With JUnit](https://www.baeldung.com/junit-test-abstract-class) - [A Quick JUnit vs TestNG Comparison](http://www.baeldung.com/junit-vs-testng) - [Guide to JUnit 5 Parameterized Tests](https://www.baeldung.com/parameterized-tests-junit-5) +- [JUnit 5 Conditional Test Execution with Annotations](https://www.baeldung.com/junit-5-conditional-test-execution) diff --git a/testing-modules/junit-5/src/test/java/com/baeldung/conditional/ConditionalAnnotationsUnitTest.java b/testing-modules/junit-5/src/test/java/com/baeldung/conditional/ConditionalAnnotationsUnitTest.java new file mode 100644 index 0000000000..ec76bd1488 --- /dev/null +++ b/testing-modules/junit-5/src/test/java/com/baeldung/conditional/ConditionalAnnotationsUnitTest.java @@ -0,0 +1,119 @@ +package com.baeldung.conditional; + +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.*; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +public class ConditionalAnnotationsUnitTest { + @Test + @EnabledOnOs({OS.WINDOWS, OS.MAC}) + public void shouldRunBothWindowsAndMac() { + System.out.println("runs on Windows and Mac"); + } + + @Test + @DisabledOnOs(OS.LINUX) + public void shouldNotRunAtLinux() { + System.out.println("will not run on Linux"); + } + + @Test + @EnabledOnJre({JRE.JAVA_10, JRE.JAVA_11}) + public void shouldOnlyRunOnJava10And11() { + System.out.println("runs with java 10 and 11"); + } + + @Test + @DisabledOnJre(JRE.OTHER) + public void thisTestOnlyRunsWithUpToDateJREs() { + System.out.println("this test will only run on java8, 9, 10 and 11."); + } + + @Test + @EnabledIfSystemProperty(named = "java.vm.vendor", matches = "Oracle.*") + public void onlyIfVendorNameStartsWithOracle() { + System.out.println("runs only if vendor name starts with Oracle"); + } + + @Test + @DisabledIfSystemProperty(named = "file.separator", matches = "[/]") + public void disabledIfFileSeperatorIsSlash() { + System.out.println("Will not run if file.sepeartor property is /"); + } + + @Test + @EnabledIfEnvironmentVariable(named = "GDMSESSION", matches = "ubuntu") + public void onlyRunOnUbuntuServer() { + System.out.println("only runs if GDMSESSION is ubuntu"); + } + + @Test + @DisabledIfEnvironmentVariable(named = "LC_TIME", matches = ".*UTF-8.") + public void shouldNotRunWhenTimeIsNotUTF8() { + System.out.println("will not run if environment variable LC_TIME is UTF-8"); + } + + @Test + @EnabledIf("'FR' == systemProperty.get('user.country')") + public void onlyFrenchPeopleWillRunThisMethod() { + System.out.println("will run only if user.country is FR"); + } + + @Test + @DisabledIf("java.lang.System.getProperty('os.name').toLowerCase().contains('mac')") + public void shouldNotRunOnMacOS() { + System.out.println("will not run if our os.name is mac"); + } + + @Test + @EnabledIf(value = { + "load('nashorn:mozilla_compat.js')", + "importPackage(java.time)", + "", + "var thisMonth = LocalDate.now().getMonth().name()", + "var february = Month.FEBRUARY.name()", + "thisMonth.equals(february)" + }, + engine = "nashorn", + reason = "Self-fulfilling: {result}") + public void onlyRunsInFebruary() { + System.out.println("this test only runs in February"); + } + + @Test + @DisabledIf("systemEnvironment.get('XPC_SERVICE_NAME') != null " + + "&& systemEnvironment.get('XPC_SERVICE_NAME').contains('intellij')") + public void notValidForIntelliJ() { + System.out.println("this test will run if our ide is INTELLIJ"); + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + @Test + @DisabledOnOs({OS.WINDOWS, OS.SOLARIS, OS.OTHER}) + @EnabledOnJre({JRE.JAVA_9, JRE.JAVA_10, JRE.JAVA_11}) + @interface ThisTestWillOnlyRunAtLinuxAndMacWithJava9Or10Or11 { + } + + @ThisTestWillOnlyRunAtLinuxAndMacWithJava9Or10Or11 + public void someSuperTestMethodHere() { + System.out.println("this method will run with java9, 10, 11 and Linux or macOS."); + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + @DisabledIf("Math.random() >= 0.5") + @interface CoinToss { + } + + @RepeatedTest(2) + @CoinToss + public void gamble() { + System.out.println("This tests run status is a gamble with %50 rate"); + } +} diff --git a/testing-modules/junit5-migration/README.md b/testing-modules/junit5-migration/README.md deleted file mode 100644 index 5fe7fc1f16..0000000000 --- a/testing-modules/junit5-migration/README.md +++ /dev/null @@ -1,3 +0,0 @@ -### Relevant Articles: -- [JUnit4 -> JUnit5 migration guide](http://www.baeldung.com/junit4-junit5-migration-guide) - diff --git a/testing-modules/mockito/README.md b/testing-modules/mockito/README.md index 158a1918e7..59954784f9 100644 --- a/testing-modules/mockito/README.md +++ b/testing-modules/mockito/README.md @@ -7,7 +7,7 @@ - [Mockito Verify Cookbook](http://www.baeldung.com/mockito-verify) - [Mockito When/Then Cookbook](http://www.baeldung.com/mockito-behavior) - [Mockito – Using Spies](http://www.baeldung.com/mockito-spy) -- [Mockito – @Mock, @Spy, @Captor and @InjectMocks](http://www.baeldung.com/mockito-annotations) +- [Getting Started with Mockito @Mock, @Spy, @Captor and @InjectMocks](http://www.baeldung.com/mockito-annotations) - [Mockito’s Mock Methods](http://www.baeldung.com/mockito-mock-methods) - [Introduction to PowerMock](http://www.baeldung.com/intro-to-powermock) - [Mocking Exception Throwing using Mockito](http://www.baeldung.com/mockito-exceptions) diff --git a/testing-modules/mockito/src/test/java/org/baeldung/mockito/misusing/MockitoMisusingUnitTest.java b/testing-modules/mockito/src/test/java/org/baeldung/mockito/misusing/MockitoMisusingUnitTest.java new file mode 100644 index 0000000000..306f53297a --- /dev/null +++ b/testing-modules/mockito/src/test/java/org/baeldung/mockito/misusing/MockitoMisusingUnitTest.java @@ -0,0 +1,38 @@ +package org.baeldung.mockito.misusing; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.exceptions.misusing.NotAMockException; +import org.mockito.internal.progress.ThreadSafeMockingProgress; + +public class MockitoMisusingUnitTest { + + @After + public void tearDown() { + ThreadSafeMockingProgress.mockingProgress().reset(); + } + + @Test + public void givenNotASpy_whenDoReturn_thenThrowNotAMock() { + try { + List list = new ArrayList(); + + Mockito.doReturn(100, Mockito.withSettings().lenient()) + .when(list) + .size(); + + fail("Should have thrown a NotAMockException because 'list' is not a mock!"); + } catch (NotAMockException e) { + assertThat(e.getMessage(), containsString("Argument passed to when() is not a mock!")); + } + } + +} diff --git a/testing-modules/mocks/README.md b/testing-modules/mocks/README.md index 2b24ed8536..3cb20dcf92 100644 --- a/testing-modules/mocks/README.md +++ b/testing-modules/mocks/README.md @@ -1,8 +1,4 @@ ## Relevant articles: -- [JMockit Advanced Usage](http://www.baeldung.com/jmockit-advanced-usage) -- [A Guide to JMockit Expectations](http://www.baeldung.com/jmockit-expectations) -- [JMockit 101](http://www.baeldung.com/jmockit-101) -- [Mockito vs EasyMock vs JMockit](http://www.baeldung.com/mockito-vs-easymock-vs-jmockit) - [EasyMock Argument Matchers](http://www.baeldung.com/easymock-argument-matchers) - [Mock Static Method using JMockit](https://www.baeldung.com/jmockit-static-method) diff --git a/testing-modules/mocks/jmockit/README.md b/testing-modules/mocks/jmockit/README.md index 3063fdc31d..0e44b93d6e 100644 --- a/testing-modules/mocks/jmockit/README.md +++ b/testing-modules/mocks/jmockit/README.md @@ -6,5 +6,4 @@ ### Relevant Articles: - [JMockit 101](http://www.baeldung.com/jmockit-101) - [A Guide to JMockit Expectations](http://www.baeldung.com/jmockit-expectations) -- [JMockit Advanced Topics](http://www.baeldung.com/jmockit-advanced-topics) - [JMockit Advanced Usage](http://www.baeldung.com/jmockit-advanced-usage) diff --git a/testing-modules/pom.xml b/testing-modules/pom.xml new file mode 100644 index 0000000000..39047fb756 --- /dev/null +++ b/testing-modules/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + testing-modules + testing-modules + pom + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + .. + + + + gatling + groovy-spock + junit-5 + junit5-migration + load-testing-comparison + mockito + mockito-2 + mocks + mockserver + parallel-tests-junit + rest-assured + rest-testing + + selenium-junit-testng + spring-testing + test-containers + testing + testng + + diff --git a/testing-modules/rest-assured/pom.xml b/testing-modules/rest-assured/pom.xml index 687a9a2fe4..cd342ccd11 100644 --- a/testing-modules/rest-assured/pom.xml +++ b/testing-modules/rest-assured/pom.xml @@ -8,16 +8,34 @@ com.baeldung - parent-java + parent-boot-2 0.0.1-SNAPSHOT - ../../parent-java + ../../parent-boot-2 + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-json + + + org.springframework.boot + spring-boot-starter-test + test + + + com.google.guava + guava + ${guava.version} + javax.servlet javax.servlet-api - ${javax.servlet-api.version} javax.servlet @@ -27,49 +45,40 @@ org.eclipse.jetty jetty-security - ${jetty.version} org.eclipse.jetty jetty-servlet - ${jetty.version} org.eclipse.jetty jetty-servlets - ${jetty.version} org.eclipse.jetty jetty-io - ${jetty.version} org.eclipse.jetty jetty-http - ${jetty.version} org.eclipse.jetty jetty-server - ${jetty.version} org.eclipse.jetty jetty-util - ${jetty.version} org.apache.httpcomponents httpcore - ${httpcore.version} org.apache.commons commons-lang3 - ${commons-lang3.version} @@ -93,18 +102,15 @@ joda-time joda-time - ${joda-time.version} com.fasterxml.jackson.core jackson-annotations - ${jackson.version} com.fasterxml.jackson.core jackson-databind - ${jackson.version} @@ -128,7 +134,6 @@ org.apache.httpcomponents httpclient - ${httpclient.version} @@ -142,17 +147,6 @@ wiremock ${wiremock.version} - - io.rest-assured - rest-assured - ${rest-assured.version} - test - - - io.rest-assured - json-schema-validator - ${rest-assured-json-schema-validator.version} - com.github.fge json-schema-validator @@ -168,9 +162,27 @@ commons-collections ${commons-collections.version} + + + + io.rest-assured + rest-assured + test + + + io.rest-assured + spring-mock-mvc + test + + + io.rest-assured + json-schema-validator + test + + 18.0 2.9.7 1.8 19.0 diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/Application.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/Application.java new file mode 100644 index 0000000000..8b53a9c63d --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/Application.java @@ -0,0 +1,13 @@ +package com.baeldung.restassured; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/controller/AppController.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/controller/AppController.java new file mode 100644 index 0000000000..d68ebf4b03 --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/controller/AppController.java @@ -0,0 +1,100 @@ +package com.baeldung.restassured.controller; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.Set; +import java.util.UUID; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.InputStreamResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.restassured.model.Movie; +import com.baeldung.restassured.service.AppService; + +@RestController +public class AppController { + + @Autowired + AppService appService; + + @GetMapping("/movies") + public ResponseEntity getMovies() { + + Set result = appService.getAll(); + + return ResponseEntity.ok() + .body(result); + } + + @PostMapping("/movie") + @ResponseStatus(HttpStatus.CREATED) + public Movie addMovie(@RequestBody Movie movie) { + + appService.add(movie); + return movie; + } + + @GetMapping("/movie/{id}") + public ResponseEntity getMovie(@PathVariable int id) { + + Movie movie = appService.findMovie(id); + if (movie == null) { + return ResponseEntity.badRequest() + .body("Invalid movie id"); + } + + return ResponseEntity.ok(movie); + } + + @GetMapping("/welcome") + public ResponseEntity welcome(HttpServletResponse response) { + + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8"); + headers.add("sessionId", UUID.randomUUID() + .toString()); + + Cookie cookie = new Cookie("token", "some-token"); + cookie.setDomain("localhost"); + + response.addCookie(cookie); + + return ResponseEntity.noContent() + .headers(headers) + .build(); + } + + @GetMapping("/download/{id}") + public ResponseEntity getFile(@PathVariable int id) throws FileNotFoundException { + + File file = appService.getFile(id); + + if (file == null) { + return ResponseEntity.notFound() + .build(); + } + + InputStreamResource resource = new InputStreamResource(new FileInputStream(file)); + + return ResponseEntity.ok() + .contentLength(file.length()) + .contentType(MediaType.parseMediaType("application/octet-stream")) + .body(resource); + } + +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/Course.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/Course.java new file mode 100644 index 0000000000..ac958b3239 --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/Course.java @@ -0,0 +1,17 @@ +package com.baeldung.restassured.learner; + +class Course { + + private String code; + + public Course() { + } + + Course(String code) { + this.code = code; + } + + String getCode() { + return code; + } +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseController.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseController.java new file mode 100644 index 0000000000..f4a3f56608 --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseController.java @@ -0,0 +1,31 @@ +package com.baeldung.restassured.learner; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collection; + +import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE; + +@RestController +@RequestMapping(path = "/courses") +public class CourseController { + + private final CourseService courseService; + + public CourseController(CourseService courseService) { + this.courseService = courseService; + } + + @GetMapping(produces = APPLICATION_JSON_UTF8_VALUE) + public Collection getCourses() { + return courseService.getCourses(); + } + + @GetMapping(path = "/{code}", produces = APPLICATION_JSON_UTF8_VALUE) + public Course getCourse(@PathVariable String code) { + return courseService.getCourse(code); + } +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseControllerExceptionHandler.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseControllerExceptionHandler.java new file mode 100644 index 0000000000..b17e95c31c --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseControllerExceptionHandler.java @@ -0,0 +1,18 @@ +package com.baeldung.restassured.learner; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +@ControllerAdvice(assignableTypes = CourseController.class) +public class CourseControllerExceptionHandler extends ResponseEntityExceptionHandler { + + @ResponseStatus(HttpStatus.NOT_FOUND) + @ExceptionHandler(CourseNotFoundException.class) + @SuppressWarnings("ThrowablePrintedToSystemOut") + public void handleCourseNotFoundException(CourseNotFoundException cnfe) { + System.out.println(cnfe); + } +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseNotFoundException.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseNotFoundException.java new file mode 100644 index 0000000000..dc1a3f796d --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseNotFoundException.java @@ -0,0 +1,8 @@ +package com.baeldung.restassured.learner; + +class CourseNotFoundException extends RuntimeException { + + CourseNotFoundException(String code) { + super(code); + } +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseService.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseService.java new file mode 100644 index 0000000000..11508ab9ba --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/learner/CourseService.java @@ -0,0 +1,27 @@ +package com.baeldung.restassured.learner; + +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +@Service +class CourseService { + + private static final Map COURSE_MAP = new ConcurrentHashMap<>(); + + static { + Course wizardry = new Course("Wizardry"); + COURSE_MAP.put(wizardry.getCode(), wizardry); + } + + Collection getCourses() { + return COURSE_MAP.values(); + } + + Course getCourse(String code) { + return Optional.ofNullable(COURSE_MAP.get(code)).orElseThrow(() -> new CourseNotFoundException(code)); + } +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/model/Movie.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/model/Movie.java new file mode 100644 index 0000000000..00a446fc65 --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/model/Movie.java @@ -0,0 +1,58 @@ +package com.baeldung.restassured.model; + +public class Movie { + + private Integer id; + + private String name; + + private String synopsis; + + public Movie() { + } + + public Movie(Integer id, String name, String synopsis) { + super(); + this.id = id; + this.name = name; + this.synopsis = synopsis; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public String getSynopsis() { + return synopsis; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Movie other = (Movie) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + +} diff --git a/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/service/AppService.java b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/service/AppService.java new file mode 100644 index 0000000000..15685f2924 --- /dev/null +++ b/testing-modules/rest-assured/src/main/java/com/baeldung/restassured/service/AppService.java @@ -0,0 +1,45 @@ +package com.baeldung.restassured.service; + +import java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +import com.baeldung.restassured.model.Movie; + +@Service +public class AppService { + + private Set movieSet = new HashSet<>(); + + public Set getAll() { + return movieSet; + } + + public void add(Movie movie) { + movieSet.add(movie); + } + + public Movie findMovie(int id) { + return movieSet.stream() + .filter(movie -> movie.getId() + .equals(id)) + .findFirst() + .orElse(null); + } + + public File getFile(int id) { + File file = null; + try { + file = new ClassPathResource(String.valueOf(id)).getFile(); + } catch (IOException e) { + e.printStackTrace(); + } + + return file; + } + +} diff --git a/testing-modules/rest-assured/src/main/resources/1 b/testing-modules/rest-assured/src/main/resources/1 new file mode 100644 index 0000000000..49351eb5b7 --- /dev/null +++ b/testing-modules/rest-assured/src/main/resources/1 @@ -0,0 +1 @@ +File 1 \ No newline at end of file diff --git a/testing-modules/rest-assured/src/main/resources/2 b/testing-modules/rest-assured/src/main/resources/2 new file mode 100644 index 0000000000..9fbb45ed08 --- /dev/null +++ b/testing-modules/rest-assured/src/main/resources/2 @@ -0,0 +1 @@ +File 2 \ No newline at end of file diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/controller/AppControllerIntegrationTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/controller/AppControllerIntegrationTest.java new file mode 100644 index 0000000000..a55c0a69e4 --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/controller/AppControllerIntegrationTest.java @@ -0,0 +1,149 @@ +package com.baeldung.restassured.controller; + +import static io.restassured.RestAssured.get; +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.annotation.PostConstruct; + +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.restassured.model.Movie; +import com.baeldung.restassured.service.AppService; + +import io.restassured.response.Response; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class AppControllerIntegrationTest { + + @LocalServerPort + private int port; + + private String uri; + + @PostConstruct + public void init() { + uri = "http://localhost:" + port; + } + + @MockBean + AppService appService; + + @Test + public void givenMovieId_whenMakingGetRequestToMovieEndpoint_thenReturnMovie() { + + Movie testMovie = new Movie(1, "movie1", "summary1"); + when(appService.findMovie(1)).thenReturn(testMovie); + + get(uri + "/movie/" + testMovie.getId()).then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .body("id", equalTo(testMovie.getId())) + .body("name", equalTo(testMovie.getName())) + .body("synopsis", notNullValue()); + + Movie result = get(uri + "/movie/" + testMovie.getId()).then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .extract() + .as(Movie.class); + assertThat(result).isEqualTo(testMovie); + + String responseString = get(uri + "/movie/" + testMovie.getId()).then() + .assertThat() + .statusCode(HttpStatus.OK.value()) + .extract() + .asString(); + assertThat(responseString).isNotEmpty(); + } + + @Test + public void whenCallingMoviesEndpoint_thenReturnAllMovies() { + + Set movieSet = new HashSet<>(); + movieSet.add(new Movie(1, "movie1", "summary1")); + movieSet.add(new Movie(2, "movie2", "summary2")); + when(appService.getAll()).thenReturn(movieSet); + + get(uri + "/movies").then() + .statusCode(HttpStatus.OK.value()) + .assertThat() + .body("size()", is(2)); + + Movie[] movies = get(uri + "/movies").then() + .statusCode(200) + .extract() + .as(Movie[].class); + assertThat(movies.length).isEqualTo(2); + } + + @Test + public void givenMovie_whenMakingPostRequestToMovieEndpoint_thenCorrect() { + + Map request = new HashMap<>(); + request.put("id", "11"); + request.put("name", "movie1"); + request.put("synopsis", "summary1"); + + int movieId = given().contentType("application/json") + .body(request) + .when() + .post(uri + "/movie") + .then() + .assertThat() + .statusCode(HttpStatus.CREATED.value()) + .extract() + .path("id"); + assertThat(movieId).isEqualTo(11); + + } + + @Test + public void whenCallingWelcomeEndpoint_thenCorrect() { + + get(uri + "/welcome").then() + .assertThat() + .header("sessionId", notNullValue()) + .cookie("token", notNullValue()); + + Response response = get(uri + "/welcome"); + + String headerName = response.getHeader("sessionId"); + String cookieValue = response.getCookie("token"); + assertThat(headerName).isNotBlank(); + assertThat(cookieValue).isNotBlank(); + } + + @Test + public void givenId_whenCallingDowloadEndpoint_thenCorrect() throws IOException { + + File file = new ClassPathResource("test.txt").getFile(); + long fileSize = file.length(); + when(appService.getFile(1)).thenReturn(file); + + byte[] result = get(uri + "/download/1").asByteArray(); + + assertThat(result.length).isEqualTo(fileSize); + } + +} diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerIntegrationTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerIntegrationTest.java new file mode 100644 index 0000000000..5e36cd169b --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerIntegrationTest.java @@ -0,0 +1,40 @@ +package com.baeldung.restassured.learner; + +import static io.restassured.module.mockmvc.RestAssuredMockMvc.given; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.springframework.http.HttpStatus.NOT_FOUND; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.context.WebApplicationContext; + +import io.restassured.module.mockmvc.RestAssuredMockMvc; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT) +public class CourseControllerIntegrationTest { + + @Autowired + private WebApplicationContext webApplicationContext; + + @Before + public void initialiseRestAssuredMockMvcWebApplicationContext() { + RestAssuredMockMvc.webAppContextSetup(webApplicationContext); + } + + @Test + public void givenNoMatchingCourseCodeWhenGetCourseThenRespondWithStatusNotFound() { + String nonMatchingCourseCode = "nonMatchingCourseCode"; + + given() + .when() + .get("/courses/" + nonMatchingCourseCode) + .then() + .log().ifValidationFails() + .statusCode(NOT_FOUND.value()); + } +} diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerUnitTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerUnitTest.java new file mode 100644 index 0000000000..2a795e2b0b --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/learner/CourseControllerUnitTest.java @@ -0,0 +1,63 @@ +package com.baeldung.restassured.learner; + +import io.restassured.module.mockmvc.RestAssuredMockMvc; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Collections; + +import static io.restassured.http.ContentType.JSON; +import static io.restassured.module.mockmvc.RestAssuredMockMvc.given; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.when; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.OK; + +@RunWith(MockitoJUnitRunner.class) +public class CourseControllerUnitTest { + + @Mock + private CourseService courseService; + @InjectMocks + private CourseController courseController; + @InjectMocks + private CourseControllerExceptionHandler courseControllerExceptionHandler; + + @Before + public void initialiseRestAssuredMockMvcStandalone() { + RestAssuredMockMvc.standaloneSetup(courseController, courseControllerExceptionHandler); + } + + @Test + public void givenNoExistingCoursesWhenGetCoursesThenRespondWithStatusOkAndEmptyArray() { + when(courseService.getCourses()).thenReturn(Collections.emptyList()); + + given() + .when() + .get("/courses") + .then() + .log().ifValidationFails() + .statusCode(OK.value()) + .contentType(JSON) + .body(is(equalTo("[]"))); + } + + @Test + public void givenNoMatchingCoursesWhenGetCoursesThenRespondWithStatusNotFound() { + String nonMatchingCourseCode = "nonMatchingCourseCode"; + + when(courseService.getCourse(nonMatchingCourseCode)).thenThrow(new CourseNotFoundException(nonMatchingCourseCode)); + + given() + .when() + .get("/courses/" + nonMatchingCourseCode) + .then() + .log().ifValidationFails() + .statusCode(NOT_FOUND.value()); + } +} diff --git a/testing-modules/rest-assured/src/test/resources/test.txt b/testing-modules/rest-assured/src/test/resources/test.txt new file mode 100644 index 0000000000..84362ca046 --- /dev/null +++ b/testing-modules/rest-assured/src/test/resources/test.txt @@ -0,0 +1 @@ +Test file \ No newline at end of file diff --git a/testing-modules/rest-testing/README.md b/testing-modules/rest-testing/README.md index ab038807bc..25e036ba5d 100644 --- a/testing-modules/rest-testing/README.md +++ b/testing-modules/rest-testing/README.md @@ -8,6 +8,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: - [Test a REST API with Java](http://www.baeldung.com/integration-testing-a-rest-api) - [Introduction to WireMock](http://www.baeldung.com/introduction-to-wiremock) +- [Using WireMock Scenarios](http://www.baeldung.com/using-wiremock-scenarios) - [REST API Testing with Cucumber](http://www.baeldung.com/cucumber-rest-api-testing) - [Testing a REST API with JBehave](http://www.baeldung.com/jbehave-rest-testing) - [REST API Testing with Karate](http://www.baeldung.com/karate-rest-api-testing) diff --git a/testing-modules/rest-testing/pom.xml b/testing-modules/rest-testing/pom.xml index 2b1f146f0f..c3a9477a47 100644 --- a/testing-modules/rest-testing/pom.xml +++ b/testing-modules/rest-testing/pom.xml @@ -159,7 +159,7 @@ 2.9.0 1.2.5 - 2.4.1 + 2.21.0 0.6.1 4.4.5 diff --git a/testing-modules/rest-testing/src/test/java/com/baeldung/rest/wiremock/scenario/WireMockScenarioExampleIntegrationTest.java b/testing-modules/rest-testing/src/test/java/com/baeldung/rest/wiremock/scenario/WireMockScenarioExampleIntegrationTest.java new file mode 100644 index 0000000000..946d3d717f --- /dev/null +++ b/testing-modules/rest-testing/src/test/java/com/baeldung/rest/wiremock/scenario/WireMockScenarioExampleIntegrationTest.java @@ -0,0 +1,75 @@ +package com.baeldung.rest.wiremock.scenario; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.junit.Rule; +import org.junit.Test; + +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.github.tomakehurst.wiremock.stubbing.Scenario; + +public class WireMockScenarioExampleIntegrationTest { + + private static final String THIRD_STATE = "third"; + private static final String SECOND_STATE = "second"; + private static final String TIP_01 = "finally block is not called when System.exit() is called in the try block"; + private static final String TIP_02 = "keep your code clean"; + private static final String TIP_03 = "use composition rather than inheritance"; + private static final String TEXT_PLAIN = "text/plain"; + + static int port = 9999; + + @Rule + public WireMockRule wireMockRule = new WireMockRule(port); + + @Test + public void changeStateOnEachCallTest() throws IOException { + createWireMockStub(Scenario.STARTED, SECOND_STATE, TIP_01); + createWireMockStub(SECOND_STATE, THIRD_STATE, TIP_02); + createWireMockStub(THIRD_STATE, Scenario.STARTED, TIP_03); + + assertEquals(TIP_01, nextTip()); + assertEquals(TIP_02, nextTip()); + assertEquals(TIP_03, nextTip()); + assertEquals(TIP_01, nextTip()); + } + + private void createWireMockStub(String currentState, String nextState, String responseBody) { + stubFor(get(urlEqualTo("/java-tip")) + .inScenario("java tips") + .whenScenarioStateIs(currentState) + .willReturn(aResponse() + .withStatus(200) + .withHeader("Content-Type", TEXT_PLAIN) + .withBody(responseBody)) + .willSetStateTo(nextState) + ); + } + + private String nextTip() throws ClientProtocolException, IOException { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpGet request = new HttpGet(String.format("http://localhost:%s/java-tip", port)); + HttpResponse httpResponse = httpClient.execute(request); + return firstLineOfResponse(httpResponse); + } + + private static String firstLineOfResponse(HttpResponse httpResponse) throws IOException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()))) { + return reader.readLine(); + } + } + +} diff --git a/testing-modules/spring-testing/README.md b/testing-modules/spring-testing/README.md index 02ab7b24bd..8eb282643a 100644 --- a/testing-modules/spring-testing/README.md +++ b/testing-modules/spring-testing/README.md @@ -3,3 +3,4 @@ - [Mockito.mock() vs @Mock vs @MockBean](http://www.baeldung.com/java-spring-mockito-mock-mockbean) - [A Quick Guide to @TestPropertySource](https://www.baeldung.com/spring-test-property-source) - [Guide to ReflectionTestUtils for Unit Testing](https://www.baeldung.com/spring-reflection-test-utils) +- [How to Test the @Scheduled Annotation](https://www.baeldung.com/spring-testing-scheduled-annotation) diff --git a/testing-modules/spring-testing/pom.xml b/testing-modules/spring-testing/pom.xml index a137bc8d33..630aed0c81 100644 --- a/testing-modules/spring-testing/pom.xml +++ b/testing-modules/spring-testing/pom.xml @@ -54,6 +54,18 @@ spring-data-jpa LATEST
+ + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + org.awaitility + awaitility + ${awaitility.version} + test + @@ -70,6 +82,8 @@ 2.0.0.0 + 3.1.6 + 5.4.0 \ No newline at end of file diff --git a/spring-5/src/main/java/com/baeldung/config/ScheduledConfig.java b/testing-modules/spring-testing/src/main/java/com/baeldung/config/ScheduledConfig.java similarity index 100% rename from spring-5/src/main/java/com/baeldung/config/ScheduledConfig.java rename to testing-modules/spring-testing/src/main/java/com/baeldung/config/ScheduledConfig.java diff --git a/spring-5/src/main/java/com/baeldung/scheduled/Counter.java b/testing-modules/spring-testing/src/main/java/com/baeldung/scheduled/Counter.java similarity index 100% rename from spring-5/src/main/java/com/baeldung/scheduled/Counter.java rename to testing-modules/spring-testing/src/main/java/com/baeldung/scheduled/Counter.java diff --git a/spring-5/src/test/java/com/baeldung/scheduled/ScheduledAwaitilityIntegrationTest.java b/testing-modules/spring-testing/src/test/java/com/baeldung/scheduled/ScheduledAwaitilityIntegrationTest.java similarity index 100% rename from spring-5/src/test/java/com/baeldung/scheduled/ScheduledAwaitilityIntegrationTest.java rename to testing-modules/spring-testing/src/test/java/com/baeldung/scheduled/ScheduledAwaitilityIntegrationTest.java diff --git a/spring-5/src/test/java/com/baeldung/scheduled/ScheduledIntegrationTest.java b/testing-modules/spring-testing/src/test/java/com/baeldung/scheduled/ScheduledIntegrationTest.java similarity index 100% rename from spring-5/src/test/java/com/baeldung/scheduled/ScheduledIntegrationTest.java rename to testing-modules/spring-testing/src/test/java/com/baeldung/scheduled/ScheduledIntegrationTest.java diff --git a/testing-modules/testing/README.md b/testing-modules/testing/README.md index 849b578a55..e96b26ab41 100644 --- a/testing-modules/testing/README.md +++ b/testing-modules/testing/README.md @@ -3,7 +3,7 @@ ## Mutation Testing ### Relevant Articles: -- [Introduction to Mutation Testing Using the PITest Library](http://www.baeldung.com/java-mutation-testing-with-pitest) +- [Mutation Testing with PITest](http://www.baeldung.com/java-mutation-testing-with-pitest) - [Intro to JaCoCo](http://www.baeldung.com/jacoco) - [AssertJ’s Java 8 Features](http://www.baeldung.com/assertJ-java-8-features) - [AssertJ for Guava](http://www.baeldung.com/assertJ-for-guava) diff --git a/vavr/README.md b/vavr/README.md index 0857765ec6..266cae91bb 100644 --- a/vavr/README.md +++ b/vavr/README.md @@ -4,7 +4,7 @@ - [Guide to Pattern Matching in Vavr](http://www.baeldung.com/vavr-pattern-matching) - [Property Testing Example With Vavr](http://www.baeldung.com/vavr-property-testing) - [Exceptions in Lambda Expression Using Vavr](http://www.baeldung.com/exceptions-using-vavr) -- [Vavr (ex-Javaslang) Support in Spring Data](http://www.baeldung.com/spring-vavr) +- [Vavr Support in Spring Data](http://www.baeldung.com/spring-vavr) - [Introduction to Vavr’s Validation API](http://www.baeldung.com/vavr-validation-api) - [Guide to Collections API in Vavr](http://www.baeldung.com/vavr-collections) - [Collection Factory Methods for Vavr](http://www.baeldung.com/vavr-collection-factory-methods) diff --git a/xml/pom.xml b/xml/pom.xml index dfdec4da16..ba6a734dc9 100644 --- a/xml/pom.xml +++ b/xml/pom.xml @@ -30,6 +30,22 @@ ${jdom2.version}
+ + javax.xml + jaxb-api + 2.1 + + + javax.xml + jaxp-api + 1.4.2 + + + javax.xml.stream + stax-api + 1.0-2 + + commons-io diff --git a/xml/src/main/java/com/baeldung/xmlhtml/Application.java b/xml/src/main/java/com/baeldung/xmlhtml/Application.java new file mode 100644 index 0000000000..063a833810 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/Application.java @@ -0,0 +1,10 @@ +package com.baeldung.xmlhtml; + +import com.baeldung.xmlhtml.helpers.XMLRunner; + +public class Application { + + public static void main(String[] args) { + XMLRunner.doWork(); + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/Constants.java b/xml/src/main/java/com/baeldung/xmlhtml/Constants.java new file mode 100644 index 0000000000..88fc5637df --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/Constants.java @@ -0,0 +1,22 @@ +package com.baeldung.xmlhtml; + +public class Constants { + + public static final String XML_FILE_IN = "src/main/resources/xml/in.xml"; + public static final String JAXB_FILE_OUT = "src/main/resources/xml/jaxb.html"; + public static final String JAXP_FILE_OUT = "src/main/resources/xml/jaxp.html"; + public static final String STAX_FILE_OUT = "src/main/resources/xml/stax.html"; + + public static final String EXCEPTION_ENCOUNTERED = "Generic exception! Error: "; + + public static final String LINE_BREAK = System.getProperty("line.separator"); + public static final String WHITE_SPACE = " "; + + public static final String DOCUMENT_START = "Document parsing has begun!"; + public static final String DOCUMENT_END = "Document parsing has ended!"; + public static final String ELEMENT_START = "Element parsing has begun!"; + public static final String ELEMENT_END = "Element parsing has ended!"; + + public static final String BREAK = "\n"; + public static final String TAB = "\t"; +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/helpers/XMLRunner.java b/xml/src/main/java/com/baeldung/xmlhtml/helpers/XMLRunner.java new file mode 100644 index 0000000000..02b2577795 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/helpers/XMLRunner.java @@ -0,0 +1,16 @@ +package com.baeldung.xmlhtml.helpers; + + +import com.baeldung.xmlhtml.helpers.jaxb.JAXBHelper; +import com.baeldung.xmlhtml.helpers.jaxp.JAXPHelper; +import com.baeldung.xmlhtml.helpers.stax.STAXHelper; + +public class XMLRunner { + + public static void doWork() { + JAXBHelper.example(); + JAXPHelper.saxParser(); + JAXPHelper.documentBuilder(); + STAXHelper.write(STAXHelper.read()); + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxb/JAXBHelper.java b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxb/JAXBHelper.java new file mode 100644 index 0000000000..715f963f2e --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxb/JAXBHelper.java @@ -0,0 +1,77 @@ +package com.baeldung.xmlhtml.helpers.jaxb; + +import com.baeldung.xmlhtml.pojo.jaxb.html.ExampleHTML; +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.Body; +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.CustomElement; +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.Meta; +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.NestedElement; +import com.baeldung.xmlhtml.pojo.jaxb.xml.XMLExample; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; + +import java.io.File; + +import static com.baeldung.xmlhtml.Constants.*; + +public class JAXBHelper { + + private static void print(String xmlContent) { + System.out.println(xmlContent); + } + + private static Unmarshaller getContextUnmarshaller(Class clazz) { + Unmarshaller unmarshaller = null; + try { + JAXBContext context = JAXBContext.newInstance(clazz); + unmarshaller = context.createUnmarshaller(); + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + return unmarshaller; + } + + private static Marshaller getContextMarshaller(Class clazz) { + Marshaller marshaller = null; + try { + JAXBContext context = JAXBContext.newInstance(clazz); + marshaller = context.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.setProperty("jaxb.fragment", Boolean.TRUE); + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + return marshaller; + } + + public static void example() { + try { + XMLExample xml = (XMLExample) JAXBHelper.getContextUnmarshaller(XMLExample.class).unmarshal(new File(XML_FILE_IN)); + JAXBHelper.print(xml.toString()); + ExampleHTML html = new ExampleHTML(); + + Body body = new Body(); + CustomElement customElement = new CustomElement(); + NestedElement nested = new NestedElement(); + CustomElement child = new CustomElement(); + + customElement.setValue("descendantOne: " + xml.getAncestor().getDescendantOne().getValue()); + child.setValue("descendantThree: " + xml.getAncestor().getDescendantTwo().getDescendantThree().getValue()); + nested.setCustomElement(child); + + body.setCustomElement(customElement); + body.setNestedElement(nested); + + Meta meta = new Meta(); + meta.setTitle("example"); + html.getHead().add(meta); + html.setBody(body); + + JAXBHelper.getContextMarshaller(ExampleHTML.class).marshal(html, new File(JAXB_FILE_OUT)); + + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + } +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/CustomHandler.java b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/CustomHandler.java new file mode 100644 index 0000000000..e6351c9e22 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/CustomHandler.java @@ -0,0 +1,34 @@ +package com.baeldung.xmlhtml.helpers.jaxp; + +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; + +import static com.baeldung.xmlhtml.Constants.*; + +public class CustomHandler implements ContentHandler { + + public void startDocument() {} + + public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes atts) { } + + public void endDocument() { + System.out.println(DOCUMENT_END); + } + + public void endElement(String uri, String localName, String qName) { } + + public void startPrefixMapping(String prefix, String uri) { } + + public void endPrefixMapping(String prefix) { } + + public void setDocumentLocator(Locator locator) { } + + public void characters(char[] ch, int start, int length) { } + + public void ignorableWhitespace(char[] ch, int start, int length) { } + + public void processingInstruction(String target, String data) { } + + public void skippedEntity(String name) { } + +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/JAXPHelper.java b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/JAXPHelper.java new file mode 100644 index 0000000000..3196d543da --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/helpers/jaxp/JAXPHelper.java @@ -0,0 +1,90 @@ +package com.baeldung.xmlhtml.helpers.jaxp; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.XMLReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.File; + +import static com.baeldung.xmlhtml.Constants.*; + +public class JAXPHelper { + + private static void print(Document document) { + NodeList list = document.getChildNodes(); + try { + for (int i = 0; i < list.getLength(); i++) { + Node node = list.item(i); + String message = + node.getNodeType() + + WHITE_SPACE + + node.getNodeName() + + LINE_BREAK; + System.out.println(message); + } + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + } + + public static void saxParser() { + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setNamespaceAware(true); + try { + SAXParser saxParser = spf.newSAXParser(); + XMLReader xmlReader = saxParser.getXMLReader(); + xmlReader.setContentHandler(new CustomHandler()); + xmlReader.parse(XML_FILE_IN); + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + } + + public static void documentBuilder() { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + try { + DocumentBuilder db = dbf.newDocumentBuilder(); + Document parsed = db.parse(new File(XML_FILE_IN)); + Element xml = parsed.getDocumentElement(); + + Document doc = db.newDocument(); + Element html = doc.createElement("html"); + Element head = doc.createElement("head"); + html.appendChild(head); + + Element body = doc.createElement("body"); + Element descendantOne = doc.createElement("p"); + descendantOne.setTextContent("descendantOne: " + + xml.getElementsByTagName("descendantOne") + .item(0).getTextContent()); + Element descendantThree = doc.createElement("p"); + descendantThree.setTextContent("descendantThree: " + + xml.getElementsByTagName("descendantThree") + .item(0).getTextContent()); + Element nested = doc.createElement("div"); + nested.appendChild(descendantThree); + + body.appendChild(descendantOne); + body.appendChild(nested); + html.appendChild(body); + doc.appendChild(html); + + TransformerFactory tFactory = TransformerFactory.newInstance(); + tFactory + .newTransformer() + .transform(new DOMSource(doc), new StreamResult(new File(JAXP_FILE_OUT))); + + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/helpers/stax/STAXHelper.java b/xml/src/main/java/com/baeldung/xmlhtml/helpers/stax/STAXHelper.java new file mode 100644 index 0000000000..a9b9217b6a --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/helpers/stax/STAXHelper.java @@ -0,0 +1,112 @@ +package com.baeldung.xmlhtml.helpers.stax; + +import com.baeldung.xmlhtml.pojo.stax.Body; +import com.baeldung.xmlhtml.pojo.stax.CustomElement; +import com.baeldung.xmlhtml.pojo.stax.NestedElement; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import java.io.FileInputStream; +import java.io.FileWriter; + +import static com.baeldung.xmlhtml.Constants.*; + +public class STAXHelper { + + private static XMLStreamReader reader() { + XMLStreamReader xmlStreamReader = null; + try { + xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(new FileInputStream(XML_FILE_IN)); + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + return xmlStreamReader; + } + + private static XMLStreamWriter writer() { + XMLStreamWriter xmlStreamWriter = null; + try { + xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(new FileWriter(STAX_FILE_OUT)); + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + return xmlStreamWriter; + } + + public static Body read() { + Body body = new Body(); + try { + XMLStreamReader xmlStreamReader = reader(); + + CustomElement customElement = new CustomElement(); + NestedElement nestedElement = new NestedElement(); + CustomElement child = new CustomElement(); + + while (xmlStreamReader.hasNext()) { + xmlStreamReader.next(); + if (xmlStreamReader.isStartElement()) { + System.out.println(xmlStreamReader.getLocalName()); + if (xmlStreamReader.getLocalName().equals("descendantOne")) { + customElement.setValue(xmlStreamReader.getElementText()); + } + if (xmlStreamReader.getLocalName().equals("descendantThree")) { + child.setValue(xmlStreamReader.getElementText()); + } + } + } + + nestedElement.setCustomElement(child); + body.setCustomElement(customElement); + body.setNestedElement(nestedElement); + + xmlStreamReader.close(); + + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + return body; + } + + public static void write(Body body) { + try { + + XMLStreamWriter xmlStreamWriter = writer(); + xmlStreamWriter.writeStartElement("html"); + xmlStreamWriter.writeCharacters(BREAK + TAB); + xmlStreamWriter.writeStartElement("head"); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB); + xmlStreamWriter.writeStartElement("meta"); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK + TAB); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK + TAB); + xmlStreamWriter.writeStartElement("body"); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB); + xmlStreamWriter.writeStartElement("p"); + xmlStreamWriter.writeCharacters("descendantOne: " + body.getCustomElement().getValue()); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB); + xmlStreamWriter.writeStartElement("div"); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB + TAB); + xmlStreamWriter.writeStartElement("p"); + xmlStreamWriter.writeCharacters(BREAK); + xmlStreamWriter.writeCharacters(TAB + TAB + TAB + TAB + "descendantThree: " + body.getNestedElement().getCustomElement().getValue()); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB + TAB); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK + TAB + TAB); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK + TAB); + xmlStreamWriter.writeEndElement(); + xmlStreamWriter.writeCharacters(BREAK); + xmlStreamWriter.writeEndDocument(); + xmlStreamWriter.flush(); + xmlStreamWriter.close(); + + } catch (Exception ex) { + System.out.println(EXCEPTION_ENCOUNTERED + ex); + } + + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/ExampleHTML.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/ExampleHTML.java new file mode 100644 index 0000000000..d44c81f309 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/ExampleHTML.java @@ -0,0 +1,38 @@ +package com.baeldung.xmlhtml.pojo.jaxb.html; + +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.Body; +import com.baeldung.xmlhtml.pojo.jaxb.html.elements.Meta; + +import javax.xml.bind.annotation.*; +import java.util.ArrayList; +import java.util.List; + +@XmlType(propOrder = {"head", "body"}) +@XmlRootElement(name = "html") +public class ExampleHTML { + + private List head = new ArrayList<>(); + + private Body body; + + public ExampleHTML() { } + + public List getHead() { + return head; + } + + @XmlElementWrapper(name = "head") + @XmlElement(name = "meta") + public void setHead(List head) { + this.head = head; + } + + public Body getBody() { + return body; + } + + @XmlElement(name = "body") + public void setBody(Body body) { + this.body = body; + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Body.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Body.java new file mode 100644 index 0000000000..36c6c13a04 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Body.java @@ -0,0 +1,29 @@ +package com.baeldung.xmlhtml.pojo.jaxb.html.elements; + +import javax.xml.bind.annotation.XmlElement; + +public class Body { + + private CustomElement customElement; + + public CustomElement getCustomElement() { + return customElement; + } + + @XmlElement(name = "p") + public void setCustomElement(CustomElement customElement) { + this.customElement = customElement; + } + + private NestedElement nestedElement; + + public NestedElement getNestedElement() { + return nestedElement; + } + + @XmlElement(name = "div") + public void setNestedElement(NestedElement nestedElement) { + this.nestedElement = nestedElement; + } + +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/CustomElement.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/CustomElement.java new file mode 100644 index 0000000000..832c5e746e --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/CustomElement.java @@ -0,0 +1,18 @@ +package com.baeldung.xmlhtml.pojo.jaxb.html.elements; + +import javax.xml.bind.annotation.XmlValue; + +public class CustomElement { + + private String value; + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Meta.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Meta.java new file mode 100644 index 0000000000..11b6b86c05 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/Meta.java @@ -0,0 +1,30 @@ +package com.baeldung.xmlhtml.pojo.jaxb.html.elements; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlValue; + +public class Meta { + + private String title; + + public String getTitle() { + return title; + } + + @XmlAttribute(name = "title") + public void setTitle(String title) { + this.title = title; + } + + private String value; + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/NestedElement.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/NestedElement.java new file mode 100644 index 0000000000..20557064bb --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/html/elements/NestedElement.java @@ -0,0 +1,17 @@ +package com.baeldung.xmlhtml.pojo.jaxb.html.elements; + +import javax.xml.bind.annotation.XmlElement; + +public class NestedElement { + + private CustomElement customElement; + + public CustomElement getCustomElement() { + return customElement; + } + + @XmlElement(name = "p") + public void setCustomElement(CustomElement customElement) { + this.customElement = customElement; + } +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/XMLExample.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/XMLExample.java new file mode 100644 index 0000000000..587cf69223 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/XMLExample.java @@ -0,0 +1,21 @@ +package com.baeldung.xmlhtml.pojo.jaxb.xml; + +import com.baeldung.xmlhtml.pojo.jaxb.xml.elements.Ancestor; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "xmlexample") +public class XMLExample { + + private Ancestor ancestor; + + @XmlElement(name = "ancestor") + public void setAncestor(Ancestor ancestor) { + this.ancestor = ancestor; + } + + public Ancestor getAncestor() { + return ancestor; + } +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/Ancestor.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/Ancestor.java new file mode 100644 index 0000000000..ff2b928206 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/Ancestor.java @@ -0,0 +1,28 @@ +package com.baeldung.xmlhtml.pojo.jaxb.xml.elements; + +import javax.xml.bind.annotation.XmlElement; + +public class Ancestor { + + private DescendantOne descendantOne; + private DescendantTwo descendantTwo; + + public DescendantOne getDescendantOne() { + return descendantOne; + } + + @XmlElement(name = "descendantOne") + public void setDescendantOne(DescendantOne descendantOne) { + this.descendantOne = descendantOne; + } + + public DescendantTwo getDescendantTwo() { + return descendantTwo; + } + + @XmlElement(name = "descendantTwo") + public void setDescendantTwo(DescendantTwo descendantTwo) { + this.descendantTwo = descendantTwo; + } +} + diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantOne.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantOne.java new file mode 100644 index 0000000000..50624cb9fa --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantOne.java @@ -0,0 +1,19 @@ +package com.baeldung.xmlhtml.pojo.jaxb.xml.elements; + +import javax.xml.bind.annotation.XmlValue; + +public class DescendantOne { + + private String value; + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} + diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantThree.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantThree.java new file mode 100644 index 0000000000..7c3ce9b6f7 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantThree.java @@ -0,0 +1,18 @@ +package com.baeldung.xmlhtml.pojo.jaxb.xml.elements; + +import javax.xml.bind.annotation.XmlValue; + +public class DescendantThree { + + private String value; + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantTwo.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantTwo.java new file mode 100644 index 0000000000..1ca989560b --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/jaxb/xml/elements/DescendantTwo.java @@ -0,0 +1,17 @@ +package com.baeldung.xmlhtml.pojo.jaxb.xml.elements; + +import javax.xml.bind.annotation.XmlElement; + +public class DescendantTwo { + + private DescendantThree descendantThree; + + public DescendantThree getDescendantThree() { + return descendantThree; + } + + @XmlElement(name = "descendantThree") + public void setDescendant(DescendantThree descendantThree) { + this.descendantThree = descendantThree; + } +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/Body.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/Body.java new file mode 100644 index 0000000000..630dfe967f --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/Body.java @@ -0,0 +1,23 @@ +package com.baeldung.xmlhtml.pojo.stax; + +public class Body { + + private CustomElement customElement; + + public CustomElement getCustomElement() { + return customElement; + } + public void setCustomElement(CustomElement customElement) { + this.customElement = customElement; + } + + private NestedElement nestedElement; + + public NestedElement getNestedElement() { + return nestedElement; + } + public void setNestedElement(NestedElement nestedElement) { + this.nestedElement = nestedElement; + } + +} \ No newline at end of file diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/CustomElement.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/CustomElement.java new file mode 100644 index 0000000000..6fc1d7b787 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/CustomElement.java @@ -0,0 +1,13 @@ +package com.baeldung.xmlhtml.pojo.stax; + +public class CustomElement { + + private String value; + + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } +} diff --git a/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/NestedElement.java b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/NestedElement.java new file mode 100644 index 0000000000..146ee068af --- /dev/null +++ b/xml/src/main/java/com/baeldung/xmlhtml/pojo/stax/NestedElement.java @@ -0,0 +1,13 @@ +package com.baeldung.xmlhtml.pojo.stax; + +public class NestedElement { + + private CustomElement customElement; + + public CustomElement getCustomElement() { + return customElement; + } + public void setCustomElement(CustomElement customElement) { + this.customElement = customElement; + } +} diff --git a/xml/src/main/resources/xml/in.xml b/xml/src/main/resources/xml/in.xml new file mode 100644 index 0000000000..6fcb404012 --- /dev/null +++ b/xml/src/main/resources/xml/in.xml @@ -0,0 +1,11 @@ + + + + Yo + + + DustyOrb + + + + \ No newline at end of file diff --git a/xml/src/main/resources/xml/jaxb.html b/xml/src/main/resources/xml/jaxb.html new file mode 100644 index 0000000000..80b894cff7 --- /dev/null +++ b/xml/src/main/resources/xml/jaxb.html @@ -0,0 +1,14 @@ + + + + + + +

descendantOne: Yo

+
+

descendantThree: + DustyOrb +

+
+ + diff --git a/xml/src/main/resources/xml/jaxp.html b/xml/src/main/resources/xml/jaxp.html new file mode 100644 index 0000000000..5392eef509 --- /dev/null +++ b/xml/src/main/resources/xml/jaxp.html @@ -0,0 +1,13 @@ + + + + + +

descendantOne: Yo

+
+

descendantThree: + DustyOrb +

+
+ + diff --git a/xml/src/main/resources/xml/stax.html b/xml/src/main/resources/xml/stax.html new file mode 100644 index 0000000000..01951dc7de --- /dev/null +++ b/xml/src/main/resources/xml/stax.html @@ -0,0 +1,15 @@ + + + + + +

descendantOne: Yo

+
+

+ descendantThree: + DustyOrb + +

+
+ + \ No newline at end of file