diff --git a/algorithms-miscellaneous-3/pom.xml b/algorithms-miscellaneous-3/pom.xml
index 802cf74320..5999d33c86 100644
--- a/algorithms-miscellaneous-3/pom.xml
+++ b/algorithms-miscellaneous-3/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
algorithms-miscellaneous-3
0.0.1-SNAPSHOT
@@ -18,17 +18,28 @@
${org.assertj.core.version}
test
-
+
- org.apache.commons
- commons-collections4
- ${commons-collections4.version}
+ org.apache.commons
+ commons-collections4
+ ${commons-collections4.version}
-
+
- com.google.guava
- guava
- ${guava.version}
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+
+ com.squareup.retrofit2
+ retrofit
+ ${retrofit.version}
+
+
+ com.squareup.retrofit2
+ converter-jackson
+ ${retrofit.version}
@@ -61,5 +72,6 @@
3.9.0
4.3
28.0-jre
+ 2.6.0
\ No newline at end of file
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java
new file mode 100644
index 0000000000..91423eeaa8
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearch.java
@@ -0,0 +1,35 @@
+package com.baeldung.algorithms.interpolationsearch;
+
+public class InterpolationSearch {
+
+ public static int interpolationSearch(int[] data, int item) {
+
+ int highEnd = (data.length - 1);
+ int lowEnd = 0;
+
+ while (item >= data[lowEnd] && item <= data[highEnd] && lowEnd <= highEnd) {
+
+ int probe = lowEnd + (highEnd - lowEnd) * (item - data[lowEnd]) / (data[highEnd] - data[lowEnd]);
+
+ if (highEnd == lowEnd) {
+ if (data[lowEnd] == item) {
+ return lowEnd;
+ } else {
+ return -1;
+ }
+ }
+
+ if (data[probe] == item) {
+ return probe;
+ }
+
+ if (data[probe] < item) {
+ lowEnd = probe + 1;
+ } else {
+ highEnd = probe - 1;
+ }
+ }
+ return -1;
+ }
+
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Centroid.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Centroid.java
new file mode 100644
index 0000000000..523d5b56a5
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Centroid.java
@@ -0,0 +1,45 @@
+package com.baeldung.algorithms.kmeans;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Encapsulates all coordinates for a particular cluster centroid.
+ */
+public class Centroid {
+
+ /**
+ * The centroid coordinates.
+ */
+ private final Map coordinates;
+
+ public Centroid(Map coordinates) {
+ this.coordinates = coordinates;
+ }
+
+ public Map getCoordinates() {
+ return coordinates;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Centroid centroid = (Centroid) o;
+ return Objects.equals(getCoordinates(), centroid.getCoordinates());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getCoordinates());
+ }
+
+ @Override
+ public String toString() {
+ return "Centroid " + coordinates;
+ }
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Distance.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Distance.java
new file mode 100644
index 0000000000..30723cb6b3
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Distance.java
@@ -0,0 +1,20 @@
+package com.baeldung.algorithms.kmeans;
+
+import java.util.Map;
+
+/**
+ * Defines a contract to calculate distance between two feature vectors. The less the
+ * calculated distance, the more two items are similar to each other.
+ */
+public interface Distance {
+
+ /**
+ * Calculates the distance between two feature vectors.
+ *
+ * @param f1 The first set of features.
+ * @param f2 The second set of features.
+ * @return Calculated distance.
+ * @throws IllegalArgumentException If the given feature vectors are invalid.
+ */
+ double calculate(Map f1, Map f2);
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Errors.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Errors.java
new file mode 100644
index 0000000000..3228876051
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Errors.java
@@ -0,0 +1,23 @@
+package com.baeldung.algorithms.kmeans;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Encapsulates methods to calculates errors between centroid and the cluster members.
+ */
+public class Errors {
+
+ public static double sse(Map> clustered, Distance distance) {
+ double sum = 0;
+ for (Map.Entry> entry : clustered.entrySet()) {
+ Centroid centroid = entry.getKey();
+ for (Record record : entry.getValue()) {
+ double d = distance.calculate(centroid.getCoordinates(), record.getFeatures());
+ sum += Math.pow(d, 2);
+ }
+ }
+
+ return sum;
+ }
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/EuclideanDistance.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/EuclideanDistance.java
new file mode 100644
index 0000000000..193d9afed1
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/EuclideanDistance.java
@@ -0,0 +1,26 @@
+package com.baeldung.algorithms.kmeans;
+
+import java.util.Map;
+
+/**
+ * Calculates the distance between two items using the Euclidean formula.
+ */
+public class EuclideanDistance implements Distance {
+
+ @Override
+ public double calculate(Map f1, Map f2) {
+ if (f1 == null || f2 == null) {
+ throw new IllegalArgumentException("Feature vectors can't be null");
+ }
+
+ double sum = 0;
+ for (String key : f1.keySet()) {
+ Double v1 = f1.get(key);
+ Double v2 = f2.get(key);
+
+ if (v1 != null && v2 != null) sum += Math.pow(v1 - v2, 2);
+ }
+
+ return Math.sqrt(sum);
+ }
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/KMeans.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/KMeans.java
new file mode 100644
index 0000000000..1fb8541ff9
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/KMeans.java
@@ -0,0 +1,236 @@
+package com.baeldung.algorithms.kmeans;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
+
+/**
+ * Encapsulates an implementation of KMeans clustering algorithm.
+ *
+ * @author Ali Dehghani
+ */
+public class KMeans {
+
+ private KMeans() {
+ throw new IllegalAccessError("You shouldn't call this constructor");
+ }
+
+ /**
+ * Will be used to generate random numbers.
+ */
+ private static final Random random = new Random();
+
+ /**
+ * Performs the K-Means clustering algorithm on the given dataset.
+ *
+ * @param records The dataset.
+ * @param k Number of Clusters.
+ * @param distance To calculate the distance between two items.
+ * @param maxIterations Upper bound for the number of iterations.
+ * @return K clusters along with their features.
+ */
+ public static Map> fit(List records, int k, Distance distance, int maxIterations) {
+ applyPreconditions(records, k, distance, maxIterations);
+
+ List centroids = randomCentroids(records, k);
+ Map> clusters = new HashMap<>();
+ Map> lastState = new HashMap<>();
+
+ // iterate for a pre-defined number of times
+ for (int i = 0; i < maxIterations; i++) {
+ boolean isLastIteration = i == maxIterations - 1;
+
+ // in each iteration we should find the nearest centroid for each record
+ for (Record record : records) {
+ Centroid centroid = nearestCentroid(record, centroids, distance);
+ assignToCluster(clusters, record, centroid);
+ }
+
+ // if the assignment does not change, then the algorithm terminates
+ boolean shouldTerminate = isLastIteration || clusters.equals(lastState);
+ lastState = clusters;
+ if (shouldTerminate) {
+ break;
+ }
+
+ // at the end of each iteration we should relocate the centroids
+ centroids = relocateCentroids(clusters);
+ clusters = new HashMap<>();
+ }
+
+ return lastState;
+ }
+
+ /**
+ * Move all cluster centroids to the average of all assigned features.
+ *
+ * @param clusters The current cluster configuration.
+ * @return Collection of new and relocated centroids.
+ */
+ private static List relocateCentroids(Map> clusters) {
+ return clusters
+ .entrySet()
+ .stream()
+ .map(e -> average(e.getKey(), e.getValue()))
+ .collect(toList());
+ }
+
+ /**
+ * Moves the given centroid to the average position of all assigned features. If
+ * the centroid has no feature in its cluster, then there would be no need for a
+ * relocation. Otherwise, for each entry we calculate the average of all records
+ * first by summing all the entries and then dividing the final summation value by
+ * the number of records.
+ *
+ * @param centroid The centroid to move.
+ * @param records The assigned features.
+ * @return The moved centroid.
+ */
+ private static Centroid average(Centroid centroid, List records) {
+ // if this cluster is empty, then we shouldn't move the centroid
+ if (records == null || records.isEmpty()) {
+ return centroid;
+ }
+
+ // Since some records don't have all possible attributes, we initialize
+ // average coordinates equal to current centroid coordinates
+ Map average = centroid.getCoordinates();
+
+ // The average function works correctly if we clear all coordinates corresponding
+ // to present record attributes
+ records
+ .stream()
+ .flatMap(e -> e
+ .getFeatures()
+ .keySet()
+ .stream())
+ .forEach(k -> average.put(k, 0.0));
+
+ for (Record record : records) {
+ record
+ .getFeatures()
+ .forEach((k, v) -> average.compute(k, (k1, currentValue) -> v + currentValue));
+ }
+
+ average.forEach((k, v) -> average.put(k, v / records.size()));
+
+ return new Centroid(average);
+ }
+
+ /**
+ * Assigns a feature vector to the given centroid. If this is the first assignment for this centroid,
+ * first we should create the list.
+ *
+ * @param clusters The current cluster configuration.
+ * @param record The feature vector.
+ * @param centroid The centroid.
+ */
+ private static void assignToCluster(Map> clusters, Record record, Centroid centroid) {
+ clusters.compute(centroid, (key, list) -> {
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+
+ list.add(record);
+ return list;
+ });
+ }
+
+ /**
+ * With the help of the given distance calculator, iterates through centroids and finds the
+ * nearest one to the given record.
+ *
+ * @param record The feature vector to find a centroid for.
+ * @param centroids Collection of all centroids.
+ * @param distance To calculate the distance between two items.
+ * @return The nearest centroid to the given feature vector.
+ */
+ private static Centroid nearestCentroid(Record record, List centroids, Distance distance) {
+ double minimumDistance = Double.MAX_VALUE;
+ Centroid nearest = null;
+
+ for (Centroid centroid : centroids) {
+ double currentDistance = distance.calculate(record.getFeatures(), centroid.getCoordinates());
+
+ if (currentDistance < minimumDistance) {
+ minimumDistance = currentDistance;
+ nearest = centroid;
+ }
+ }
+
+ return nearest;
+ }
+
+ /**
+ * Generates k random centroids. Before kicking-off the centroid generation process,
+ * first we calculate the possible value range for each attribute. Then when
+ * we're going to generate the centroids, we generate random coordinates in
+ * the [min, max] range for each attribute.
+ *
+ * @param records The dataset which helps to calculate the [min, max] range for
+ * each attribute.
+ * @param k Number of clusters.
+ * @return Collections of randomly generated centroids.
+ */
+ private static List randomCentroids(List records, int k) {
+ List centroids = new ArrayList<>();
+ Map maxs = new HashMap<>();
+ Map mins = new HashMap<>();
+
+ for (Record record : records) {
+ record
+ .getFeatures()
+ .forEach((key, value) -> {
+ // compares the value with the current max and choose the bigger value between them
+ maxs.compute(key, (k1, max) -> max == null || value > max ? value : max);
+
+ // compare the value with the current min and choose the smaller value between them
+ mins.compute(key, (k1, min) -> min == null || value < min ? value : min);
+ });
+ }
+
+ Set attributes = records
+ .stream()
+ .flatMap(e -> e
+ .getFeatures()
+ .keySet()
+ .stream())
+ .collect(toSet());
+ for (int i = 0; i < k; i++) {
+ Map coordinates = new HashMap<>();
+ for (String attribute : attributes) {
+ double max = maxs.get(attribute);
+ double min = mins.get(attribute);
+ coordinates.put(attribute, random.nextDouble() * (max - min) + min);
+ }
+
+ centroids.add(new Centroid(coordinates));
+ }
+
+ return centroids;
+ }
+
+ private static void applyPreconditions(List records, int k, Distance distance, int maxIterations) {
+ if (records == null || records.isEmpty()) {
+ throw new IllegalArgumentException("The dataset can't be empty");
+ }
+
+ if (k <= 1) {
+ throw new IllegalArgumentException("It doesn't make sense to have less than or equal to 1 cluster");
+ }
+
+ if (distance == null) {
+ throw new IllegalArgumentException("The distance calculator is required");
+ }
+
+ if (maxIterations <= 0) {
+ throw new IllegalArgumentException("Max iterations should be a positive number");
+ }
+ }
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFm.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFm.java
new file mode 100644
index 0000000000..4694a845af
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFm.java
@@ -0,0 +1,144 @@
+package com.baeldung.algorithms.kmeans;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import okhttp3.OkHttpClient;
+import retrofit2.Retrofit;
+import retrofit2.converter.jackson.JacksonConverterFactory;
+
+import static java.util.stream.Collectors.toSet;
+
+public class LastFm {
+
+ private static OkHttpClient okHttp = new OkHttpClient.Builder()
+ .addInterceptor(new LastFmService.Authenticator("put your API key here"))
+ .build();
+
+ private static Retrofit retrofit = new Retrofit.Builder()
+ .client(okHttp)
+ .addConverterFactory(JacksonConverterFactory.create())
+ .baseUrl("http://ws.audioscrobbler.com/")
+ .build();
+
+ private static LastFmService lastFm = retrofit.create(LastFmService.class);
+
+ private static ObjectMapper mapper = new ObjectMapper();
+
+ public static void main(String[] args) throws IOException {
+ List artists = getTop100Artists();
+ Set tags = getTop100Tags();
+ List records = datasetWithTaggedArtists(artists, tags);
+
+ Map> clusters = KMeans.fit(records, 7, new EuclideanDistance(), 1000);
+ // Print the cluster configuration
+ clusters.forEach((key, value) -> {
+ System.out.println("------------------------------ CLUSTER -----------------------------------");
+
+ System.out.println(sortedCentroid(key));
+ String members = String.join(", ", value
+ .stream()
+ .map(Record::getDescription)
+ .collect(toSet()));
+ System.out.print(members);
+
+ System.out.println();
+ System.out.println();
+ });
+
+ Map json = convertToD3CompatibleMap(clusters);
+ System.out.println(mapper.writeValueAsString(json));
+ }
+
+ private static Map convertToD3CompatibleMap(Map> clusters) {
+ Map json = new HashMap<>();
+ json.put("name", "Musicians");
+ List> children = new ArrayList<>();
+ clusters.forEach((key, value) -> {
+ Map child = new HashMap<>();
+ child.put("name", dominantGenre(sortedCentroid(key)));
+ List> nested = new ArrayList<>();
+ for (Record record : value) {
+ nested.add(Collections.singletonMap("name", record.getDescription()));
+ }
+ child.put("children", nested);
+
+ children.add(child);
+ });
+ json.put("children", children);
+ return json;
+ }
+
+ private static String dominantGenre(Centroid centroid) {
+ return centroid
+ .getCoordinates()
+ .keySet()
+ .stream()
+ .limit(2)
+ .collect(Collectors.joining(", "));
+ }
+
+ private static Centroid sortedCentroid(Centroid key) {
+ List> entries = new ArrayList<>(key
+ .getCoordinates()
+ .entrySet());
+ entries.sort((e1, e2) -> e2
+ .getValue()
+ .compareTo(e1.getValue()));
+
+ Map sorted = new LinkedHashMap<>();
+ for (Map.Entry entry : entries) {
+ sorted.put(entry.getKey(), entry.getValue());
+ }
+
+ return new Centroid(sorted);
+ }
+
+ private static List datasetWithTaggedArtists(List artists, Set topTags) throws IOException {
+ List records = new ArrayList<>();
+ for (String artist : artists) {
+ Map tags = lastFm
+ .topTagsFor(artist)
+ .execute()
+ .body()
+ .all();
+
+ // Only keep popular tags.
+ tags
+ .entrySet()
+ .removeIf(e -> !topTags.contains(e.getKey()));
+
+ records.add(new Record(artist, tags));
+ }
+ return records;
+ }
+
+ private static Set getTop100Tags() throws IOException {
+ return lastFm
+ .topTags()
+ .execute()
+ .body()
+ .all();
+ }
+
+ private static List getTop100Artists() throws IOException {
+ List artists = new ArrayList<>();
+ for (int i = 1; i <= 2; i++) {
+ artists.addAll(lastFm
+ .topArtists(i)
+ .execute()
+ .body()
+ .all());
+ }
+
+ return artists;
+ }
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFmService.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFmService.java
new file mode 100644
index 0000000000..db57deb888
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/LastFmService.java
@@ -0,0 +1,118 @@
+package com.baeldung.algorithms.kmeans;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import okhttp3.HttpUrl;
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Query;
+
+import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
+import static java.util.stream.Collectors.toList;
+
+public interface LastFmService {
+
+ @GET("/2.0/?method=chart.gettopartists&format=json&limit=50")
+ Call topArtists(@Query("page") int page);
+
+ @GET("/2.0/?method=artist.gettoptags&format=json&limit=20&autocorrect=1")
+ Call topTagsFor(@Query("artist") String artist);
+
+ @GET("/2.0/?method=chart.gettoptags&format=json&limit=100")
+ Call topTags();
+
+ /**
+ * HTTP interceptor to intercept all HTTP requests and add the API key to them.
+ */
+ class Authenticator implements Interceptor {
+
+ private final String apiKey;
+
+ Authenticator(String apiKey) {
+ this.apiKey = apiKey;
+ }
+
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ HttpUrl url = chain
+ .request()
+ .url()
+ .newBuilder()
+ .addQueryParameter("api_key", apiKey)
+ .build();
+ Request request = chain
+ .request()
+ .newBuilder()
+ .url(url)
+ .build();
+
+ return chain.proceed(request);
+ }
+ }
+
+ @JsonAutoDetect(fieldVisibility = ANY)
+ class TopTags {
+
+ private Map tags;
+
+ @SuppressWarnings("unchecked")
+ public Set all() {
+ List> topTags = (List>) tags.get("tag");
+ return topTags
+ .stream()
+ .map(e -> ((String) e.get("name")))
+ .collect(Collectors.toSet());
+ }
+ }
+
+ @JsonAutoDetect(fieldVisibility = ANY)
+ class Tags {
+
+ @JsonProperty("toptags") private Map topTags;
+
+ @SuppressWarnings("unchecked")
+ public Map all() {
+ try {
+ Map all = new HashMap<>();
+ List> tags = (List>) topTags.get("tag");
+ for (Map tag : tags) {
+ all.put(((String) tag.get("name")), ((Integer) tag.get("count")).doubleValue());
+ }
+
+ return all;
+ } catch (Exception e) {
+ return Collections.emptyMap();
+ }
+ }
+ }
+
+ @JsonAutoDetect(fieldVisibility = ANY)
+ class Artists {
+
+ private Map artists;
+
+ @SuppressWarnings("unchecked")
+ public List all() {
+ try {
+ List> artists = (List>) this.artists.get("artist");
+ return artists
+ .stream()
+ .map(e -> ((String) e.get("name")))
+ .collect(toList());
+ } catch (Exception e) {
+ return Collections.emptyList();
+ }
+ }
+ }
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Record.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Record.java
new file mode 100644
index 0000000000..d2a7b61c62
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/kmeans/Record.java
@@ -0,0 +1,65 @@
+package com.baeldung.algorithms.kmeans;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Encapsulates all feature values for a few attributes. Optionally each record
+ * can be described with the {@link #description} field.
+ */
+public class Record {
+
+ /**
+ * The record description. For example, this can be the artist name for the famous musician
+ * example.
+ */
+ private final String description;
+
+ /**
+ * Encapsulates all attributes and their corresponding values, i.e. features.
+ */
+ private final Map features;
+
+ public Record(String description, Map features) {
+ this.description = description;
+ this.features = features;
+ }
+
+ public Record(Map features) {
+ this("", features);
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Map getFeatures() {
+ return features;
+ }
+
+ @Override
+ public String toString() {
+ String prefix = description == null || description
+ .trim()
+ .isEmpty() ? "Record" : description;
+
+ return prefix + ": " + features;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Record record = (Record) o;
+ return Objects.equals(getDescription(), record.getDescription()) && Objects.equals(getFeatures(), record.getFeatures());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getDescription(), getFeatures());
+ }
+}
diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamples.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamples.java
index a67c54a922..156766f382 100644
--- a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamples.java
+++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamples.java
@@ -4,7 +4,7 @@ import org.apache.commons.lang3.StringUtils;
public class PrintTriangleExamples {
- public static String printARightAngledTriangle(int N) {
+ public static String printARightTriangle(int N) {
StringBuilder result = new StringBuilder();
for (int r = 1; r <= N; r++) {
for (int j = 1; j <= r; j++) {
@@ -29,6 +29,17 @@ public class PrintTriangleExamples {
return result.toString();
}
+ public static String printAnIsoscelesTriangleUsingStringUtils(int N) {
+ StringBuilder result = new StringBuilder();
+
+ for (int r = 1; r <= N; r++) {
+ result.append(StringUtils.repeat(' ', N - r));
+ result.append(StringUtils.repeat('*', 2 * r - 1));
+ result.append(System.lineSeparator());
+ }
+ return result.toString();
+ }
+
public static String printAnIsoscelesTriangleUsingSubstring(int N) {
StringBuilder result = new StringBuilder();
String helperString = StringUtils.repeat(' ', N - 1) + StringUtils.repeat('*', N * 2 - 1);
@@ -41,8 +52,9 @@ public class PrintTriangleExamples {
}
public static void main(String[] args) {
- System.out.println(printARightAngledTriangle(5));
+ System.out.println(printARightTriangle(5));
System.out.println(printAnIsoscelesTriangle(5));
+ System.out.println(printAnIsoscelesTriangleUsingStringUtils(5));
System.out.println(printAnIsoscelesTriangleUsingSubstring(5));
}
diff --git a/algorithms-miscellaneous-3/src/main/resources/kmeans/artists.json b/algorithms-miscellaneous-3/src/main/resources/kmeans/artists.json
new file mode 100644
index 0000000000..6cee0d1de2
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/resources/kmeans/artists.json
@@ -0,0 +1,3384 @@
+[
+ {
+ "description": "Billie Eilish",
+ "features": {
+ "singer-songwriter": 3.0,
+ "american": 23.0,
+ "british": 3.0,
+ "experimental": 3.0,
+ "rnb": 3.0,
+ "female vocalists": 49.0,
+ "indie": 58.0,
+ "chillout": 12.0,
+ "ambient": 3.0,
+ "pop": 100.0,
+ "synthpop": 3.0,
+ "electronic": 58.0,
+ "indie pop": 83.0,
+ "seen live": 18.0,
+ "alternative": 40.0,
+ "female vocalist": 9.0
+ }
+ },
+ {
+ "description": "Ed Sheeran",
+ "features": {
+ "indie": 12.0,
+ "singer-songwriter": 78.0,
+ "male vocalists": 13.0,
+ "soul": 3.0,
+ "chillout": 2.0,
+ "Mellow": 2.0,
+ "british": 82.0,
+ "pop": 23.0,
+ "rock": 4.0,
+ "rap": 2.0,
+ "indie pop": 3.0,
+ "seen live": 21.0,
+ "Hip-Hop": 4.0,
+ "acoustic": 100.0,
+ "alternative": 8.0,
+ "guitar": 2.0,
+ "00s": 2.0,
+ "Soundtrack": 1.0,
+ "Love": 2.0,
+ "folk": 12.0
+ }
+ },
+ {
+ "description": "Lil Nas X",
+ "features": {
+ "country": 54.0,
+ "male vocalists": 8.0,
+ "american": 24.0,
+ "rock": 16.0,
+ "pop": 8.0,
+ "hip hop": 47.0,
+ "rap": 62.0,
+ "Hip-Hop": 100.0,
+ "alternative": 24.0
+ }
+ },
+ {
+ "description": "Queen",
+ "features": {
+ "favorites": 2.0,
+ "male vocalists": 3.0,
+ "british": 17.0,
+ "classic rock": 100.0,
+ "rock": 81.0,
+ "pop": 7.0,
+ "heavy metal": 2.0,
+ "oldies": 2.0,
+ "seen live": 2.0,
+ "alternative": 4.0,
+ "metal": 2.0,
+ "Progressive rock": 6.0,
+ "alternative rock": 1.0,
+ "hard rock": 38.0,
+ "70s": 8.0,
+ "80s": 41.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Ariana Grande",
+ "features": {
+ "american": 13.0,
+ "beautiful": 2.0,
+ "dance": 11.0,
+ "House": 2.0,
+ "Soundtrack": 3.0,
+ "chillout": 3.0,
+ "pop": 100.0,
+ "rock": 2.0,
+ "electronic": 3.0,
+ "seen live": 3.0,
+ "female vocalist": 3.0,
+ "singer-songwriter": 5.0,
+ "rnb": 51.0,
+ "female vocalists": 54.0,
+ "soul": 10.0,
+ "synthpop": 2.0,
+ "hip hop": 3.0,
+ "Hip-Hop": 3.0
+ }
+ },
+ {
+ "description": "Post Malone",
+ "features": {
+ "american": 8.0,
+ "rap": 72.0,
+ "rnb": 14.0,
+ "pop": 8.0,
+ "synthpop": 3.0,
+ "hip hop": 35.0,
+ "seen live": 19.0,
+ "Hip-Hop": 100.0
+ }
+ },
+ {
+ "description": "Drake",
+ "features": {
+ "indie": 4.0,
+ "male vocalists": 5.0,
+ "soul": 2.0,
+ "pop": 6.0,
+ "hip hop": 37.0,
+ "rap": 72.0,
+ "seen live": 8.0,
+ "Hip-Hop": 100.0,
+ "rnb": 50.0,
+ "00s": 1.0
+ }
+ },
+ {
+ "description": "Kanye West",
+ "features": {
+ "indie": 2.0,
+ "male vocalists": 3.0,
+ "soul": 4.0,
+ "american": 6.0,
+ "experimental": 2.0,
+ "pop": 6.0,
+ "rock": 2.0,
+ "electronica": 1.0,
+ "hip hop": 40.0,
+ "electronic": 3.0,
+ "dance": 2.0,
+ "rap": 69.0,
+ "seen live": 22.0,
+ "Hip-Hop": 100.0,
+ "rnb": 31.0,
+ "alternative": 3.0,
+ "00s": 3.0
+ }
+ },
+ {
+ "description": "The Beatles",
+ "features": {
+ "indie": 3.0,
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "singer-songwriter": 2.0,
+ "Psychedelic Rock": 6.0,
+ "british": 58.0,
+ "experimental": 2.0,
+ "classic rock": 100.0,
+ "rock": 71.0,
+ "pop": 41.0,
+ "psychedelic": 13.0,
+ "indie rock": 2.0,
+ "oldies": 10.0,
+ "britpop": 4.0,
+ "alternative": 4.0,
+ "Progressive rock": 2.0,
+ "alternative rock": 1.0,
+ "Love": 2.0,
+ "folk": 1.0,
+ "60s": 56.0,
+ "70s": 3.0
+ }
+ },
+ {
+ "description": "Taylor Swift",
+ "features": {
+ "country": 100.0,
+ "singer-songwriter": 42.0,
+ "chillout": 2.0,
+ "american": 8.0,
+ "pop": 71.0,
+ "rock": 2.0,
+ "beautiful": 2.0,
+ "synthpop": 2.0,
+ "seen live": 4.0,
+ "acoustic": 31.0,
+ "female vocalist": 3.0,
+ "00s": 3.0,
+ "female vocalists": 60.0,
+ "Love": 3.0,
+ "folk": 2.0
+ }
+ },
+ {
+ "description": "Radiohead",
+ "features": {
+ "indie": 59.0,
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "emo": 1.0,
+ "chillout": 2.0,
+ "british": 22.0,
+ "experimental": 14.0,
+ "ambient": 2.0,
+ "classic rock": 1.0,
+ "rock": 73.0,
+ "electronica": 5.0,
+ "psychedelic": 3.0,
+ "pop": 2.0,
+ "beautiful": 1.0,
+ "post-rock": 3.0,
+ "indie rock": 15.0,
+ "electronic": 48.0,
+ "trip-hop": 1.0,
+ "britpop": 17.0,
+ "indie pop": 1.0,
+ "seen live": 27.0,
+ "alternative": 100.0,
+ "Progressive rock": 6.0,
+ "alternative rock": 81.0,
+ "00s": 2.0,
+ "idm": 1.0,
+ "90s": 5.0
+ }
+ },
+ {
+ "description": "Beyoncé",
+ "features": {
+ "singer-songwriter": 3.0,
+ "jazz": 2.0,
+ "american": 9.0,
+ "beautiful": 2.0,
+ "dance": 13.0,
+ "rap": 2.0,
+ "rnb": 100.0,
+ "female vocalists": 70.0,
+ "Love": 3.0,
+ "soul": 56.0,
+ "pop": 91.0,
+ "hip hop": 5.0,
+ "electronic": 2.0,
+ "seen live": 6.0,
+ "Hip-Hop": 45.0,
+ "alternative": 1.0,
+ "female vocalist": 4.0,
+ "00s": 3.0,
+ "funk": 2.0
+ }
+ },
+ {
+ "description": "Shawn Mendes",
+ "features": {
+ "male vocalists": 28.0,
+ "singer-songwriter": 13.0,
+ "british": 7.0,
+ "rnb": 7.0,
+ "acoustic": 37.0,
+ "metal": 4.0,
+ "folk": 37.0,
+ "indie": 10.0,
+ "soul": 4.0,
+ "pop": 100.0,
+ "seen live": 13.0,
+ "alternative": 4.0,
+ "alternative rock": 4.0
+ }
+ },
+ {
+ "description": "David Bowie",
+ "features": {
+ "singer-songwriter": 11.0,
+ "male vocalists": 4.0,
+ "Psychedelic Rock": 2.0,
+ "british": 23.0,
+ "experimental": 9.0,
+ "classic rock": 86.0,
+ "psychedelic": 3.0,
+ "electronica": 2.0,
+ "indie rock": 2.0,
+ "dance": 2.0,
+ "post-punk": 2.0,
+ "punk": 2.0,
+ "hard rock": 3.0,
+ "folk": 2.0,
+ "70s": 15.0,
+ "90s": 4.0,
+ "indie": 6.0,
+ "favorites": 2.0,
+ "soul": 2.0,
+ "ambient": 2.0,
+ "rock": 100.0,
+ "pop": 19.0,
+ "new wave": 7.0,
+ "electronic": 4.0,
+ "oldies": 2.0,
+ "britpop": 2.0,
+ "seen live": 11.0,
+ "alternative": 43.0,
+ "Progressive rock": 4.0,
+ "alternative rock": 6.0,
+ "industrial": 2.0,
+ "00s": 2.0,
+ "60s": 3.0,
+ "80s": 48.0,
+ "funk": 2.0
+ }
+ },
+ {
+ "description": "Kendrick Lamar",
+ "features": {
+ "male vocalists": 2.0,
+ "american": 7.0,
+ "hip hop": 17.0,
+ "rap": 70.0,
+ "seen live": 38.0,
+ "Hip-Hop": 100.0,
+ "funk": 2.0
+ }
+ },
+ {
+ "description": "Rihanna",
+ "features": {
+ "american": 4.0,
+ "beautiful": 2.0,
+ "dance": 56.0,
+ "rap": 2.0,
+ "rnb": 89.0,
+ "House": 1.0,
+ "female vocalists": 63.0,
+ "Love": 2.0,
+ "soul": 4.0,
+ "pop": 100.0,
+ "rock": 2.0,
+ "hip hop": 6.0,
+ "electronic": 3.0,
+ "seen live": 7.0,
+ "Hip-Hop": 41.0,
+ "alternative": 1.0,
+ "female vocalist": 4.0,
+ "00s": 3.0,
+ "reggae": 6.0
+ }
+ },
+ {
+ "description": "Arctic Monkeys",
+ "features": {
+ "indie": 98.0,
+ "male vocalists": 2.0,
+ "Psychedelic Rock": 1.0,
+ "british": 75.0,
+ "rock": 63.0,
+ "pop": 2.0,
+ "punk rock": 1.0,
+ "indie rock": 100.0,
+ "britpop": 16.0,
+ "indie pop": 2.0,
+ "seen live": 45.0,
+ "alternative": 60.0,
+ "post-punk": 3.0,
+ "alternative rock": 19.0,
+ "00s": 3.0,
+ "punk": 2.0
+ }
+ },
+ {
+ "description": "Tyler, the Creator",
+ "features": {
+ "experimental": 4.0,
+ "american": 4.0,
+ "hip hop": 12.0,
+ "rap": 55.0,
+ "seen live": 15.0,
+ "Hip-Hop": 100.0,
+ "alternative": 2.0
+ }
+ },
+ {
+ "description": "Lana Del Rey",
+ "features": {
+ "singer-songwriter": 10.0,
+ "jazz": 2.0,
+ "american": 14.0,
+ "beautiful": 2.0,
+ "indie rock": 2.0,
+ "female vocalists": 100.0,
+ "folk": 2.0,
+ "indie": 93.0,
+ "soul": 3.0,
+ "chillout": 3.0,
+ "blues": 2.0,
+ "pop": 80.0,
+ "rock": 2.0,
+ "electronic": 2.0,
+ "trip-hop": 10.0,
+ "indie pop": 88.0,
+ "seen live": 12.0,
+ "alternative": 67.0,
+ "female vocalist": 4.0,
+ "alternative rock": 2.0
+ }
+ },
+ {
+ "description": "Katy Perry",
+ "features": {
+ "indie": 25.0,
+ "singer-songwriter": 4.0,
+ "american": 9.0,
+ "pop": 100.0,
+ "rock": 24.0,
+ "beautiful": 2.0,
+ "indie rock": 1.0,
+ "electronic": 4.0,
+ "dance": 9.0,
+ "indie pop": 1.0,
+ "seen live": 7.0,
+ "rnb": 1.0,
+ "alternative": 3.0,
+ "female vocalist": 5.0,
+ "00s": 3.0,
+ "female vocalists": 62.0,
+ "Love": 2.0
+ }
+ },
+ {
+ "description": "Lady Gaga",
+ "features": {
+ "singer-songwriter": 4.0,
+ "american": 7.0,
+ "pop": 100.0,
+ "electronica": 3.0,
+ "rock": 2.0,
+ "electro": 2.0,
+ "synthpop": 2.0,
+ "electronic": 53.0,
+ "dance": 73.0,
+ "seen live": 8.0,
+ "techno": 1.0,
+ "rnb": 1.0,
+ "alternative": 1.0,
+ "female vocalist": 21.0,
+ "00s": 3.0,
+ "female vocalists": 43.0,
+ "Love": 2.0
+ }
+ },
+ {
+ "description": "Tame Impala",
+ "features": {
+ "indie": 21.0,
+ "male vocalists": 1.0,
+ "Psychedelic Rock": 100.0,
+ "experimental": 4.0,
+ "psychedelic": 92.0,
+ "rock": 41.0,
+ "indie rock": 60.0,
+ "electronic": 3.0,
+ "indie pop": 2.0,
+ "seen live": 53.0,
+ "alternative": 7.0,
+ "Progressive rock": 3.0,
+ "alternative rock": 3.0,
+ "00s": 3.0
+ }
+ },
+ {
+ "description": "Calvin Harris",
+ "features": {
+ "indie": 8.0,
+ "male vocalists": 3.0,
+ "singer-songwriter": 1.0,
+ "british": 15.0,
+ "electronica": 34.0,
+ "pop": 8.0,
+ "electro": 53.0,
+ "synthpop": 4.0,
+ "electronic": 100.0,
+ "dance": 75.0,
+ "indie pop": 2.0,
+ "seen live": 36.0,
+ "techno": 1.0,
+ "alternative": 1.0,
+ "House": 9.0,
+ "00s": 3.0,
+ "80s": 1.0
+ }
+ },
+ {
+ "description": "Red Hot Chili Peppers",
+ "features": {
+ "indie": 5.0,
+ "favorites": 1.0,
+ "male vocalists": 1.0,
+ "american": 5.0,
+ "classic rock": 3.0,
+ "rock": 100.0,
+ "pop": 2.0,
+ "punk rock": 2.0,
+ "indie rock": 2.0,
+ "seen live": 23.0,
+ "Grunge": 2.0,
+ "alternative": 54.0,
+ "metal": 2.0,
+ "alternative rock": 59.0,
+ "00s": 2.0,
+ "punk": 6.0,
+ "hard rock": 2.0,
+ "80s": 2.0,
+ "funk": 50.0,
+ "90s": 5.0
+ }
+ },
+ {
+ "description": "Coldplay",
+ "features": {
+ "indie": 55.0,
+ "favorites": 2.0,
+ "male vocalists": 3.0,
+ "singer-songwriter": 2.0,
+ "emo": 2.0,
+ "Mellow": 3.0,
+ "chillout": 3.0,
+ "british": 28.0,
+ "classic rock": 2.0,
+ "rock": 100.0,
+ "pop": 18.0,
+ "piano": 3.0,
+ "indie rock": 11.0,
+ "electronic": 2.0,
+ "britpop": 81.0,
+ "indie pop": 2.0,
+ "seen live": 22.0,
+ "alternative": 87.0,
+ "acoustic": 2.0,
+ "alternative rock": 68.0,
+ "00s": 2.0,
+ "Love": 2.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Miley Cyrus",
+ "features": {
+ "country": 3.0,
+ "singer-songwriter": 1.0,
+ "american": 12.0,
+ "beautiful": 2.0,
+ "grindcore": 1.0,
+ "dance": 42.0,
+ "rnb": 4.0,
+ "Soundtrack": 2.0,
+ "female vocalists": 55.0,
+ "Love": 2.0,
+ "death metal": 2.0,
+ "pop": 100.0,
+ "rock": 8.0,
+ "electronic": 5.0,
+ "seen live": 3.0,
+ "Hip-Hop": 4.0,
+ "alternative": 2.0,
+ "female vocalist": 4.0,
+ "00s": 2.0
+ }
+ },
+ {
+ "description": "Mark Ronson",
+ "features": {
+ "singer-songwriter": 1.0,
+ "jazz": 7.0,
+ "british": 68.0,
+ "experimental": 2.0,
+ "american": 1.0,
+ "cover": 4.0,
+ "electronica": 2.0,
+ "dance": 5.0,
+ "rap": 4.0,
+ "rnb": 2.0,
+ "House": 1.0,
+ "indie": 3.0,
+ "soul": 17.0,
+ "chillout": 2.0,
+ "pop": 68.0,
+ "rock": 3.0,
+ "electro": 2.0,
+ "hip hop": 11.0,
+ "electronic": 9.0,
+ "trip-hop": 1.0,
+ "britpop": 4.0,
+ "seen live": 31.0,
+ "Hip-Hop": 57.0,
+ "alternative": 9.0,
+ "00s": 7.0,
+ "funk": 100.0
+ }
+ },
+ {
+ "description": "Imagine Dragons",
+ "features": {
+ "indie": 100.0,
+ "male vocalists": 6.0,
+ "american": 12.0,
+ "rock": 64.0,
+ "pop": 10.0,
+ "indie rock": 96.0,
+ "electronic": 4.0,
+ "new wave": 2.0,
+ "indie pop": 57.0,
+ "seen live": 29.0,
+ "alternative": 86.0,
+ "alternative rock": 21.0,
+ "folk": 2.0
+ }
+ },
+ {
+ "description": "The Weeknd",
+ "features": {
+ "indie": 6.0,
+ "male vocalists": 5.0,
+ "soul": 9.0,
+ "chillout": 2.0,
+ "Mellow": 2.0,
+ "experimental": 6.0,
+ "ambient": 3.0,
+ "pop": 10.0,
+ "electronica": 5.0,
+ "electro": 1.0,
+ "downtempo": 7.0,
+ "hip hop": 2.0,
+ "electronic": 78.0,
+ "trip-hop": 3.0,
+ "rap": 2.0,
+ "indie pop": 2.0,
+ "seen live": 16.0,
+ "Hip-Hop": 8.0,
+ "rnb": 100.0,
+ "alternative": 5.0
+ }
+ },
+ {
+ "description": "Eminem",
+ "features": {
+ "male vocalists": 3.0,
+ "singer-songwriter": 2.0,
+ "emo": 1.0,
+ "american": 6.0,
+ "pop": 16.0,
+ "rock": 3.0,
+ "hip hop": 33.0,
+ "dance": 1.0,
+ "rap": 100.0,
+ "seen live": 4.0,
+ "Hip-Hop": 79.0,
+ "alternative": 3.0,
+ "00s": 2.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Nirvana",
+ "features": {
+ "indie": 4.0,
+ "favorites": 1.0,
+ "male vocalists": 2.0,
+ "Grunge": 100.0,
+ "alternative": 35.0,
+ "metal": 3.0,
+ "american": 4.0,
+ "classic rock": 2.0,
+ "rock": 52.0,
+ "alternative rock": 34.0,
+ "punk rock": 3.0,
+ "punk": 7.0,
+ "indie rock": 2.0,
+ "hard rock": 3.0,
+ "90s": 28.0
+ }
+ },
+ {
+ "description": "Fleetwood Mac",
+ "features": {
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "singer-songwriter": 2.0,
+ "british": 10.0,
+ "american": 3.0,
+ "classic rock": 100.0,
+ "blues": 41.0,
+ "rock": 67.0,
+ "pop": 33.0,
+ "oldies": 3.0,
+ "seen live": 7.0,
+ "alternative": 1.0,
+ "acoustic": 1.0,
+ "female vocalist": 2.0,
+ "guitar": 1.0,
+ "Progressive rock": 2.0,
+ "female vocalists": 10.0,
+ "folk": 2.0,
+ "60s": 5.0,
+ "70s": 48.0,
+ "80s": 12.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Childish Gambino",
+ "features": {
+ "indie": 35.0,
+ "male vocalists": 1.0,
+ "soul": 5.0,
+ "american": 8.0,
+ "experimental": 3.0,
+ "pop": 3.0,
+ "psychedelic": 2.0,
+ "hip hop": 31.0,
+ "electronic": 2.0,
+ "dance": 1.0,
+ "rap": 70.0,
+ "seen live": 37.0,
+ "Hip-Hop": 100.0,
+ "rnb": 6.0,
+ "alternative": 4.0,
+ "funk": 8.0
+ }
+ },
+ {
+ "description": "Pink Floyd",
+ "features": {
+ "favorites": 1.0,
+ "indie": 1.0,
+ "Psychedelic Rock": 72.0,
+ "british": 13.0,
+ "experimental": 6.0,
+ "ambient": 1.0,
+ "classic rock": 79.0,
+ "rock": 53.0,
+ "psychedelic": 44.0,
+ "oldies": 1.0,
+ "seen live": 3.0,
+ "alternative": 6.0,
+ "Progressive rock": 100.0,
+ "alternative rock": 2.0,
+ "hard rock": 2.0,
+ "60s": 5.0,
+ "70s": 8.0,
+ "80s": 3.0
+ }
+ },
+ {
+ "description": "The Killers",
+ "features": {
+ "indie": 100.0,
+ "favorites": 2.0,
+ "male vocalists": 3.0,
+ "emo": 2.0,
+ "american": 9.0,
+ "british": 2.0,
+ "classic rock": 1.0,
+ "rock": 93.0,
+ "pop": 10.0,
+ "electronica": 1.0,
+ "punk rock": 1.0,
+ "indie rock": 90.0,
+ "new wave": 4.0,
+ "electronic": 3.0,
+ "dance": 1.0,
+ "britpop": 4.0,
+ "indie pop": 4.0,
+ "seen live": 39.0,
+ "alternative": 75.0,
+ "post-punk": 3.0,
+ "alternative rock": 64.0,
+ "00s": 3.0,
+ "punk": 4.0
+ }
+ },
+ {
+ "description": "The Rolling Stones",
+ "features": {
+ "indie": 2.0,
+ "male vocalists": 1.0,
+ "Psychedelic Rock": 2.0,
+ "british": 43.0,
+ "classic rock": 100.0,
+ "blues": 31.0,
+ "rock": 80.0,
+ "psychedelic": 3.0,
+ "pop": 2.0,
+ "oldies": 3.0,
+ "seen live": 14.0,
+ "alternative": 4.0,
+ "guitar": 1.0,
+ "hard rock": 8.0,
+ "60s": 41.0,
+ "70s": 8.0,
+ "80s": 4.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Gorillaz",
+ "features": {
+ "indie": 46.0,
+ "favorites": 1.0,
+ "chillout": 3.0,
+ "british": 12.0,
+ "experimental": 6.0,
+ "rock": 58.0,
+ "electronica": 13.0,
+ "pop": 13.0,
+ "electro": 2.0,
+ "downtempo": 1.0,
+ "punk rock": 1.0,
+ "indie rock": 4.0,
+ "hip hop": 7.0,
+ "electronic": 88.0,
+ "trip-hop": 20.0,
+ "dance": 4.0,
+ "britpop": 4.0,
+ "rap": 4.0,
+ "indie pop": 2.0,
+ "seen live": 5.0,
+ "Hip-Hop": 63.0,
+ "alternative": 100.0,
+ "metal": 2.0,
+ "alternative rock": 11.0,
+ "00s": 3.0,
+ "punk": 2.0,
+ "funk": 3.0
+ }
+ },
+ {
+ "description": "Frank Ocean",
+ "features": {
+ "indie": 3.0,
+ "male vocalists": 6.0,
+ "singer-songwriter": 4.0,
+ "soul": 93.0,
+ "american": 8.0,
+ "experimental": 2.0,
+ "pop": 6.0,
+ "electronica": 1.0,
+ "hip hop": 8.0,
+ "electronic": 3.0,
+ "rap": 4.0,
+ "seen live": 14.0,
+ "Hip-Hop": 82.0,
+ "rnb": 100.0,
+ "alternative": 3.0,
+ "funk": 2.0
+ }
+ },
+ {
+ "description": "Panic! at the Disco",
+ "features": {
+ "male vocalists": 3.0,
+ "american": 8.0,
+ "electronica": 2.0,
+ "punk rock": 6.0,
+ "indie rock": 21.0,
+ "dance": 20.0,
+ "metal": 2.0,
+ "screamo": 2.0,
+ "punk": 21.0,
+ "Love": 2.0,
+ "indie": 68.0,
+ "favorites": 4.0,
+ "emo": 97.0,
+ "rock": 100.0,
+ "pop": 9.0,
+ "electronic": 4.0,
+ "indie pop": 2.0,
+ "seen live": 51.0,
+ "hardcore": 2.0,
+ "techno": 1.0,
+ "alternative": 99.0,
+ "alternative rock": 21.0,
+ "00s": 2.0
+ }
+ },
+ {
+ "description": "The Cure",
+ "features": {
+ "indie": 14.0,
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "emo": 1.0,
+ "british": 16.0,
+ "classic rock": 3.0,
+ "rock": 52.0,
+ "pop": 6.0,
+ "psychedelic": 1.0,
+ "synthpop": 1.0,
+ "punk rock": 1.0,
+ "indie rock": 3.0,
+ "new wave": 100.0,
+ "electronic": 2.0,
+ "britpop": 2.0,
+ "indie pop": 1.0,
+ "seen live": 24.0,
+ "alternative": 68.0,
+ "Gothic": 10.0,
+ "post-punk": 100.0,
+ "alternative rock": 23.0,
+ "punk": 4.0,
+ "Love": 2.0,
+ "70s": 2.0,
+ "80s": 65.0,
+ "90s": 3.0
+ }
+ },
+ {
+ "description": "Madonna",
+ "features": {
+ "singer-songwriter": 3.0,
+ "american": 8.0,
+ "pop": 100.0,
+ "rock": 5.0,
+ "electronica": 3.0,
+ "electronic": 29.0,
+ "dance": 50.0,
+ "seen live": 9.0,
+ "rnb": 1.0,
+ "alternative": 2.0,
+ "female vocalist": 4.0,
+ "00s": 4.0,
+ "female vocalists": 50.0,
+ "Love": 1.0,
+ "80s": 35.0,
+ "90s": 8.0
+ }
+ },
+ {
+ "description": "The Chainsmokers",
+ "features": {
+ "male vocalists": 6.0,
+ "american": 28.0,
+ "electronica": 3.0,
+ "dance": 33.0,
+ "House": 63.0,
+ "pop": 79.0,
+ "electro": 6.0,
+ "electronic": 100.0,
+ "seen live": 17.0,
+ "techno": 3.0,
+ "alternative": 3.0
+ }
+ },
+ {
+ "description": "Linkin Park",
+ "features": {
+ "favorites": 2.0,
+ "indie": 1.0,
+ "male vocalists": 3.0,
+ "emo": 3.0,
+ "american": 6.0,
+ "rock": 100.0,
+ "pop": 3.0,
+ "punk rock": 2.0,
+ "electronic": 4.0,
+ "rap": 3.0,
+ "seen live": 21.0,
+ "Hip-Hop": 2.0,
+ "alternative": 67.0,
+ "metal": 37.0,
+ "Nu Metal": 92.0,
+ "alternative rock": 74.0,
+ "00s": 2.0,
+ "punk": 4.0,
+ "hard rock": 5.0
+ }
+ },
+ {
+ "description": "Lorde",
+ "features": {
+ "indie": 72.0,
+ "singer-songwriter": 7.0,
+ "soul": 1.0,
+ "experimental": 2.0,
+ "pop": 100.0,
+ "electronica": 5.0,
+ "rock": 1.0,
+ "synthpop": 7.0,
+ "electronic": 81.0,
+ "trip-hop": 2.0,
+ "indie pop": 92.0,
+ "seen live": 20.0,
+ "alternative": 17.0,
+ "female vocalist": 4.0,
+ "female vocalists": 28.0,
+ "folk": 2.0
+ }
+ },
+ {
+ "description": "The Black Keys",
+ "features": {
+ "indie": 50.0,
+ "male vocalists": 2.0,
+ "soul": 2.0,
+ "Psychedelic Rock": 2.0,
+ "american": 8.0,
+ "blues": 68.0,
+ "classic rock": 2.0,
+ "rock": 63.0,
+ "psychedelic": 2.0,
+ "indie rock": 48.0,
+ "seen live": 37.0,
+ "alternative": 11.0,
+ "alternative rock": 7.0,
+ "00s": 3.0,
+ "hard rock": 2.0
+ }
+ },
+ {
+ "description": "Daft Punk",
+ "features": {
+ "indie": 2.0,
+ "chillout": 2.0,
+ "experimental": 2.0,
+ "electronica": 37.0,
+ "rock": 3.0,
+ "pop": 2.0,
+ "electro": 11.0,
+ "synthpop": 1.0,
+ "electronic": 100.0,
+ "dance": 54.0,
+ "french": 19.0,
+ "seen live": 7.0,
+ "techno": 36.0,
+ "alternative": 6.0,
+ "House": 54.0,
+ "trance": 2.0,
+ "00s": 2.0,
+ "Soundtrack": 2.0,
+ "funk": 4.0,
+ "90s": 3.0
+ }
+ },
+ {
+ "description": "Led Zeppelin",
+ "features": {
+ "favorites": 1.0,
+ "indie": 1.0,
+ "Psychedelic Rock": 3.0,
+ "british": 9.0,
+ "classic rock": 100.0,
+ "blues": 9.0,
+ "rock": 64.0,
+ "psychedelic": 4.0,
+ "heavy metal": 8.0,
+ "oldies": 1.0,
+ "metal": 4.0,
+ "alternative": 4.0,
+ "guitar": 2.0,
+ "Progressive rock": 33.0,
+ "alternative rock": 1.0,
+ "hard rock": 63.0,
+ "folk": 1.0,
+ "60s": 3.0,
+ "70s": 36.0,
+ "80s": 1.0
+ }
+ },
+ {
+ "description": "Marshmello",
+ "features": {
+ "emo": 10.0,
+ "pop": 28.0,
+ "electronic": 91.0,
+ "dance": 100.0,
+ "rap": 28.0,
+ "seen live": 19.0,
+ "rnb": 19.0,
+ "House": 10.0
+ }
+ },
+ {
+ "description": "Khalid",
+ "features": {
+ "indie": 7.0,
+ "male vocalists": 7.0,
+ "soul": 88.0,
+ "american": 19.0,
+ "pop": 100.0,
+ "synthpop": 7.0,
+ "electronic": 13.0,
+ "seen live": 25.0,
+ "rnb": 75.0,
+ "alternative": 63.0,
+ "folk": 7.0
+ }
+ },
+ {
+ "description": "David Guetta",
+ "features": {
+ "chillout": 1.0,
+ "electronica": 7.0,
+ "pop": 6.0,
+ "electro": 6.0,
+ "electronic": 76.0,
+ "dance": 82.0,
+ "french": 11.0,
+ "seen live": 9.0,
+ "techno": 39.0,
+ "House": 100.0,
+ "trance": 4.0,
+ "00s": 2.0
+ }
+ },
+ {
+ "description": "Billie Eilish",
+ "features": {
+ "singer-songwriter": 3.0,
+ "american": 23.0,
+ "british": 3.0,
+ "experimental": 3.0,
+ "rnb": 3.0,
+ "female vocalists": 49.0,
+ "indie": 58.0,
+ "chillout": 12.0,
+ "ambient": 3.0,
+ "pop": 100.0,
+ "synthpop": 3.0,
+ "electronic": 58.0,
+ "indie pop": 83.0,
+ "seen live": 18.0,
+ "alternative": 40.0,
+ "female vocalist": 9.0
+ }
+ },
+ {
+ "description": "Ed Sheeran",
+ "features": {
+ "indie": 12.0,
+ "singer-songwriter": 78.0,
+ "male vocalists": 13.0,
+ "soul": 3.0,
+ "chillout": 2.0,
+ "Mellow": 2.0,
+ "british": 82.0,
+ "pop": 23.0,
+ "rock": 4.0,
+ "rap": 2.0,
+ "indie pop": 3.0,
+ "seen live": 21.0,
+ "Hip-Hop": 4.0,
+ "acoustic": 100.0,
+ "alternative": 8.0,
+ "guitar": 2.0,
+ "00s": 2.0,
+ "Soundtrack": 1.0,
+ "Love": 2.0,
+ "folk": 12.0
+ }
+ },
+ {
+ "description": "Lil Nas X",
+ "features": {
+ "country": 54.0,
+ "male vocalists": 8.0,
+ "american": 24.0,
+ "rock": 16.0,
+ "pop": 8.0,
+ "hip hop": 47.0,
+ "rap": 62.0,
+ "Hip-Hop": 100.0,
+ "alternative": 24.0
+ }
+ },
+ {
+ "description": "Queen",
+ "features": {
+ "favorites": 2.0,
+ "male vocalists": 3.0,
+ "british": 17.0,
+ "classic rock": 100.0,
+ "rock": 81.0,
+ "pop": 7.0,
+ "heavy metal": 2.0,
+ "oldies": 2.0,
+ "seen live": 2.0,
+ "alternative": 4.0,
+ "metal": 2.0,
+ "Progressive rock": 6.0,
+ "alternative rock": 1.0,
+ "hard rock": 38.0,
+ "70s": 8.0,
+ "80s": 41.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Ariana Grande",
+ "features": {
+ "american": 13.0,
+ "beautiful": 2.0,
+ "dance": 11.0,
+ "House": 2.0,
+ "Soundtrack": 3.0,
+ "chillout": 3.0,
+ "pop": 100.0,
+ "rock": 2.0,
+ "electronic": 3.0,
+ "seen live": 3.0,
+ "female vocalist": 3.0,
+ "singer-songwriter": 5.0,
+ "rnb": 51.0,
+ "female vocalists": 54.0,
+ "soul": 10.0,
+ "synthpop": 2.0,
+ "hip hop": 3.0,
+ "Hip-Hop": 3.0
+ }
+ },
+ {
+ "description": "Post Malone",
+ "features": {
+ "american": 8.0,
+ "rap": 72.0,
+ "rnb": 14.0,
+ "pop": 8.0,
+ "synthpop": 3.0,
+ "hip hop": 35.0,
+ "seen live": 19.0,
+ "Hip-Hop": 100.0
+ }
+ },
+ {
+ "description": "Drake",
+ "features": {
+ "indie": 4.0,
+ "male vocalists": 5.0,
+ "soul": 2.0,
+ "pop": 6.0,
+ "hip hop": 37.0,
+ "rap": 72.0,
+ "seen live": 8.0,
+ "Hip-Hop": 100.0,
+ "rnb": 50.0,
+ "00s": 1.0
+ }
+ },
+ {
+ "description": "Kanye West",
+ "features": {
+ "indie": 2.0,
+ "male vocalists": 3.0,
+ "soul": 4.0,
+ "american": 6.0,
+ "experimental": 2.0,
+ "pop": 6.0,
+ "rock": 2.0,
+ "electronica": 1.0,
+ "hip hop": 40.0,
+ "electronic": 3.0,
+ "dance": 2.0,
+ "rap": 69.0,
+ "seen live": 22.0,
+ "Hip-Hop": 100.0,
+ "rnb": 31.0,
+ "alternative": 3.0,
+ "00s": 3.0
+ }
+ },
+ {
+ "description": "The Beatles",
+ "features": {
+ "indie": 3.0,
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "singer-songwriter": 2.0,
+ "Psychedelic Rock": 6.0,
+ "british": 58.0,
+ "experimental": 2.0,
+ "classic rock": 100.0,
+ "rock": 71.0,
+ "pop": 41.0,
+ "psychedelic": 13.0,
+ "indie rock": 2.0,
+ "oldies": 10.0,
+ "britpop": 4.0,
+ "alternative": 4.0,
+ "Progressive rock": 2.0,
+ "alternative rock": 1.0,
+ "Love": 2.0,
+ "folk": 1.0,
+ "60s": 56.0,
+ "70s": 3.0
+ }
+ },
+ {
+ "description": "Taylor Swift",
+ "features": {
+ "country": 100.0,
+ "singer-songwriter": 42.0,
+ "chillout": 2.0,
+ "american": 8.0,
+ "pop": 71.0,
+ "rock": 2.0,
+ "beautiful": 2.0,
+ "synthpop": 2.0,
+ "seen live": 4.0,
+ "acoustic": 31.0,
+ "female vocalist": 3.0,
+ "00s": 3.0,
+ "female vocalists": 60.0,
+ "Love": 3.0,
+ "folk": 2.0
+ }
+ },
+ {
+ "description": "Radiohead",
+ "features": {
+ "indie": 59.0,
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "emo": 1.0,
+ "chillout": 2.0,
+ "british": 22.0,
+ "experimental": 14.0,
+ "ambient": 2.0,
+ "classic rock": 1.0,
+ "rock": 73.0,
+ "electronica": 5.0,
+ "psychedelic": 3.0,
+ "pop": 2.0,
+ "beautiful": 1.0,
+ "post-rock": 3.0,
+ "indie rock": 15.0,
+ "electronic": 48.0,
+ "trip-hop": 1.0,
+ "britpop": 17.0,
+ "indie pop": 1.0,
+ "seen live": 27.0,
+ "alternative": 100.0,
+ "Progressive rock": 6.0,
+ "alternative rock": 81.0,
+ "00s": 2.0,
+ "idm": 1.0,
+ "90s": 5.0
+ }
+ },
+ {
+ "description": "Beyoncé",
+ "features": {
+ "singer-songwriter": 3.0,
+ "jazz": 2.0,
+ "american": 9.0,
+ "beautiful": 2.0,
+ "dance": 13.0,
+ "rap": 2.0,
+ "rnb": 100.0,
+ "female vocalists": 70.0,
+ "Love": 3.0,
+ "soul": 56.0,
+ "pop": 91.0,
+ "hip hop": 5.0,
+ "electronic": 2.0,
+ "seen live": 6.0,
+ "Hip-Hop": 45.0,
+ "alternative": 1.0,
+ "female vocalist": 4.0,
+ "00s": 3.0,
+ "funk": 2.0
+ }
+ },
+ {
+ "description": "Shawn Mendes",
+ "features": {
+ "male vocalists": 28.0,
+ "singer-songwriter": 13.0,
+ "british": 7.0,
+ "rnb": 7.0,
+ "acoustic": 37.0,
+ "metal": 4.0,
+ "folk": 37.0,
+ "indie": 10.0,
+ "soul": 4.0,
+ "pop": 100.0,
+ "seen live": 13.0,
+ "alternative": 4.0,
+ "alternative rock": 4.0
+ }
+ },
+ {
+ "description": "David Bowie",
+ "features": {
+ "singer-songwriter": 11.0,
+ "male vocalists": 4.0,
+ "Psychedelic Rock": 2.0,
+ "british": 23.0,
+ "experimental": 9.0,
+ "classic rock": 86.0,
+ "psychedelic": 3.0,
+ "electronica": 2.0,
+ "indie rock": 2.0,
+ "dance": 2.0,
+ "post-punk": 2.0,
+ "punk": 2.0,
+ "hard rock": 3.0,
+ "folk": 2.0,
+ "70s": 15.0,
+ "90s": 4.0,
+ "indie": 6.0,
+ "favorites": 2.0,
+ "soul": 2.0,
+ "ambient": 2.0,
+ "rock": 100.0,
+ "pop": 19.0,
+ "new wave": 7.0,
+ "electronic": 4.0,
+ "oldies": 2.0,
+ "britpop": 2.0,
+ "seen live": 11.0,
+ "alternative": 43.0,
+ "Progressive rock": 4.0,
+ "alternative rock": 6.0,
+ "industrial": 2.0,
+ "00s": 2.0,
+ "60s": 3.0,
+ "80s": 48.0,
+ "funk": 2.0
+ }
+ },
+ {
+ "description": "Kendrick Lamar",
+ "features": {
+ "male vocalists": 2.0,
+ "american": 7.0,
+ "hip hop": 17.0,
+ "rap": 70.0,
+ "seen live": 38.0,
+ "Hip-Hop": 100.0,
+ "funk": 2.0
+ }
+ },
+ {
+ "description": "Rihanna",
+ "features": {
+ "american": 4.0,
+ "beautiful": 2.0,
+ "dance": 56.0,
+ "rap": 2.0,
+ "rnb": 89.0,
+ "House": 1.0,
+ "female vocalists": 63.0,
+ "Love": 2.0,
+ "soul": 4.0,
+ "pop": 100.0,
+ "rock": 2.0,
+ "hip hop": 6.0,
+ "electronic": 3.0,
+ "seen live": 7.0,
+ "Hip-Hop": 41.0,
+ "alternative": 1.0,
+ "female vocalist": 4.0,
+ "00s": 3.0,
+ "reggae": 6.0
+ }
+ },
+ {
+ "description": "Arctic Monkeys",
+ "features": {
+ "indie": 98.0,
+ "male vocalists": 2.0,
+ "Psychedelic Rock": 1.0,
+ "british": 75.0,
+ "rock": 63.0,
+ "pop": 2.0,
+ "punk rock": 1.0,
+ "indie rock": 100.0,
+ "britpop": 16.0,
+ "indie pop": 2.0,
+ "seen live": 45.0,
+ "alternative": 60.0,
+ "post-punk": 3.0,
+ "alternative rock": 19.0,
+ "00s": 3.0,
+ "punk": 2.0
+ }
+ },
+ {
+ "description": "Tyler, the Creator",
+ "features": {
+ "experimental": 4.0,
+ "american": 4.0,
+ "hip hop": 12.0,
+ "rap": 55.0,
+ "seen live": 15.0,
+ "Hip-Hop": 100.0,
+ "alternative": 2.0
+ }
+ },
+ {
+ "description": "Lana Del Rey",
+ "features": {
+ "singer-songwriter": 10.0,
+ "jazz": 2.0,
+ "american": 14.0,
+ "beautiful": 2.0,
+ "indie rock": 2.0,
+ "female vocalists": 100.0,
+ "folk": 2.0,
+ "indie": 93.0,
+ "soul": 3.0,
+ "chillout": 3.0,
+ "blues": 2.0,
+ "pop": 80.0,
+ "rock": 2.0,
+ "electronic": 2.0,
+ "trip-hop": 10.0,
+ "indie pop": 88.0,
+ "seen live": 12.0,
+ "alternative": 67.0,
+ "female vocalist": 4.0,
+ "alternative rock": 2.0
+ }
+ },
+ {
+ "description": "Katy Perry",
+ "features": {
+ "indie": 25.0,
+ "singer-songwriter": 4.0,
+ "american": 9.0,
+ "pop": 100.0,
+ "rock": 24.0,
+ "beautiful": 2.0,
+ "indie rock": 1.0,
+ "electronic": 4.0,
+ "dance": 9.0,
+ "indie pop": 1.0,
+ "seen live": 7.0,
+ "rnb": 1.0,
+ "alternative": 3.0,
+ "female vocalist": 5.0,
+ "00s": 3.0,
+ "female vocalists": 62.0,
+ "Love": 2.0
+ }
+ },
+ {
+ "description": "Lady Gaga",
+ "features": {
+ "singer-songwriter": 4.0,
+ "american": 7.0,
+ "pop": 100.0,
+ "electronica": 3.0,
+ "rock": 2.0,
+ "electro": 2.0,
+ "synthpop": 2.0,
+ "electronic": 53.0,
+ "dance": 73.0,
+ "seen live": 8.0,
+ "techno": 1.0,
+ "rnb": 1.0,
+ "alternative": 1.0,
+ "female vocalist": 21.0,
+ "00s": 3.0,
+ "female vocalists": 43.0,
+ "Love": 2.0
+ }
+ },
+ {
+ "description": "Tame Impala",
+ "features": {
+ "indie": 21.0,
+ "male vocalists": 1.0,
+ "Psychedelic Rock": 100.0,
+ "experimental": 4.0,
+ "psychedelic": 92.0,
+ "rock": 41.0,
+ "indie rock": 60.0,
+ "electronic": 3.0,
+ "indie pop": 2.0,
+ "seen live": 53.0,
+ "alternative": 7.0,
+ "Progressive rock": 3.0,
+ "alternative rock": 3.0,
+ "00s": 3.0
+ }
+ },
+ {
+ "description": "Calvin Harris",
+ "features": {
+ "indie": 8.0,
+ "male vocalists": 3.0,
+ "singer-songwriter": 1.0,
+ "british": 15.0,
+ "electronica": 34.0,
+ "pop": 8.0,
+ "electro": 53.0,
+ "synthpop": 4.0,
+ "electronic": 100.0,
+ "dance": 75.0,
+ "indie pop": 2.0,
+ "seen live": 36.0,
+ "techno": 1.0,
+ "alternative": 1.0,
+ "House": 9.0,
+ "00s": 3.0,
+ "80s": 1.0
+ }
+ },
+ {
+ "description": "Red Hot Chili Peppers",
+ "features": {
+ "indie": 5.0,
+ "favorites": 1.0,
+ "male vocalists": 1.0,
+ "american": 5.0,
+ "classic rock": 3.0,
+ "rock": 100.0,
+ "pop": 2.0,
+ "punk rock": 2.0,
+ "indie rock": 2.0,
+ "seen live": 23.0,
+ "Grunge": 2.0,
+ "alternative": 54.0,
+ "metal": 2.0,
+ "alternative rock": 59.0,
+ "00s": 2.0,
+ "punk": 6.0,
+ "hard rock": 2.0,
+ "80s": 2.0,
+ "funk": 50.0,
+ "90s": 5.0
+ }
+ },
+ {
+ "description": "Coldplay",
+ "features": {
+ "indie": 55.0,
+ "favorites": 2.0,
+ "male vocalists": 3.0,
+ "singer-songwriter": 2.0,
+ "emo": 2.0,
+ "Mellow": 3.0,
+ "chillout": 3.0,
+ "british": 28.0,
+ "classic rock": 2.0,
+ "rock": 100.0,
+ "pop": 18.0,
+ "piano": 3.0,
+ "indie rock": 11.0,
+ "electronic": 2.0,
+ "britpop": 81.0,
+ "indie pop": 2.0,
+ "seen live": 22.0,
+ "alternative": 87.0,
+ "acoustic": 2.0,
+ "alternative rock": 68.0,
+ "00s": 2.0,
+ "Love": 2.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Miley Cyrus",
+ "features": {
+ "country": 3.0,
+ "singer-songwriter": 1.0,
+ "american": 12.0,
+ "beautiful": 2.0,
+ "grindcore": 1.0,
+ "dance": 42.0,
+ "rnb": 4.0,
+ "Soundtrack": 2.0,
+ "female vocalists": 55.0,
+ "Love": 2.0,
+ "death metal": 2.0,
+ "pop": 100.0,
+ "rock": 8.0,
+ "electronic": 5.0,
+ "seen live": 3.0,
+ "Hip-Hop": 4.0,
+ "alternative": 2.0,
+ "female vocalist": 4.0,
+ "00s": 2.0
+ }
+ },
+ {
+ "description": "Mark Ronson",
+ "features": {
+ "singer-songwriter": 1.0,
+ "jazz": 7.0,
+ "british": 68.0,
+ "experimental": 2.0,
+ "american": 1.0,
+ "cover": 4.0,
+ "electronica": 2.0,
+ "dance": 5.0,
+ "rap": 4.0,
+ "rnb": 2.0,
+ "House": 1.0,
+ "indie": 3.0,
+ "soul": 17.0,
+ "chillout": 2.0,
+ "pop": 68.0,
+ "rock": 3.0,
+ "electro": 2.0,
+ "hip hop": 11.0,
+ "electronic": 9.0,
+ "trip-hop": 1.0,
+ "britpop": 4.0,
+ "seen live": 31.0,
+ "Hip-Hop": 57.0,
+ "alternative": 9.0,
+ "00s": 7.0,
+ "funk": 100.0
+ }
+ },
+ {
+ "description": "Imagine Dragons",
+ "features": {
+ "indie": 100.0,
+ "male vocalists": 6.0,
+ "american": 12.0,
+ "rock": 64.0,
+ "pop": 10.0,
+ "indie rock": 96.0,
+ "electronic": 4.0,
+ "new wave": 2.0,
+ "indie pop": 57.0,
+ "seen live": 29.0,
+ "alternative": 86.0,
+ "alternative rock": 21.0,
+ "folk": 2.0
+ }
+ },
+ {
+ "description": "The Weeknd",
+ "features": {
+ "indie": 6.0,
+ "male vocalists": 5.0,
+ "soul": 9.0,
+ "chillout": 2.0,
+ "Mellow": 2.0,
+ "experimental": 6.0,
+ "ambient": 3.0,
+ "pop": 10.0,
+ "electronica": 5.0,
+ "electro": 1.0,
+ "downtempo": 7.0,
+ "hip hop": 2.0,
+ "electronic": 78.0,
+ "trip-hop": 3.0,
+ "rap": 2.0,
+ "indie pop": 2.0,
+ "seen live": 16.0,
+ "Hip-Hop": 8.0,
+ "rnb": 100.0,
+ "alternative": 5.0
+ }
+ },
+ {
+ "description": "Eminem",
+ "features": {
+ "male vocalists": 3.0,
+ "singer-songwriter": 2.0,
+ "emo": 1.0,
+ "american": 6.0,
+ "pop": 16.0,
+ "rock": 3.0,
+ "hip hop": 33.0,
+ "dance": 1.0,
+ "rap": 100.0,
+ "seen live": 4.0,
+ "Hip-Hop": 79.0,
+ "alternative": 3.0,
+ "00s": 2.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Nirvana",
+ "features": {
+ "indie": 4.0,
+ "favorites": 1.0,
+ "male vocalists": 2.0,
+ "Grunge": 100.0,
+ "alternative": 35.0,
+ "metal": 3.0,
+ "american": 4.0,
+ "classic rock": 2.0,
+ "rock": 52.0,
+ "alternative rock": 34.0,
+ "punk rock": 3.0,
+ "punk": 7.0,
+ "indie rock": 2.0,
+ "hard rock": 3.0,
+ "90s": 28.0
+ }
+ },
+ {
+ "description": "Fleetwood Mac",
+ "features": {
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "singer-songwriter": 2.0,
+ "british": 10.0,
+ "american": 3.0,
+ "classic rock": 100.0,
+ "blues": 41.0,
+ "rock": 67.0,
+ "pop": 33.0,
+ "oldies": 3.0,
+ "seen live": 7.0,
+ "alternative": 1.0,
+ "acoustic": 1.0,
+ "female vocalist": 2.0,
+ "guitar": 1.0,
+ "Progressive rock": 2.0,
+ "female vocalists": 10.0,
+ "folk": 2.0,
+ "60s": 5.0,
+ "70s": 48.0,
+ "80s": 12.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Childish Gambino",
+ "features": {
+ "indie": 35.0,
+ "male vocalists": 1.0,
+ "soul": 5.0,
+ "american": 8.0,
+ "experimental": 3.0,
+ "pop": 3.0,
+ "psychedelic": 2.0,
+ "hip hop": 31.0,
+ "electronic": 2.0,
+ "dance": 1.0,
+ "rap": 70.0,
+ "seen live": 37.0,
+ "Hip-Hop": 100.0,
+ "rnb": 6.0,
+ "alternative": 4.0,
+ "funk": 8.0
+ }
+ },
+ {
+ "description": "Pink Floyd",
+ "features": {
+ "favorites": 1.0,
+ "indie": 1.0,
+ "Psychedelic Rock": 72.0,
+ "british": 13.0,
+ "experimental": 6.0,
+ "ambient": 1.0,
+ "classic rock": 79.0,
+ "rock": 53.0,
+ "psychedelic": 44.0,
+ "oldies": 1.0,
+ "seen live": 3.0,
+ "alternative": 6.0,
+ "Progressive rock": 100.0,
+ "alternative rock": 2.0,
+ "hard rock": 2.0,
+ "60s": 5.0,
+ "70s": 8.0,
+ "80s": 3.0
+ }
+ },
+ {
+ "description": "The Killers",
+ "features": {
+ "indie": 100.0,
+ "favorites": 2.0,
+ "male vocalists": 3.0,
+ "emo": 2.0,
+ "american": 9.0,
+ "british": 2.0,
+ "classic rock": 1.0,
+ "rock": 93.0,
+ "pop": 10.0,
+ "electronica": 1.0,
+ "punk rock": 1.0,
+ "indie rock": 90.0,
+ "new wave": 4.0,
+ "electronic": 3.0,
+ "dance": 1.0,
+ "britpop": 4.0,
+ "indie pop": 4.0,
+ "seen live": 39.0,
+ "alternative": 75.0,
+ "post-punk": 3.0,
+ "alternative rock": 64.0,
+ "00s": 3.0,
+ "punk": 4.0
+ }
+ },
+ {
+ "description": "The Rolling Stones",
+ "features": {
+ "indie": 2.0,
+ "male vocalists": 1.0,
+ "Psychedelic Rock": 2.0,
+ "british": 43.0,
+ "classic rock": 100.0,
+ "blues": 31.0,
+ "rock": 80.0,
+ "psychedelic": 3.0,
+ "pop": 2.0,
+ "oldies": 3.0,
+ "seen live": 14.0,
+ "alternative": 4.0,
+ "guitar": 1.0,
+ "hard rock": 8.0,
+ "60s": 41.0,
+ "70s": 8.0,
+ "80s": 4.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Gorillaz",
+ "features": {
+ "indie": 46.0,
+ "favorites": 1.0,
+ "chillout": 3.0,
+ "british": 12.0,
+ "experimental": 6.0,
+ "rock": 58.0,
+ "electronica": 13.0,
+ "pop": 13.0,
+ "electro": 2.0,
+ "downtempo": 1.0,
+ "punk rock": 1.0,
+ "indie rock": 4.0,
+ "hip hop": 7.0,
+ "electronic": 88.0,
+ "trip-hop": 20.0,
+ "dance": 4.0,
+ "britpop": 4.0,
+ "rap": 4.0,
+ "indie pop": 2.0,
+ "seen live": 5.0,
+ "Hip-Hop": 63.0,
+ "alternative": 100.0,
+ "metal": 2.0,
+ "alternative rock": 11.0,
+ "00s": 3.0,
+ "punk": 2.0,
+ "funk": 3.0
+ }
+ },
+ {
+ "description": "Frank Ocean",
+ "features": {
+ "indie": 3.0,
+ "male vocalists": 6.0,
+ "singer-songwriter": 4.0,
+ "soul": 93.0,
+ "american": 8.0,
+ "experimental": 2.0,
+ "pop": 6.0,
+ "electronica": 1.0,
+ "hip hop": 8.0,
+ "electronic": 3.0,
+ "rap": 4.0,
+ "seen live": 14.0,
+ "Hip-Hop": 82.0,
+ "rnb": 100.0,
+ "alternative": 3.0,
+ "funk": 2.0
+ }
+ },
+ {
+ "description": "Panic! at the Disco",
+ "features": {
+ "male vocalists": 3.0,
+ "american": 8.0,
+ "electronica": 2.0,
+ "punk rock": 6.0,
+ "indie rock": 21.0,
+ "dance": 20.0,
+ "metal": 2.0,
+ "screamo": 2.0,
+ "punk": 21.0,
+ "Love": 2.0,
+ "indie": 68.0,
+ "favorites": 4.0,
+ "emo": 97.0,
+ "rock": 100.0,
+ "pop": 9.0,
+ "electronic": 4.0,
+ "indie pop": 2.0,
+ "seen live": 51.0,
+ "hardcore": 2.0,
+ "techno": 1.0,
+ "alternative": 99.0,
+ "alternative rock": 21.0,
+ "00s": 2.0
+ }
+ },
+ {
+ "description": "The Cure",
+ "features": {
+ "indie": 14.0,
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "emo": 1.0,
+ "british": 16.0,
+ "classic rock": 3.0,
+ "rock": 52.0,
+ "pop": 6.0,
+ "psychedelic": 1.0,
+ "synthpop": 1.0,
+ "punk rock": 1.0,
+ "indie rock": 3.0,
+ "new wave": 100.0,
+ "electronic": 2.0,
+ "britpop": 2.0,
+ "indie pop": 1.0,
+ "seen live": 24.0,
+ "alternative": 68.0,
+ "Gothic": 10.0,
+ "post-punk": 100.0,
+ "alternative rock": 23.0,
+ "punk": 4.0,
+ "Love": 2.0,
+ "70s": 2.0,
+ "80s": 65.0,
+ "90s": 3.0
+ }
+ },
+ {
+ "description": "Madonna",
+ "features": {
+ "singer-songwriter": 3.0,
+ "american": 8.0,
+ "pop": 100.0,
+ "rock": 5.0,
+ "electronica": 3.0,
+ "electronic": 29.0,
+ "dance": 50.0,
+ "seen live": 9.0,
+ "rnb": 1.0,
+ "alternative": 2.0,
+ "female vocalist": 4.0,
+ "00s": 4.0,
+ "female vocalists": 50.0,
+ "Love": 1.0,
+ "80s": 35.0,
+ "90s": 8.0
+ }
+ },
+ {
+ "description": "The Chainsmokers",
+ "features": {
+ "male vocalists": 6.0,
+ "american": 28.0,
+ "electronica": 3.0,
+ "dance": 33.0,
+ "House": 63.0,
+ "pop": 79.0,
+ "electro": 6.0,
+ "electronic": 100.0,
+ "seen live": 17.0,
+ "techno": 3.0,
+ "alternative": 3.0
+ }
+ },
+ {
+ "description": "Linkin Park",
+ "features": {
+ "favorites": 2.0,
+ "indie": 1.0,
+ "male vocalists": 3.0,
+ "emo": 3.0,
+ "american": 6.0,
+ "rock": 100.0,
+ "pop": 3.0,
+ "punk rock": 2.0,
+ "electronic": 4.0,
+ "rap": 3.0,
+ "seen live": 21.0,
+ "Hip-Hop": 2.0,
+ "alternative": 67.0,
+ "metal": 37.0,
+ "Nu Metal": 92.0,
+ "alternative rock": 74.0,
+ "00s": 2.0,
+ "punk": 4.0,
+ "hard rock": 5.0
+ }
+ },
+ {
+ "description": "Lorde",
+ "features": {
+ "indie": 72.0,
+ "singer-songwriter": 7.0,
+ "soul": 1.0,
+ "experimental": 2.0,
+ "pop": 100.0,
+ "electronica": 5.0,
+ "rock": 1.0,
+ "synthpop": 7.0,
+ "electronic": 81.0,
+ "trip-hop": 2.0,
+ "indie pop": 92.0,
+ "seen live": 20.0,
+ "alternative": 17.0,
+ "female vocalist": 4.0,
+ "female vocalists": 28.0,
+ "folk": 2.0
+ }
+ },
+ {
+ "description": "The Black Keys",
+ "features": {
+ "indie": 50.0,
+ "male vocalists": 2.0,
+ "soul": 2.0,
+ "Psychedelic Rock": 2.0,
+ "american": 8.0,
+ "blues": 68.0,
+ "classic rock": 2.0,
+ "rock": 63.0,
+ "psychedelic": 2.0,
+ "indie rock": 48.0,
+ "seen live": 37.0,
+ "alternative": 11.0,
+ "alternative rock": 7.0,
+ "00s": 3.0,
+ "hard rock": 2.0
+ }
+ },
+ {
+ "description": "Daft Punk",
+ "features": {
+ "indie": 2.0,
+ "chillout": 2.0,
+ "experimental": 2.0,
+ "electronica": 37.0,
+ "rock": 3.0,
+ "pop": 2.0,
+ "electro": 11.0,
+ "synthpop": 1.0,
+ "electronic": 100.0,
+ "dance": 54.0,
+ "french": 19.0,
+ "seen live": 7.0,
+ "techno": 36.0,
+ "alternative": 6.0,
+ "House": 54.0,
+ "trance": 2.0,
+ "00s": 2.0,
+ "Soundtrack": 2.0,
+ "funk": 4.0,
+ "90s": 3.0
+ }
+ },
+ {
+ "description": "Led Zeppelin",
+ "features": {
+ "favorites": 1.0,
+ "indie": 1.0,
+ "Psychedelic Rock": 3.0,
+ "british": 9.0,
+ "classic rock": 100.0,
+ "blues": 9.0,
+ "rock": 64.0,
+ "psychedelic": 4.0,
+ "heavy metal": 8.0,
+ "oldies": 1.0,
+ "metal": 4.0,
+ "alternative": 4.0,
+ "guitar": 2.0,
+ "Progressive rock": 33.0,
+ "alternative rock": 1.0,
+ "hard rock": 63.0,
+ "folk": 1.0,
+ "60s": 3.0,
+ "70s": 36.0,
+ "80s": 1.0
+ }
+ },
+ {
+ "description": "Marshmello",
+ "features": {
+ "emo": 10.0,
+ "pop": 28.0,
+ "electronic": 91.0,
+ "dance": 100.0,
+ "rap": 28.0,
+ "seen live": 19.0,
+ "rnb": 19.0,
+ "House": 10.0
+ }
+ },
+ {
+ "description": "Khalid",
+ "features": {
+ "indie": 7.0,
+ "male vocalists": 7.0,
+ "soul": 88.0,
+ "american": 19.0,
+ "pop": 100.0,
+ "synthpop": 7.0,
+ "electronic": 13.0,
+ "seen live": 25.0,
+ "rnb": 75.0,
+ "alternative": 63.0,
+ "folk": 7.0
+ }
+ },
+ {
+ "description": "David Guetta",
+ "features": {
+ "chillout": 1.0,
+ "electronica": 7.0,
+ "pop": 6.0,
+ "electro": 6.0,
+ "electronic": 76.0,
+ "dance": 82.0,
+ "french": 11.0,
+ "seen live": 9.0,
+ "techno": 39.0,
+ "House": 100.0,
+ "trance": 4.0,
+ "00s": 2.0
+ }
+ },
+ {
+ "description": "Lizzo",
+ "features": {
+ "american": 16.0,
+ "dance": 8.0,
+ "rap": 47.0,
+ "rnb": 54.0,
+ "female vocalists": 24.0,
+ "pop": 16.0,
+ "hip hop": 47.0,
+ "seen live": 93.0,
+ "Hip-Hop": 100.0,
+ "alternative": 8.0
+ }
+ },
+ {
+ "description": "Sia",
+ "features": {
+ "indie": 70.0,
+ "favorites": 1.0,
+ "singer-songwriter": 18.0,
+ "soul": 3.0,
+ "jazz": 2.0,
+ "chillout": 76.0,
+ "Mellow": 4.0,
+ "ambient": 2.0,
+ "pop": 20.0,
+ "electronica": 4.0,
+ "rock": 2.0,
+ "beautiful": 4.0,
+ "piano": 1.0,
+ "downtempo": 57.0,
+ "indie rock": 1.0,
+ "electronic": 16.0,
+ "trip-hop": 57.0,
+ "dance": 2.0,
+ "indie pop": 8.0,
+ "lounge": 2.0,
+ "seen live": 7.0,
+ "alternative": 9.0,
+ "acoustic": 2.0,
+ "female vocalist": 7.0,
+ "alternative rock": 1.0,
+ "00s": 2.0,
+ "female vocalists": 100.0,
+ "Love": 2.0
+ }
+ },
+ {
+ "description": "Elton John",
+ "features": {
+ "favorites": 2.0,
+ "indie": 1.0,
+ "singer-songwriter": 64.0,
+ "male vocalists": 9.0,
+ "soul": 2.0,
+ "british": 28.0,
+ "classic rock": 87.0,
+ "blues": 1.0,
+ "pop": 100.0,
+ "rock": 59.0,
+ "piano": 54.0,
+ "oldies": 4.0,
+ "britpop": 2.0,
+ "seen live": 19.0,
+ "alternative": 2.0,
+ "Soundtrack": 3.0,
+ "00s": 2.0,
+ "Love": 2.0,
+ "60s": 2.0,
+ "70s": 16.0,
+ "80s": 16.0,
+ "90s": 5.0
+ }
+ },
+ {
+ "description": "Twenty One Pilots",
+ "features": {
+ "american": 15.0,
+ "experimental": 6.0,
+ "electronica": 1.0,
+ "piano": 1.0,
+ "indie rock": 12.0,
+ "rap": 48.0,
+ "pop": 17.0,
+ "rock": 11.0,
+ "electronic": 100.0,
+ "noise": 1.0,
+ "indie pop": 71.0,
+ "seen live": 50.0,
+ "male vocalists": 4.0,
+ "punk": 1.0,
+ "Love": 1.0,
+ "indie": 84.0,
+ "emo": 5.0,
+ "electro": 1.0,
+ "synthpop": 1.0,
+ "hip hop": 7.0,
+ "Hip-Hop": 27.0,
+ "alternative": 84.0,
+ "alternative rock": 23.0
+ }
+ },
+ {
+ "description": "Avicii",
+ "features": {
+ "swedish": 20.0,
+ "seen live": 14.0,
+ "techno": 2.0,
+ "House": 100.0,
+ "trance": 3.0,
+ "electronica": 6.0,
+ "pop": 3.0,
+ "electro": 5.0,
+ "electronic": 83.0,
+ "dance": 66.0
+ }
+ },
+ {
+ "description": "Ellie Goulding",
+ "features": {
+ "indie": 85.0,
+ "singer-songwriter": 11.0,
+ "chillout": 3.0,
+ "british": 89.0,
+ "pop": 36.0,
+ "electronica": 3.0,
+ "rock": 1.0,
+ "electro": 2.0,
+ "synthpop": 9.0,
+ "electronic": 98.0,
+ "dance": 5.0,
+ "britpop": 2.0,
+ "indie pop": 78.0,
+ "seen live": 27.0,
+ "alternative": 6.0,
+ "acoustic": 2.0,
+ "female vocalist": 5.0,
+ "00s": 2.0,
+ "female vocalists": 100.0,
+ "folk": 4.0
+ }
+ },
+ {
+ "description": "Muse",
+ "features": {
+ "indie": 43.0,
+ "favorites": 2.0,
+ "male vocalists": 3.0,
+ "emo": 2.0,
+ "british": 21.0,
+ "experimental": 3.0,
+ "rock": 83.0,
+ "pop": 2.0,
+ "piano": 1.0,
+ "indie rock": 12.0,
+ "electronic": 4.0,
+ "britpop": 10.0,
+ "seen live": 46.0,
+ "alternative": 70.0,
+ "metal": 1.0,
+ "Progressive rock": 57.0,
+ "alternative rock": 100.0,
+ "00s": 2.0,
+ "hard rock": 2.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Green Day",
+ "features": {
+ "indie": 3.0,
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "emo": 4.0,
+ "american": 7.0,
+ "classic rock": 2.0,
+ "rock": 75.0,
+ "pop": 6.0,
+ "punk rock": 100.0,
+ "indie rock": 2.0,
+ "seen live": 26.0,
+ "Grunge": 1.0,
+ "alternative": 47.0,
+ "metal": 2.0,
+ "alternative rock": 17.0,
+ "00s": 2.0,
+ "punk": 69.0,
+ "hard rock": 2.0,
+ "90s": 5.0
+ }
+ },
+ {
+ "description": "Metallica",
+ "features": {
+ "seen live": 31.0,
+ "emo": 2.0,
+ "metal": 91.0,
+ "alternative": 2.0,
+ "american": 6.0,
+ "Power metal": 1.0,
+ "classic rock": 6.0,
+ "rock": 34.0,
+ "alternative rock": 2.0,
+ "hard rock": 41.0,
+ "heavy metal": 74.0,
+ "80s": 4.0,
+ "thrash metal": 100.0,
+ "90s": 3.0,
+ "Progressive metal": 2.0
+ }
+ },
+ {
+ "description": "Sam Smith",
+ "features": {
+ "indie": 3.0,
+ "male vocalists": 9.0,
+ "singer-songwriter": 8.0,
+ "soul": 100.0,
+ "british": 55.0,
+ "pop": 87.0,
+ "electronic": 45.0,
+ "dance": 32.0,
+ "seen live": 30.0,
+ "rnb": 7.0,
+ "alternative": 3.0,
+ "folk": 2.0
+ }
+ },
+ {
+ "description": "Kygo",
+ "features": {
+ "electronica": 7.0,
+ "downtempo": 49.0,
+ "dance": 5.0,
+ "House": 74.0,
+ "chillout": 65.0,
+ "pop": 5.0,
+ "synthpop": 3.0,
+ "electronic": 100.0,
+ "seen live": 36.0
+ }
+ },
+ {
+ "description": "Halsey",
+ "features": {
+ "american": 34.0,
+ "classic rock": 2.0,
+ "beautiful": 4.0,
+ "black metal": 4.0,
+ "pop": 100.0,
+ "electronic": 38.0,
+ "noise": 2.0,
+ "heavy metal": 2.0,
+ "indie pop": 44.0,
+ "seen live": 32.0,
+ "female vocalist": 4.0,
+ "singer-songwriter": 8.0,
+ "british": 4.0,
+ "rnb": 4.0,
+ "trance": 2.0,
+ "female vocalists": 44.0,
+ "indie": 68.0,
+ "soul": 4.0,
+ "emo": 4.0,
+ "synthpop": 12.0,
+ "alternative": 32.0
+ }
+ },
+ {
+ "description": "Michael Jackson",
+ "features": {
+ "male vocalists": 5.0,
+ "singer-songwriter": 2.0,
+ "soul": 36.0,
+ "american": 6.0,
+ "classic rock": 2.0,
+ "pop": 100.0,
+ "rock": 8.0,
+ "electronic": 1.0,
+ "dance": 41.0,
+ "seen live": 3.0,
+ "rnb": 7.0,
+ "70s": 3.0,
+ "80s": 50.0,
+ "funk": 34.0,
+ "90s": 5.0
+ }
+ },
+ {
+ "description": "Maroon 5",
+ "features": {
+ "indie": 12.0,
+ "favorites": 3.0,
+ "male vocalists": 9.0,
+ "singer-songwriter": 2.0,
+ "soul": 3.0,
+ "emo": 2.0,
+ "jazz": 2.0,
+ "american": 11.0,
+ "classic rock": 2.0,
+ "rock": 100.0,
+ "pop": 96.0,
+ "punk rock": 2.0,
+ "indie rock": 3.0,
+ "electronic": 1.0,
+ "dance": 2.0,
+ "britpop": 1.0,
+ "indie pop": 2.0,
+ "seen live": 16.0,
+ "alternative": 69.0,
+ "acoustic": 2.0,
+ "metal": 1.0,
+ "alternative rock": 52.0,
+ "00s": 4.0,
+ "punk": 3.0,
+ "Love": 2.0,
+ "funk": 5.0
+ }
+ },
+ {
+ "description": "Charli XCX",
+ "features": {
+ "singer-songwriter": 5.0,
+ "british": 26.0,
+ "experimental": 2.0,
+ "electronica": 5.0,
+ "dance": 4.0,
+ "female vocalists": 56.0,
+ "indie": 7.0,
+ "chillout": 11.0,
+ "pop": 98.0,
+ "rock": 2.0,
+ "electro": 4.0,
+ "synthpop": 100.0,
+ "electronic": 99.0,
+ "new wave": 4.0,
+ "britpop": 2.0,
+ "indie pop": 7.0,
+ "seen live": 63.0,
+ "Hip-Hop": 2.0,
+ "alternative": 5.0,
+ "female vocalist": 2.0,
+ "00s": 2.0
+ }
+ },
+ {
+ "description": "Foo Fighters",
+ "features": {
+ "indie": 7.0,
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "emo": 1.0,
+ "american": 5.0,
+ "classic rock": 1.0,
+ "rock": 100.0,
+ "pop": 2.0,
+ "punk rock": 2.0,
+ "indie rock": 3.0,
+ "seen live": 35.0,
+ "Grunge": 48.0,
+ "alternative": 47.0,
+ "metal": 2.0,
+ "alternative rock": 69.0,
+ "00s": 2.0,
+ "punk": 5.0,
+ "hard rock": 30.0,
+ "90s": 4.0
+ }
+ },
+ {
+ "description": "Florence + the Machine",
+ "features": {
+ "indie": 100.0,
+ "singer-songwriter": 7.0,
+ "soul": 5.0,
+ "british": 72.0,
+ "experimental": 2.0,
+ "pop": 10.0,
+ "rock": 5.0,
+ "beautiful": 1.0,
+ "indie rock": 8.0,
+ "electronic": 2.0,
+ "britpop": 2.0,
+ "indie pop": 61.0,
+ "seen live": 29.0,
+ "alternative": 72.0,
+ "female vocalist": 3.0,
+ "alternative rock": 5.0,
+ "00s": 2.0,
+ "female vocalists": 86.0,
+ "Love": 2.0,
+ "folk": 6.0
+ }
+ },
+ {
+ "description": "blink-182",
+ "features": {
+ "indie": 3.0,
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "emo": 8.0,
+ "american": 6.0,
+ "rock": 56.0,
+ "pop": 5.0,
+ "punk rock": 100.0,
+ "indie rock": 2.0,
+ "seen live": 23.0,
+ "hardcore": 2.0,
+ "alternative": 42.0,
+ "metal": 2.0,
+ "alternative rock": 10.0,
+ "00s": 1.0,
+ "punk": 72.0,
+ "hard rock": 1.0,
+ "90s": 4.0
+ }
+ },
+ {
+ "description": "Vampire Weekend",
+ "features": {
+ "indie": 100.0,
+ "male vocalists": 3.0,
+ "american": 11.0,
+ "experimental": 6.0,
+ "rock": 37.0,
+ "pop": 9.0,
+ "indie rock": 82.0,
+ "electronic": 2.0,
+ "indie pop": 63.0,
+ "seen live": 58.0,
+ "alternative": 57.0,
+ "alternative rock": 7.0,
+ "00s": 4.0,
+ "folk": 1.0
+ }
+ },
+ {
+ "description": "Martin Garrix",
+ "features": {
+ "german": 2.0,
+ "experimental": 2.0,
+ "american": 2.0,
+ "electronica": 5.0,
+ "dance": 57.0,
+ "House": 100.0,
+ "Soundtrack": 2.0,
+ "black metal": 2.0,
+ "Power metal": 2.0,
+ "pop": 30.0,
+ "electronic": 80.0,
+ "noise": 2.0,
+ "seen live": 38.0,
+ "Grunge": 2.0,
+ "techno": 2.0,
+ "trance": 3.0,
+ "electro": 5.0
+ }
+ },
+ {
+ "description": "Paramore",
+ "features": {
+ "indie": 9.0,
+ "favorites": 2.0,
+ "emo": 35.0,
+ "american": 7.0,
+ "rock": 100.0,
+ "pop": 6.0,
+ "punk rock": 8.0,
+ "indie rock": 4.0,
+ "seen live": 34.0,
+ "alternative": 79.0,
+ "female vocalist": 6.0,
+ "alternative rock": 22.0,
+ "screamo": 1.0,
+ "00s": 2.0,
+ "female vocalists": 72.0,
+ "punk": 13.0,
+ "Love": 2.0
+ }
+ },
+ {
+ "description": "Britney Spears",
+ "features": {
+ "singer-songwriter": 2.0,
+ "american": 9.0,
+ "electronica": 1.0,
+ "beautiful": 2.0,
+ "dance": 44.0,
+ "rnb": 3.0,
+ "House": 1.0,
+ "trance": 1.0,
+ "female vocalists": 44.0,
+ "Love": 2.0,
+ "black metal": 2.0,
+ "90s": 6.0,
+ "indie": 1.0,
+ "death metal": 1.0,
+ "emo": 2.0,
+ "pop": 100.0,
+ "rock": 3.0,
+ "electro": 2.0,
+ "electronic": 5.0,
+ "seen live": 7.0,
+ "Hip-Hop": 2.0,
+ "alternative": 2.0,
+ "female vocalist": 4.0,
+ "00s": 4.0
+ }
+ },
+ {
+ "description": "Travi$ Scott",
+ "features": {
+ "male vocalists": 2.0,
+ "american": 10.0,
+ "experimental": 4.0,
+ "electronica": 2.0,
+ "rap": 62.0,
+ "rnb": 4.0,
+ "soul": 4.0,
+ "electro": 4.0,
+ "hip hop": 20.0,
+ "seen live": 24.0,
+ "Hip-Hop": 100.0,
+ "alternative": 2.0
+ }
+ },
+ {
+ "description": "Oasis",
+ "features": {
+ "indie": 45.0,
+ "favorites": 1.0,
+ "male vocalists": 2.0,
+ "british": 61.0,
+ "classic rock": 3.0,
+ "rock": 89.0,
+ "pop": 7.0,
+ "indie rock": 12.0,
+ "britpop": 100.0,
+ "seen live": 21.0,
+ "alternative": 53.0,
+ "alternative rock": 20.0,
+ "00s": 2.0,
+ "punk": 1.0,
+ "hard rock": 2.0,
+ "90s": 10.0
+ }
+ },
+ {
+ "description": "A$AP Rocky",
+ "features": {
+ "male vocalists": 3.0,
+ "american": 9.0,
+ "experimental": 2.0,
+ "hip hop": 12.0,
+ "rap": 61.0,
+ "seen live": 30.0,
+ "Hip-Hop": 100.0
+ }
+ },
+ {
+ "description": "Nicki Minaj",
+ "features": {
+ "singer-songwriter": 2.0,
+ "american": 7.0,
+ "dance": 9.0,
+ "rap": 84.0,
+ "rnb": 51.0,
+ "female vocalists": 25.0,
+ "Love": 2.0,
+ "chillout": 1.0,
+ "pop": 44.0,
+ "hip hop": 39.0,
+ "electronic": 3.0,
+ "seen live": 4.0,
+ "Hip-Hop": 100.0,
+ "alternative": 2.0,
+ "female vocalist": 3.0
+ }
+ },
+ {
+ "description": "The Smiths",
+ "features": {
+ "indie": 100.0,
+ "favorites": 3.0,
+ "male vocalists": 3.0,
+ "singer-songwriter": 2.0,
+ "emo": 2.0,
+ "british": 32.0,
+ "classic rock": 4.0,
+ "rock": 32.0,
+ "pop": 10.0,
+ "indie rock": 22.0,
+ "new wave": 85.0,
+ "electronic": 1.0,
+ "britpop": 10.0,
+ "indie pop": 10.0,
+ "seen live": 2.0,
+ "alternative": 77.0,
+ "post-punk": 85.0,
+ "alternative rock": 21.0,
+ "punk": 2.0,
+ "Love": 2.0,
+ "80s": 96.0
+ }
+ },
+ {
+ "description": "The Strokes",
+ "features": {
+ "indie": 97.0,
+ "favorites": 2.0,
+ "male vocalists": 2.0,
+ "emo": 1.0,
+ "american": 10.0,
+ "british": 2.0,
+ "classic rock": 2.0,
+ "rock": 98.0,
+ "pop": 2.0,
+ "punk rock": 2.0,
+ "indie rock": 100.0,
+ "new wave": 1.0,
+ "britpop": 2.0,
+ "indie pop": 3.0,
+ "seen live": 42.0,
+ "alternative": 71.0,
+ "post-punk": 5.0,
+ "alternative rock": 59.0,
+ "00s": 4.0,
+ "punk": 4.0,
+ "Love": 1.0
+ }
+ },
+ {
+ "description": "MGMT",
+ "features": {
+ "indie": 90.0,
+ "male vocalists": 2.0,
+ "Psychedelic Rock": 4.0,
+ "american": 8.0,
+ "experimental": 5.0,
+ "psychedelic": 68.0,
+ "pop": 7.0,
+ "rock": 5.0,
+ "electronica": 5.0,
+ "electro": 3.0,
+ "synthpop": 10.0,
+ "indie rock": 10.0,
+ "electronic": 100.0,
+ "dance": 3.0,
+ "indie pop": 51.0,
+ "seen live": 35.0,
+ "alternative": 53.0,
+ "post-punk": 1.0,
+ "alternative rock": 3.0,
+ "00s": 3.0
+ }
+ },
+ {
+ "description": "Fall Out Boy",
+ "features": {
+ "indie": 14.0,
+ "favorites": 3.0,
+ "male vocalists": 3.0,
+ "emo": 86.0,
+ "american": 7.0,
+ "rock": 91.0,
+ "pop": 9.0,
+ "punk rock": 28.0,
+ "indie rock": 4.0,
+ "dance": 1.0,
+ "seen live": 39.0,
+ "hardcore": 3.0,
+ "alternative": 69.0,
+ "metal": 2.0,
+ "alternative rock": 16.0,
+ "screamo": 3.0,
+ "00s": 2.0,
+ "punk": 55.0,
+ "Love": 2.0
+ }
+ },
+ {
+ "description": "Dua Lipa",
+ "features": {
+ "beautiful": 8.0,
+ "dance": 11.0,
+ "pop": 100.0,
+ "electronic": 11.0,
+ "indie pop": 16.0,
+ "seen live": 28.0,
+ "british": 29.0,
+ "japanese": 6.0,
+ "rnb": 12.0,
+ "female vocalists": 31.0,
+ "indie": 9.0,
+ "emo": 9.0,
+ "synthpop": 35.0
+ }
+ },
+ {
+ "description": "Jonas Brothers",
+ "features": {
+ "american": 9.0,
+ "grindcore": 3.0,
+ "punk rock": 2.0,
+ "dance": 2.0,
+ "metal": 3.0,
+ "House": 2.0,
+ "Soundtrack": 2.0,
+ "black metal": 3.0,
+ "Power metal": 2.0,
+ "pop": 100.0,
+ "rock": 56.0,
+ "Melodic Death Metal": 3.0,
+ "seen live": 17.0,
+ "00s": 4.0,
+ "male vocalists": 10.0,
+ "female vocalists": 2.0,
+ "punk": 3.0,
+ "Love": 3.0,
+ "indie": 2.0,
+ "death metal": 4.0,
+ "emo": 3.0,
+ "metalcore": 2.0,
+ "hardcore": 2.0,
+ "alternative": 2.0,
+ "alternative rock": 2.0
+ }
+ },
+ {
+ "description": "Foster the People",
+ "features": {
+ "indie": 100.0,
+ "male vocalists": 4.0,
+ "american": 36.0,
+ "pop": 10.0,
+ "rock": 7.0,
+ "indie rock": 12.0,
+ "electronic": 8.0,
+ "dance": 2.0,
+ "indie pop": 83.0,
+ "seen live": 23.0,
+ "alternative": 65.0,
+ "alternative rock": 7.0,
+ "00s": 1.0
+ }
+ },
+ {
+ "description": "Bon Iver",
+ "features": {
+ "indie": 75.0,
+ "singer-songwriter": 70.0,
+ "male vocalists": 4.0,
+ "Mellow": 3.0,
+ "chillout": 2.0,
+ "american": 7.0,
+ "experimental": 2.0,
+ "ambient": 2.0,
+ "rock": 2.0,
+ "beautiful": 3.0,
+ "indie rock": 5.0,
+ "indie pop": 2.0,
+ "seen live": 36.0,
+ "acoustic": 59.0,
+ "alternative": 6.0,
+ "00s": 2.0,
+ "folk": 100.0
+ }
+ },
+ {
+ "description": "Major Lazer",
+ "features": {
+ "indie": 2.0,
+ "american": 4.0,
+ "experimental": 3.0,
+ "british": 2.0,
+ "electronica": 5.0,
+ "pop": 2.0,
+ "electro": 37.0,
+ "hip hop": 2.0,
+ "electronic": 85.0,
+ "dance": 12.0,
+ "seen live": 100.0,
+ "Hip-Hop": 4.0,
+ "alternative": 2.0,
+ "House": 3.0,
+ "00s": 2.0,
+ "funk": 4.0,
+ "reggae": 66.0
+ }
+ },
+ {
+ "description": "Two Door Cinema Club",
+ "features": {
+ "indie": 100.0,
+ "male vocalists": 2.0,
+ "british": 63.0,
+ "rock": 6.0,
+ "pop": 3.0,
+ "electronica": 2.0,
+ "synthpop": 2.0,
+ "indie rock": 19.0,
+ "electronic": 68.0,
+ "dance": 2.0,
+ "britpop": 2.0,
+ "indie pop": 10.0,
+ "seen live": 47.0,
+ "alternative": 53.0,
+ "alternative rock": 4.0,
+ "00s": 2.0
+ }
+ },
+ {
+ "description": "OneRepublic",
+ "features": {
+ "indie": 63.0,
+ "favorites": 2.0,
+ "male vocalists": 8.0,
+ "emo": 1.0,
+ "american": 12.0,
+ "rock": 100.0,
+ "pop": 21.0,
+ "piano": 2.0,
+ "indie rock": 5.0,
+ "indie pop": 2.0,
+ "seen live": 9.0,
+ "alternative": 94.0,
+ "acoustic": 1.0,
+ "alternative rock": 80.0,
+ "00s": 3.0,
+ "Love": 2.0
+ }
+ },
+ {
+ "description": "Cage the Elephant",
+ "features": {
+ "indie": 59.0,
+ "male vocalists": 2.0,
+ "american": 11.0,
+ "rock": 68.0,
+ "punk rock": 44.0,
+ "indie rock": 100.0,
+ "seen live": 41.0,
+ "alternative": 73.0,
+ "alternative rock": 26.0,
+ "00s": 4.0,
+ "punk": 7.0
+ }
+ },
+ {
+ "description": "Arcade Fire",
+ "features": {
+ "indie": 100.0,
+ "male vocalists": 2.0,
+ "experimental": 6.0,
+ "rock": 48.0,
+ "pop": 2.0,
+ "beautiful": 1.0,
+ "post-rock": 2.0,
+ "indie rock": 99.0,
+ "new wave": 1.0,
+ "indie pop": 4.0,
+ "seen live": 59.0,
+ "alternative": 76.0,
+ "post-punk": 3.0,
+ "alternative rock": 16.0,
+ "00s": 5.0,
+ "female vocalists": 2.0,
+ "folk": 6.0
+ }
+ },
+ {
+ "description": "Bruno Mars",
+ "features": {
+ "indie": 3.0,
+ "male vocalists": 47.0,
+ "singer-songwriter": 7.0,
+ "soul": 10.0,
+ "american": 8.0,
+ "blues": 2.0,
+ "pop": 100.0,
+ "rock": 2.0,
+ "hip hop": 2.0,
+ "dance": 2.0,
+ "seen live": 6.0,
+ "Hip-Hop": 3.0,
+ "rnb": 63.0,
+ "alternative": 2.0,
+ "acoustic": 1.0,
+ "folk": 1.0,
+ "funk": 4.0,
+ "reggae": 4.0
+ }
+ },
+ {
+ "description": "Carly Rae Jepsen",
+ "features": {
+ "singer-songwriter": 5.0,
+ "soul": 2.0,
+ "chillout": 2.0,
+ "pop": 100.0,
+ "synthpop": 9.0,
+ "electronic": 4.0,
+ "dance": 11.0,
+ "seen live": 6.0,
+ "acoustic": 21.0,
+ "female vocalist": 4.0,
+ "00s": 1.0,
+ "female vocalists": 46.0,
+ "folk": 26.0
+ }
+ },
+ {
+ "description": "Weezer",
+ "features": {
+ "indie": 50.0,
+ "favorites": 3.0,
+ "male vocalists": 2.0,
+ "emo": 15.0,
+ "american": 8.0,
+ "classic rock": 2.0,
+ "rock": 100.0,
+ "pop": 6.0,
+ "punk rock": 5.0,
+ "indie rock": 41.0,
+ "britpop": 1.0,
+ "indie pop": 3.0,
+ "seen live": 37.0,
+ "hardcore": 1.0,
+ "Grunge": 2.0,
+ "alternative": 86.0,
+ "metal": 2.0,
+ "alternative rock": 73.0,
+ "00s": 2.0,
+ "punk": 11.0,
+ "Love": 1.0,
+ "hard rock": 2.0,
+ "90s": 9.0
+ }
+ },
+ {
+ "description": "P!nk",
+ "features": {
+ "indie": 2.0,
+ "favorites": 2.0,
+ "singer-songwriter": 5.0,
+ "soul": 2.0,
+ "american": 11.0,
+ "pop": 100.0,
+ "rock": 59.0,
+ "electronic": 2.0,
+ "dance": 7.0,
+ "seen live": 14.0,
+ "Hip-Hop": 2.0,
+ "rnb": 5.0,
+ "alternative": 4.0,
+ "female vocalist": 4.0,
+ "alternative rock": 2.0,
+ "00s": 4.0,
+ "female vocalists": 74.0,
+ "punk": 3.0
+ }
+ },
+ {
+ "description": "System of a Down",
+ "features": {
+ "indie": 2.0,
+ "favorites": 1.0,
+ "male vocalists": 1.0,
+ "emo": 2.0,
+ "american": 5.0,
+ "experimental": 3.0,
+ "rock": 65.0,
+ "punk rock": 2.0,
+ "metalcore": 1.0,
+ "heavy metal": 6.0,
+ "Progressive metal": 3.0,
+ "thrash metal": 2.0,
+ "seen live": 18.0,
+ "hardcore": 3.0,
+ "metal": 100.0,
+ "alternative": 54.0,
+ "Progressive rock": 2.0,
+ "Nu Metal": 62.0,
+ "alternative rock": 13.0,
+ "industrial": 1.0,
+ "00s": 2.0,
+ "punk": 3.0,
+ "hard rock": 20.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "Adele",
+ "features": {
+ "indie": 40.0,
+ "singer-songwriter": 50.0,
+ "soul": 100.0,
+ "jazz": 8.0,
+ "chillout": 2.0,
+ "Mellow": 2.0,
+ "british": 66.0,
+ "blues": 3.0,
+ "pop": 19.0,
+ "rock": 2.0,
+ "beautiful": 1.0,
+ "piano": 2.0,
+ "britpop": 3.0,
+ "indie pop": 3.0,
+ "seen live": 2.0,
+ "rnb": 2.0,
+ "acoustic": 4.0,
+ "alternative": 4.0,
+ "female vocalist": 4.0,
+ "00s": 2.0,
+ "female vocalists": 81.0,
+ "Love": 2.0,
+ "folk": 2.0
+ }
+ },
+ {
+ "description": "xxxtentacion",
+ "features": {
+ "american": 11.0,
+ "experimental": 7.0,
+ "punk rock": 4.0,
+ "rap": 80.0,
+ "folk": 4.0,
+ "rock": 7.0,
+ "pop": 4.0,
+ "heavy metal": 4.0,
+ "seen live": 4.0,
+ "rnb": 7.0,
+ "emo": 49.0,
+ "soul": 4.0,
+ "hip hop": 32.0,
+ "new wave": 4.0,
+ "hardcore": 4.0,
+ "Hip-Hop": 100.0,
+ "alternative": 11.0,
+ "alternative rock": 7.0
+ }
+ },
+ {
+ "description": "The 1975",
+ "features": {
+ "male vocalists": 5.0,
+ "british": 69.0,
+ "experimental": 2.0,
+ "indie rock": 98.0,
+ "Love": 1.0,
+ "indie": 100.0,
+ "emo": 1.0,
+ "ambient": 1.0,
+ "rock": 21.0,
+ "pop": 9.0,
+ "post-rock": 1.0,
+ "synthpop": 5.0,
+ "new wave": 4.0,
+ "electronic": 3.0,
+ "britpop": 1.0,
+ "indie pop": 17.0,
+ "seen live": 73.0,
+ "alternative": 69.0,
+ "alternative rock": 20.0,
+ "00s": 1.0,
+ "funk": 1.0
+ }
+ },
+ {
+ "description": "Depeche Mode",
+ "features": {
+ "indie": 3.0,
+ "favorites": 1.0,
+ "male vocalists": 2.0,
+ "british": 13.0,
+ "ambient": 1.0,
+ "experimental": 1.0,
+ "classic rock": 2.0,
+ "rock": 16.0,
+ "electronica": 11.0,
+ "pop": 9.0,
+ "electro": 3.0,
+ "synthpop": 56.0,
+ "electronic": 100.0,
+ "new wave": 87.0,
+ "dance": 3.0,
+ "britpop": 2.0,
+ "seen live": 22.0,
+ "techno": 1.0,
+ "alternative": 20.0,
+ "Gothic": 2.0,
+ "post-punk": 4.0,
+ "alternative rock": 5.0,
+ "industrial": 3.0,
+ "00s": 2.0,
+ "80s": 59.0,
+ "90s": 4.0
+ }
+ },
+ {
+ "description": "The White Stripes",
+ "features": {
+ "indie": 59.0,
+ "favorites": 2.0,
+ "male vocalists": 1.0,
+ "singer-songwriter": 1.0,
+ "american": 8.0,
+ "experimental": 1.0,
+ "blues": 13.0,
+ "classic rock": 3.0,
+ "rock": 100.0,
+ "pop": 2.0,
+ "punk rock": 2.0,
+ "indie rock": 47.0,
+ "seen live": 25.0,
+ "Grunge": 1.0,
+ "alternative": 74.0,
+ "metal": 1.0,
+ "guitar": 2.0,
+ "Progressive rock": 1.0,
+ "alternative rock": 65.0,
+ "00s": 3.0,
+ "punk": 5.0,
+ "hard rock": 3.0,
+ "folk": 2.0,
+ "90s": 2.0
+ }
+ },
+ {
+ "description": "The Clash",
+ "features": {
+ "indie": 5.0,
+ "british": 43.0,
+ "classic rock": 29.0,
+ "rock": 43.0,
+ "pop": 1.0,
+ "punk rock": 71.0,
+ "indie rock": 2.0,
+ "new wave": 4.0,
+ "alternative": 9.0,
+ "post-punk": 3.0,
+ "alternative rock": 2.0,
+ "punk": 100.0,
+ "hard rock": 1.0,
+ "70s": 8.0,
+ "80s": 13.0,
+ "reggae": 6.0
+ }
+ }
+]
\ No newline at end of file
diff --git a/algorithms-miscellaneous-3/src/main/resources/kmeans/lastfm.json b/algorithms-miscellaneous-3/src/main/resources/kmeans/lastfm.json
new file mode 100644
index 0000000000..4d684b2fc0
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/resources/kmeans/lastfm.json
@@ -0,0 +1,490 @@
+{
+ "children": [
+ {
+ "children": [
+ {
+ "name": "Radiohead"
+ },
+ {
+ "name": "Red Hot Chili Peppers"
+ },
+ {
+ "name": "Coldplay"
+ },
+ {
+ "name": "Nirvana"
+ },
+ {
+ "name": "Panic! at the Disco"
+ },
+ {
+ "name": "The Cure"
+ },
+ {
+ "name": "Linkin Park"
+ },
+ {
+ "name": "Radiohead"
+ },
+ {
+ "name": "Red Hot Chili Peppers"
+ },
+ {
+ "name": "Coldplay"
+ },
+ {
+ "name": "Nirvana"
+ },
+ {
+ "name": "Panic! at the Disco"
+ },
+ {
+ "name": "The Cure"
+ },
+ {
+ "name": "Linkin Park"
+ },
+ {
+ "name": "Muse"
+ },
+ {
+ "name": "Maroon 5"
+ },
+ {
+ "name": "Foo Fighters"
+ },
+ {
+ "name": "Paramore"
+ },
+ {
+ "name": "Oasis"
+ },
+ {
+ "name": "Fall Out Boy"
+ },
+ {
+ "name": "OneRepublic"
+ },
+ {
+ "name": "Weezer"
+ },
+ {
+ "name": "System of a Down"
+ },
+ {
+ "name": "The White Stripes"
+ }
+ ],
+ "name": "rock, alternative"
+ },
+ {
+ "children": [
+ {
+ "name": "Lil Nas X"
+ },
+ {
+ "name": "Post Malone"
+ },
+ {
+ "name": "Drake"
+ },
+ {
+ "name": "Kanye West"
+ },
+ {
+ "name": "Kendrick Lamar"
+ },
+ {
+ "name": "Tyler, the Creator"
+ },
+ {
+ "name": "Eminem"
+ },
+ {
+ "name": "Childish Gambino"
+ },
+ {
+ "name": "Frank Ocean"
+ },
+ {
+ "name": "Lil Nas X"
+ },
+ {
+ "name": "Post Malone"
+ },
+ {
+ "name": "Drake"
+ },
+ {
+ "name": "Kanye West"
+ },
+ {
+ "name": "Kendrick Lamar"
+ },
+ {
+ "name": "Tyler, the Creator"
+ },
+ {
+ "name": "Eminem"
+ },
+ {
+ "name": "Childish Gambino"
+ },
+ {
+ "name": "Frank Ocean"
+ },
+ {
+ "name": "Lizzo"
+ },
+ {
+ "name": "Travi$ Scott"
+ },
+ {
+ "name": "A$AP Rocky"
+ },
+ {
+ "name": "Nicki Minaj"
+ },
+ {
+ "name": "xxxtentacion"
+ }
+ ],
+ "name": "Hip-Hop, rap"
+ },
+ {
+ "children": [
+ {
+ "name": "Arctic Monkeys"
+ },
+ {
+ "name": "Imagine Dragons"
+ },
+ {
+ "name": "The Killers"
+ },
+ {
+ "name": "Gorillaz"
+ },
+ {
+ "name": "The Black Keys"
+ },
+ {
+ "name": "Arctic Monkeys"
+ },
+ {
+ "name": "Imagine Dragons"
+ },
+ {
+ "name": "The Killers"
+ },
+ {
+ "name": "Gorillaz"
+ },
+ {
+ "name": "The Black Keys"
+ },
+ {
+ "name": "Twenty One Pilots"
+ },
+ {
+ "name": "Ellie Goulding"
+ },
+ {
+ "name": "Florence + the Machine"
+ },
+ {
+ "name": "Vampire Weekend"
+ },
+ {
+ "name": "The Smiths"
+ },
+ {
+ "name": "The Strokes"
+ },
+ {
+ "name": "MGMT"
+ },
+ {
+ "name": "Foster the People"
+ },
+ {
+ "name": "Two Door Cinema Club"
+ },
+ {
+ "name": "Cage the Elephant"
+ },
+ {
+ "name": "Arcade Fire"
+ },
+ {
+ "name": "The 1975"
+ }
+ ],
+ "name": "indie, alternative"
+ },
+ {
+ "children": [
+ {
+ "name": "Ed Sheeran"
+ },
+ {
+ "name": "Tame Impala"
+ },
+ {
+ "name": "Ed Sheeran"
+ },
+ {
+ "name": "Tame Impala"
+ },
+ {
+ "name": "Green Day"
+ },
+ {
+ "name": "Metallica"
+ },
+ {
+ "name": "blink-182"
+ },
+ {
+ "name": "Bon Iver"
+ },
+ {
+ "name": "The Clash"
+ }
+ ],
+ "name": "rock, punk rock"
+ },
+ {
+ "children": [
+ {
+ "name": "Calvin Harris"
+ },
+ {
+ "name": "The Weeknd"
+ },
+ {
+ "name": "The Chainsmokers"
+ },
+ {
+ "name": "Daft Punk"
+ },
+ {
+ "name": "Marshmello"
+ },
+ {
+ "name": "David Guetta"
+ },
+ {
+ "name": "Calvin Harris"
+ },
+ {
+ "name": "The Weeknd"
+ },
+ {
+ "name": "The Chainsmokers"
+ },
+ {
+ "name": "Daft Punk"
+ },
+ {
+ "name": "Marshmello"
+ },
+ {
+ "name": "David Guetta"
+ },
+ {
+ "name": "Avicii"
+ },
+ {
+ "name": "Kygo"
+ },
+ {
+ "name": "Martin Garrix"
+ },
+ {
+ "name": "Major Lazer"
+ },
+ {
+ "name": "Depeche Mode"
+ }
+ ],
+ "name": "electronic, dance"
+ },
+ {
+ "children": [
+ {
+ "name": "Queen"
+ },
+ {
+ "name": "The Beatles"
+ },
+ {
+ "name": "David Bowie"
+ },
+ {
+ "name": "Fleetwood Mac"
+ },
+ {
+ "name": "Pink Floyd"
+ },
+ {
+ "name": "The Rolling Stones"
+ },
+ {
+ "name": "Led Zeppelin"
+ },
+ {
+ "name": "Queen"
+ },
+ {
+ "name": "The Beatles"
+ },
+ {
+ "name": "David Bowie"
+ },
+ {
+ "name": "Fleetwood Mac"
+ },
+ {
+ "name": "Pink Floyd"
+ },
+ {
+ "name": "The Rolling Stones"
+ },
+ {
+ "name": "Led Zeppelin"
+ },
+ {
+ "name": "Elton John"
+ }
+ ],
+ "name": "classic rock, rock"
+ },
+ {
+ "children": [
+ {
+ "name": "Billie Eilish"
+ },
+ {
+ "name": "Ariana Grande"
+ },
+ {
+ "name": "Taylor Swift"
+ },
+ {
+ "name": "Beyoncé"
+ },
+ {
+ "name": "Shawn Mendes"
+ },
+ {
+ "name": "Rihanna"
+ },
+ {
+ "name": "Lana Del Rey"
+ },
+ {
+ "name": "Katy Perry"
+ },
+ {
+ "name": "Lady Gaga"
+ },
+ {
+ "name": "Miley Cyrus"
+ },
+ {
+ "name": "Mark Ronson"
+ },
+ {
+ "name": "Madonna"
+ },
+ {
+ "name": "Lorde"
+ },
+ {
+ "name": "Khalid"
+ },
+ {
+ "name": "Billie Eilish"
+ },
+ {
+ "name": "Ariana Grande"
+ },
+ {
+ "name": "Taylor Swift"
+ },
+ {
+ "name": "Beyoncé"
+ },
+ {
+ "name": "Shawn Mendes"
+ },
+ {
+ "name": "Rihanna"
+ },
+ {
+ "name": "Lana Del Rey"
+ },
+ {
+ "name": "Katy Perry"
+ },
+ {
+ "name": "Lady Gaga"
+ },
+ {
+ "name": "Miley Cyrus"
+ },
+ {
+ "name": "Mark Ronson"
+ },
+ {
+ "name": "Madonna"
+ },
+ {
+ "name": "Lorde"
+ },
+ {
+ "name": "Khalid"
+ },
+ {
+ "name": "Sia"
+ },
+ {
+ "name": "Sam Smith"
+ },
+ {
+ "name": "Halsey"
+ },
+ {
+ "name": "Michael Jackson"
+ },
+ {
+ "name": "Charli XCX"
+ },
+ {
+ "name": "Britney Spears"
+ },
+ {
+ "name": "Dua Lipa"
+ },
+ {
+ "name": "Jonas Brothers"
+ },
+ {
+ "name": "Bruno Mars"
+ },
+ {
+ "name": "Carly Rae Jepsen"
+ },
+ {
+ "name": "P!nk"
+ },
+ {
+ "name": "Adele"
+ }
+ ],
+ "name": "pop, female vocalists"
+ }
+ ],
+ "name": "Musicians"
+}
diff --git a/algorithms-miscellaneous-3/src/main/resources/kmeans/radial.html b/algorithms-miscellaneous-3/src/main/resources/kmeans/radial.html
new file mode 100644
index 0000000000..e7e7403871
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/main/resources/kmeans/radial.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java
new file mode 100644
index 0000000000..8ad962055e
--- /dev/null
+++ b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/interpolationsearch/InterpolationSearchUnitTest.java
@@ -0,0 +1,29 @@
+package com.baeldung.algorithms.interpolationsearch;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class InterpolationSearchUnitTest {
+
+ private int[] myData;
+
+ @Before
+ public void setUp() {
+ myData = new int[]{13,21,34,55,69,73,84,101};
+ }
+
+ @Test
+ public void givenSortedArray_whenLookingFor84_thenReturn6() {
+ int pos = InterpolationSearch.interpolationSearch(myData, 84);
+ assertEquals(6, pos);
+ }
+
+ @Test
+ public void givenSortedArray_whenLookingFor19_thenReturnMinusOne() {
+ int pos = InterpolationSearch.interpolationSearch(myData, 19);
+ assertEquals(-1, pos);
+ }
+
+}
diff --git a/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamplesUnitTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamplesUnitTest.java
index 6fa6584b8e..97e99290c9 100644
--- a/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamplesUnitTest.java
+++ b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/printtriangles/PrintTriangleExamplesUnitTest.java
@@ -9,9 +9,9 @@ import static org.junit.Assert.assertEquals;
@RunWith(JUnitParamsRunner.class)
public class PrintTriangleExamplesUnitTest {
-
- private static Object[][] rightAngledTriangles() {
- String expected0 = "";
+
+ private static Object[][] rightTriangles() {
+ String expected0 = "";
String expected2 = "*" + System.lineSeparator()
+ "**" + System.lineSeparator();
@@ -39,9 +39,9 @@ public class PrintTriangleExamplesUnitTest {
}
@Test
- @Parameters(method = "rightAngledTriangles")
- public void whenPrintARightAngledTriangleIsCalled_ThenTheCorrectStringIsReturned(int nrOfRows, String expected) {
- String actual = PrintTriangleExamples.printARightAngledTriangle(nrOfRows);
+ @Parameters(method = "rightTriangles")
+ public void whenPrintARightTriangleIsCalled_ThenTheCorrectStringIsReturned(int nrOfRows, String expected) {
+ String actual = PrintTriangleExamples.printARightTriangle(nrOfRows);
assertEquals(expected, actual);
}
@@ -81,6 +81,14 @@ public class PrintTriangleExamplesUnitTest {
assertEquals(expected, actual);
}
+
+ @Test
+ @Parameters(method = "isoscelesTriangles")
+ public void whenPrintAnIsoscelesTriangleUsingStringUtilsIsCalled_ThenTheCorrectStringIsReturned(int nrOfRows, String expected) {
+ String actual = PrintTriangleExamples.printAnIsoscelesTriangleUsingStringUtils(nrOfRows);
+
+ assertEquals(expected, actual);
+ }
@Test
@Parameters(method = "isoscelesTriangles")
diff --git a/algorithms-sorting/README.md b/algorithms-sorting/README.md
index 36460293b0..48c75f88cd 100644
--- a/algorithms-sorting/README.md
+++ b/algorithms-sorting/README.md
@@ -5,3 +5,4 @@
- [Quicksort Algorithm Implementation in Java](https://www.baeldung.com/java-quicksort)
- [Insertion Sort in Java](https://www.baeldung.com/java-insertion-sort)
- [Heap Sort in Java](https://www.baeldung.com/java-heap-sort)
+- [Shell Sort in Java](https://www.baeldung.com/java-shell-sort)
diff --git a/core-groovy-2/README.md b/core-groovy-2/README.md
index 33df8b107b..1211dae76d 100644
--- a/core-groovy-2/README.md
+++ b/core-groovy-2/README.md
@@ -8,3 +8,4 @@
- [Pattern Matching in Strings in Groovy](https://www.baeldung.com/groovy-pattern-matching)
- [Working with XML in Groovy](https://www.baeldung.com/groovy-xml)
- [Integrating Groovy into Java Applications](https://www.baeldung.com/groovy-java-applications)
+- [Concatenate Strings with Groovy](https://www.baeldung.com/groovy-concatenate-strings)
diff --git a/core-java-modules/core-java-arrays-2/README.MD b/core-java-modules/core-java-arrays-2/README.MD
index 9ee6998784..f272f4d299 100644
--- a/core-java-modules/core-java-arrays-2/README.MD
+++ b/core-java-modules/core-java-arrays-2/README.MD
@@ -1,3 +1,5 @@
## Relevant Articles
- [Extending an Array’s Length](https://www.baeldung.com/java-array-add-element-at-the-end)
+- [Checking If an Array Is Sorted in Java](https://www.baeldung.com/java-check-sorted-array)
+- [Looping Diagonally Through a 2d Java Array](https://www.baeldung.com/java-loop-diagonal-array)
diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGenerator.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGenerator.java
new file mode 100644
index 0000000000..97d44e5156
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGenerator.java
@@ -0,0 +1,11 @@
+package com.baeldung.concurrent.mutex;
+
+public class SequenceGenerator {
+ private int currentValue = 0;
+
+ public int getNextSequence() throws InterruptedException {
+ currentValue = currentValue + 1;
+ Thread.sleep(500);
+ return currentValue;
+ }
+}
diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingMonitor.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingMonitor.java
new file mode 100644
index 0000000000..30c8da4865
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingMonitor.java
@@ -0,0 +1,18 @@
+package com.baeldung.concurrent.mutex;
+
+import com.google.common.util.concurrent.Monitor;
+
+public class SequenceGeneratorUsingMonitor extends SequenceGenerator {
+
+ private Monitor monitor = new Monitor();
+
+ @Override
+ public int getNextSequence() throws InterruptedException {
+ monitor.enter();
+ try {
+ return super.getNextSequence();
+ } finally {
+ monitor.leave();
+ }
+ }
+}
diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingReentrantLock.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingReentrantLock.java
new file mode 100644
index 0000000000..85ce780bda
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingReentrantLock.java
@@ -0,0 +1,18 @@
+package com.baeldung.concurrent.mutex;
+
+import java.util.concurrent.locks.ReentrantLock;
+
+public class SequenceGeneratorUsingReentrantLock extends SequenceGenerator {
+
+ private ReentrantLock mutex = new ReentrantLock();
+
+ @Override
+ public int getNextSequence() throws InterruptedException {
+ try {
+ mutex.lock();
+ return super.getNextSequence();
+ } finally {
+ mutex.unlock();
+ }
+ }
+}
diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingSemaphore.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingSemaphore.java
new file mode 100644
index 0000000000..fdece049e6
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingSemaphore.java
@@ -0,0 +1,18 @@
+package com.baeldung.concurrent.mutex;
+
+import java.util.concurrent.Semaphore;
+
+public class SequenceGeneratorUsingSemaphore extends SequenceGenerator {
+
+ private Semaphore mutex = new Semaphore(1);
+
+ @Override
+ public int getNextSequence() throws InterruptedException {
+ try {
+ mutex.acquire();
+ return super.getNextSequence();
+ } finally {
+ mutex.release();
+ }
+ }
+}
diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingSynchronizedBlock.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingSynchronizedBlock.java
new file mode 100644
index 0000000000..d485eae21c
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingSynchronizedBlock.java
@@ -0,0 +1,12 @@
+package com.baeldung.concurrent.mutex;
+
+public class SequenceGeneratorUsingSynchronizedBlock extends SequenceGenerator {
+
+ @Override
+ public int getNextSequence() throws InterruptedException {
+ synchronized (this) {
+ return super.getNextSequence();
+ }
+ }
+
+}
diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingSynchronizedMethod.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingSynchronizedMethod.java
new file mode 100644
index 0000000000..441b33dc43
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/mutex/SequenceGeneratorUsingSynchronizedMethod.java
@@ -0,0 +1,10 @@
+package com.baeldung.concurrent.mutex;
+
+public class SequenceGeneratorUsingSynchronizedMethod extends SequenceGenerator {
+
+ @Override
+ public synchronized int getNextSequence() throws InterruptedException {
+ return super.getNextSequence();
+ }
+
+}
diff --git a/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/mutex/MutexUnitTest.java b/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/mutex/MutexUnitTest.java
new file mode 100644
index 0000000000..620179800a
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/mutex/MutexUnitTest.java
@@ -0,0 +1,81 @@
+package com.baeldung.concurrent.mutex;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.baeldung.concurrent.mutex.SequenceGenerator;
+import com.baeldung.concurrent.mutex.SequenceGeneratorUsingMonitor;
+import com.baeldung.concurrent.mutex.SequenceGeneratorUsingReentrantLock;
+import com.baeldung.concurrent.mutex.SequenceGeneratorUsingSemaphore;
+import com.baeldung.concurrent.mutex.SequenceGeneratorUsingSynchronizedBlock;
+import com.baeldung.concurrent.mutex.SequenceGeneratorUsingSynchronizedMethod;
+
+public class MutexUnitTest {
+
+ private final int RANGE = 30;
+
+ @Test
+ public void givenUnsafeSequenceGenerator_whenRaceCondition_thenUnexpectedBehavior() throws Exception {
+ Set uniqueSequences = getASetOFUniqueSequences(new SequenceGenerator());
+ Assert.assertNotEquals(RANGE, uniqueSequences.size());
+ }
+
+ @Test
+ public void givenSequenceGeneratorUsingSynchronizedMethod_whenRaceCondition_thenSuccess() throws Exception {
+ Set uniqueSequences = getASetOFUniqueSequences(new SequenceGeneratorUsingSynchronizedMethod());
+ Assert.assertEquals(RANGE, uniqueSequences.size());
+ }
+
+ @Test
+ public void givenSequenceGeneratorUsingSynchronizedBlock_whenRaceCondition_thenSuccess() throws Exception {
+ Set uniqueSequences = getASetOFUniqueSequences(new SequenceGeneratorUsingSynchronizedBlock());
+ Assert.assertEquals(RANGE, uniqueSequences.size());
+ }
+
+ @Test
+ public void givenSequenceGeneratorUsingReentrantLock_whenRaceCondition_thenSuccess() throws Exception {
+ Set uniqueSequences = getASetOFUniqueSequences(new SequenceGeneratorUsingReentrantLock());
+ Assert.assertEquals(RANGE, uniqueSequences.size());
+ }
+
+ @Test
+ public void givenSequenceGeneratorUsingSemaphore_whenRaceCondition_thenSuccess() throws Exception {
+ Set uniqueSequences = getASetOFUniqueSequences(new SequenceGeneratorUsingSemaphore());
+ Assert.assertEquals(RANGE, uniqueSequences.size());
+ }
+
+ @Test
+ public void givenSequenceGeneratorUsingMonitor_whenRaceCondition_thenSuccess() throws Exception {
+ Set uniqueSequences = getASetOFUniqueSequences(new SequenceGeneratorUsingMonitor());
+ Assert.assertEquals(RANGE, uniqueSequences.size());
+ }
+
+ private Set getASetOFUniqueSequences(SequenceGenerator generator) throws Exception {
+ ExecutorService executor = Executors.newFixedThreadPool(3);
+ Set uniqueSequences = new HashSet<>();
+ List> futures = new ArrayList<>();
+
+ for (int i = 0; i < RANGE; i++) {
+ futures.add(executor.submit(generator::getNextSequence));
+ }
+
+ for (Future future : futures) {
+ uniqueSequences.add(future.get());
+ }
+
+ executor.awaitTermination(15, TimeUnit.SECONDS);
+ executor.shutdown();
+
+ return uniqueSequences;
+ }
+
+}
diff --git a/core-java-modules/core-java-jndi/pom.xml b/core-java-modules/core-java-jndi/pom.xml
new file mode 100644
index 0000000000..eb363f8598
--- /dev/null
+++ b/core-java-modules/core-java-jndi/pom.xml
@@ -0,0 +1,65 @@
+
+
+ 4.0.0
+
+ com.baeldung.jndi
+ core-java-jndi
+ 1.0-SNAPSHOT
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+ ../../
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.5.1
+ test
+
+
+ org.springframework
+ spring-core
+ 5.0.9.RELEASE
+
+
+ org.springframework
+ spring-context
+ 5.0.9.RELEASE
+
+
+ org.springframework
+ spring-jdbc
+ 5.0.9.RELEASE
+
+
+ org.springframework
+ spring-test
+ 5.0.9.RELEASE
+ test
+
+
+ com.h2database
+ h2
+ 1.4.199
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+
+
diff --git a/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/JndiUnitTest.java b/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/JndiUnitTest.java
new file mode 100644
index 0000000000..9eea420e7a
--- /dev/null
+++ b/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/JndiUnitTest.java
@@ -0,0 +1,60 @@
+package com.baeldung.jndi;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.jndi.JndiTemplate;
+import org.springframework.mock.jndi.SimpleNamingContextBuilder;
+
+import javax.naming.*;
+import javax.sql.DataSource;
+
+import java.util.Enumeration;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JndiUnitTest {
+
+ private static InitialContext ctx;
+ private static DriverManagerDataSource ds;
+
+ @BeforeAll
+ static void setUp() throws Exception {
+ SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
+ ds = new DriverManagerDataSource("jdbc:h2:mem:mydb");
+ builder.activate();
+
+ JndiTemplate jndiTemplate = new JndiTemplate();
+ ctx = (InitialContext) jndiTemplate.getContext();
+ }
+
+ @Test
+ void givenACompositeName_whenAddingAnElement_thenNameIncludesIt() throws Exception {
+ Name objectName = new CompositeName("java:comp/env/jdbc");
+
+ Enumeration elements = objectName.getAll();
+ while(elements.hasMoreElements()) {
+ System.out.println(elements.nextElement());
+ }
+
+ objectName.add("example");
+
+ assertEquals("env", objectName.get(1));
+ assertEquals("example", objectName.get(objectName.size() - 1));
+ }
+
+ @Test
+ void givenADataSource_whenAddingDriver_thenBind() throws Exception {
+ ds.setDriverClassName("org.h2.Driver");
+ ctx.bind("java:comp/env/jdbc/datasource", ds);
+ }
+
+ @Test
+ void givenContext_whenLookupByName_thenValidDataSource() throws Exception {
+ DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
+
+ assertNotNull(ds);
+ assertNotNull(ds.getConnection());
+ }
+
+}
diff --git a/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/exceptions/JndiExceptionsUnitTest.java b/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/exceptions/JndiExceptionsUnitTest.java
new file mode 100644
index 0000000000..49d4facffb
--- /dev/null
+++ b/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/exceptions/JndiExceptionsUnitTest.java
@@ -0,0 +1,42 @@
+package com.baeldung.jndi.exceptions;
+
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.jndi.JndiTemplate;
+import org.springframework.mock.jndi.SimpleNamingContextBuilder;
+
+import javax.naming.InitialContext;
+import javax.naming.NameNotFoundException;
+import javax.naming.NoInitialContextException;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class JndiExceptionsUnitTest {
+
+ @Test
+ @Order(1)
+ void givenNoContext_whenLookupObject_thenThrowNoInitialContext() {
+ assertThrows(NoInitialContextException.class, () -> {
+ JndiTemplate jndiTemplate = new JndiTemplate();
+ InitialContext ctx = (InitialContext) jndiTemplate.getContext();
+ ctx.lookup("java:comp/env/jdbc/datasource");
+ }).printStackTrace();
+ }
+
+ @Test
+ @Order(2)
+ void givenEmptyContext_whenLookupNotBounds_thenThrowNameNotFound() {
+ assertThrows(NameNotFoundException.class, () -> {
+ SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
+ builder.activate();
+
+ JndiTemplate jndiTemplate = new JndiTemplate();
+ InitialContext ctx = (InitialContext) jndiTemplate.getContext();
+ ctx.lookup("badJndiName");
+ }).printStackTrace();
+ }
+
+}
diff --git a/core-java-modules/core-java-networking-2/README.md b/core-java-modules/core-java-networking-2/README.md
new file mode 100644
index 0000000000..6b6151248e
--- /dev/null
+++ b/core-java-modules/core-java-networking-2/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles
+
+- [Checking if a URL Exists in Java](https://www.baeldung.com/java-check-url-exists)
diff --git a/core-java-modules/core-java-os/README.md b/core-java-modules/core-java-os/README.md
index 5f5d373d9b..697af5e4d6 100644
--- a/core-java-modules/core-java-os/README.md
+++ b/core-java-modules/core-java-os/README.md
@@ -7,4 +7,4 @@ This module uses Java 9, so make sure to have the JDK 9 installed to run it.
- [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)
-
+- [Get the Current Working Directory in Java](https://www.baeldung.com/java-current-directory)
diff --git a/java-math/src/main/java/com/baeldung/matrices/HomemadeMatrix.java b/java-math/src/main/java/com/baeldung/matrices/HomemadeMatrix.java
new file mode 100644
index 0000000000..0676250959
--- /dev/null
+++ b/java-math/src/main/java/com/baeldung/matrices/HomemadeMatrix.java
@@ -0,0 +1,23 @@
+package com.baeldung.matrices;
+
+public class HomemadeMatrix {
+ public static double[][] multiplyMatrices(double[][] firstMatrix, double[][] secondMatrix) {
+ double[][] result = new double[firstMatrix.length][secondMatrix[0].length];
+
+ for (int row = 0; row < result.length; row++) {
+ for (int col = 0; col < result[row].length; col++) {
+ result[row][col] = multiplyMatricesCell(firstMatrix, secondMatrix, row, col);
+ }
+ }
+
+ return result;
+ }
+
+ private static double multiplyMatricesCell(double[][] firstMatrix, double[][] secondMatrix, int row, int col) {
+ double cell = 0;
+ for (int i = 0; i < secondMatrix.length; i++) {
+ cell += firstMatrix[row][i] * secondMatrix[i][col];
+ }
+ return cell;
+ }
+}
\ No newline at end of file
diff --git a/java-math/src/test/java/com/baeldung/algorithms/logarithm/LogarithmUnitTest.java b/java-math/src/test/java/com/baeldung/algorithms/logarithm/LogarithmUnitTest.java
new file mode 100644
index 0000000000..facad1edc4
--- /dev/null
+++ b/java-math/src/test/java/com/baeldung/algorithms/logarithm/LogarithmUnitTest.java
@@ -0,0 +1,31 @@
+package com.baeldung.algorithms.logarithm;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.Test;
+
+public class LogarithmUnitTest {
+
+ @Test
+ public void givenLog10_shouldReturnValidResults() {
+ assertEquals(Math.log10(100), 2);
+ assertEquals(Math.log10(1000), 3);
+ }
+
+ @Test
+ public void givenLogE_shouldReturnValidResults() {
+ assertEquals(Math.log(Math.E), 1);
+ assertEquals(Math.log(10), 2.30258, 0.00001);
+ }
+
+ @Test
+ public void givenCustomLog_shouldReturnValidResults() {
+ assertEquals(customLog(2, 256), 8);
+ assertEquals(customLog(10, 100), 2);
+ }
+
+ private static double customLog(double base, double logNumber) {
+ return Math.log(logNumber) / Math.log(base);
+ }
+
+}
diff --git a/java-math/src/test/java/com/baeldung/matrices/MatrixMultiplicationBenchmarking.java b/java-math/src/test/java/com/baeldung/matrices/MatrixMultiplicationBenchmarking.java
index 1e3b183aa7..171a1d28a4 100644
--- a/java-math/src/test/java/com/baeldung/matrices/MatrixMultiplicationBenchmarking.java
+++ b/java-math/src/test/java/com/baeldung/matrices/MatrixMultiplicationBenchmarking.java
@@ -1,9 +1,84 @@
package com.baeldung.matrices;
+import cern.colt.matrix.DoubleFactory2D;
+import cern.colt.matrix.DoubleMatrix2D;
+import cern.colt.matrix.linalg.Algebra;
+import org.apache.commons.math3.linear.Array2DRowRealMatrix;
+import org.apache.commons.math3.linear.RealMatrix;
+import org.ejml.simple.SimpleMatrix;
+import org.la4j.Matrix;
+import org.la4j.matrix.dense.Basic2DMatrix;
+import org.nd4j.linalg.api.ndarray.INDArray;
+import org.nd4j.linalg.factory.Nd4j;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
public class MatrixMultiplicationBenchmarking {
public static void main(String[] args) throws Exception {
- org.openjdk.jmh.Main.main(args);
+ Options opt = new OptionsBuilder()
+ .include(MatrixMultiplicationBenchmarking.class.getSimpleName())
+ .mode(Mode.AverageTime)
+ .forks(2)
+ .warmupIterations(5)
+ .measurementIterations(10)
+ .timeUnit(TimeUnit.MICROSECONDS)
+ .build();
+
+ new Runner(opt).run();
}
-}
+ @Benchmark
+ public Object homemadeMatrixMultiplication(MatrixProvider matrixProvider) {
+ return HomemadeMatrix.multiplyMatrices(matrixProvider.getFirstMatrix(), matrixProvider.getSecondMatrix());
+ }
+
+ @Benchmark
+ public Object ejmlMatrixMultiplication(MatrixProvider matrixProvider) {
+ SimpleMatrix firstMatrix = new SimpleMatrix(matrixProvider.getFirstMatrix());
+ SimpleMatrix secondMatrix = new SimpleMatrix(matrixProvider.getSecondMatrix());
+
+ return firstMatrix.mult(secondMatrix);
+ }
+
+ @Benchmark
+ public Object apacheCommonsMatrixMultiplication(MatrixProvider matrixProvider) {
+ RealMatrix firstMatrix = new Array2DRowRealMatrix(matrixProvider.getFirstMatrix());
+ RealMatrix secondMatrix = new Array2DRowRealMatrix(matrixProvider.getSecondMatrix());
+
+ return firstMatrix.multiply(secondMatrix);
+ }
+
+ @Benchmark
+ public Object la4jMatrixMultiplication(MatrixProvider matrixProvider) {
+ Matrix firstMatrix = new Basic2DMatrix(matrixProvider.getFirstMatrix());
+ Matrix secondMatrix = new Basic2DMatrix(matrixProvider.getSecondMatrix());
+
+ return firstMatrix.multiply(secondMatrix);
+ }
+
+ @Benchmark
+ public Object nd4jMatrixMultiplication(MatrixProvider matrixProvider) {
+ INDArray firstMatrix = Nd4j.create(matrixProvider.getFirstMatrix());
+ INDArray secondMatrix = Nd4j.create(matrixProvider.getSecondMatrix());
+
+ return firstMatrix.mmul(secondMatrix);
+ }
+
+ @Benchmark
+ public Object coltMatrixMultiplication(MatrixProvider matrixProvider) {
+ DoubleFactory2D doubleFactory2D = DoubleFactory2D.dense;
+
+ DoubleMatrix2D firstMatrix = doubleFactory2D.make(matrixProvider.getFirstMatrix());
+ DoubleMatrix2D secondMatrix = doubleFactory2D.make(matrixProvider.getSecondMatrix());
+
+ Algebra algebra = new Algebra();
+ return algebra.mult(firstMatrix, secondMatrix);
+ }
+
+}
\ No newline at end of file
diff --git a/java-math/src/test/java/com/baeldung/matrices/MatrixProvider.java b/java-math/src/test/java/com/baeldung/matrices/MatrixProvider.java
new file mode 100644
index 0000000000..33bd074b6e
--- /dev/null
+++ b/java-math/src/test/java/com/baeldung/matrices/MatrixProvider.java
@@ -0,0 +1,33 @@
+package com.baeldung.matrices;
+
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+
+@State(Scope.Benchmark)
+public class MatrixProvider {
+ private double[][] firstMatrix;
+ private double[][] secondMatrix;
+
+ public MatrixProvider() {
+ firstMatrix =
+ new double[][] {
+ new double[] {1d, 5d},
+ new double[] {2d, 3d},
+ new double[] {1d ,7d}
+ };
+
+ secondMatrix =
+ new double[][] {
+ new double[] {1d, 2d, 3d, 7d},
+ new double[] {5d, 2d, 8d, 1d}
+ };
+ }
+
+ public double[][] getFirstMatrix() {
+ return firstMatrix;
+ }
+
+ public double[][] getSecondMatrix() {
+ return secondMatrix;
+ }
+}
\ No newline at end of file
diff --git a/java-math/src/test/java/com/baeldung/matrices/apache/RealMatrixUnitTest.java b/java-math/src/test/java/com/baeldung/matrices/apache/RealMatrixUnitTest.java
index 05944e7b3a..e7d99fbe3e 100644
--- a/java-math/src/test/java/com/baeldung/matrices/apache/RealMatrixUnitTest.java
+++ b/java-math/src/test/java/com/baeldung/matrices/apache/RealMatrixUnitTest.java
@@ -7,15 +7,10 @@ import org.openjdk.jmh.annotations.*;
import static org.assertj.core.api.Assertions.assertThat;
-@BenchmarkMode(Mode.AverageTime)
-@Fork(value = 2)
-@Warmup(iterations = 5)
-@Measurement(iterations = 10)
-public class RealMatrixUnitTest {
+class RealMatrixUnitTest {
@Test
- @Benchmark
- public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
RealMatrix firstMatrix = new Array2DRowRealMatrix(
new double[][] {
new double[] {1d, 5d},
@@ -43,5 +38,4 @@ public class RealMatrixUnitTest {
assertThat(actual).isEqualTo(expected);
}
-
}
diff --git a/java-math/src/test/java/com/baeldung/matrices/colt/DoubleMatrix2DUnitTest.java b/java-math/src/test/java/com/baeldung/matrices/colt/DoubleMatrix2DUnitTest.java
index fb4a419eb0..da66cd7d61 100644
--- a/java-math/src/test/java/com/baeldung/matrices/colt/DoubleMatrix2DUnitTest.java
+++ b/java-math/src/test/java/com/baeldung/matrices/colt/DoubleMatrix2DUnitTest.java
@@ -8,15 +8,10 @@ import org.openjdk.jmh.annotations.*;
import static org.assertj.core.api.Assertions.assertThat;
-@BenchmarkMode(Mode.AverageTime)
-@Fork(value = 2)
-@Warmup(iterations = 5)
-@Measurement(iterations = 10)
-public class DoubleMatrix2DUnitTest {
+class DoubleMatrix2DUnitTest {
@Test
- @Benchmark
- public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
DoubleFactory2D doubleFactory2D = DoubleFactory2D.dense;
DoubleMatrix2D firstMatrix = doubleFactory2D.make(
@@ -48,4 +43,4 @@ public class DoubleMatrix2DUnitTest {
assertThat(actual).isEqualTo(expected);
}
-}
+}
\ No newline at end of file
diff --git a/java-math/src/test/java/com/baeldung/matrices/ejml/SimpleMatrixUnitTest.java b/java-math/src/test/java/com/baeldung/matrices/ejml/SimpleMatrixUnitTest.java
index b025266a1d..60381ece63 100644
--- a/java-math/src/test/java/com/baeldung/matrices/ejml/SimpleMatrixUnitTest.java
+++ b/java-math/src/test/java/com/baeldung/matrices/ejml/SimpleMatrixUnitTest.java
@@ -6,15 +6,10 @@ import org.openjdk.jmh.annotations.*;
import static org.assertj.core.api.Assertions.assertThat;
-@BenchmarkMode(Mode.AverageTime)
-@Fork(value = 2)
-@Warmup(iterations = 5)
-@Measurement(iterations = 10)
-public class SimpleMatrixUnitTest {
+class SimpleMatrixUnitTest {
@Test
- @Benchmark
- public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
SimpleMatrix firstMatrix = new SimpleMatrix(
new double[][] {
new double[] {1d, 5d},
@@ -43,4 +38,4 @@ public class SimpleMatrixUnitTest {
assertThat(actual).matches(m -> m.isIdentical(expected, 0d));
}
-}
+}
\ No newline at end of file
diff --git a/java-math/src/test/java/com/baeldung/matrices/homemade/HomemadeMatrixUnitTest.java b/java-math/src/test/java/com/baeldung/matrices/homemade/HomemadeMatrixUnitTest.java
index be9e483d5b..d1a062ee79 100644
--- a/java-math/src/test/java/com/baeldung/matrices/homemade/HomemadeMatrixUnitTest.java
+++ b/java-math/src/test/java/com/baeldung/matrices/homemade/HomemadeMatrixUnitTest.java
@@ -5,15 +5,10 @@ import org.openjdk.jmh.annotations.*;
import static org.assertj.core.api.Assertions.assertThat;
-@BenchmarkMode(Mode.AverageTime)
-@Fork(value = 2)
-@Warmup(iterations = 5)
-@Measurement(iterations = 10)
-public class HomemadeMatrixUnitTest {
+class HomemadeMatrixUnitTest {
@Test
- @Benchmark
- public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
double[][] firstMatrix = {
new double[]{1d, 5d},
new double[]{2d, 3d},
@@ -55,4 +50,5 @@ public class HomemadeMatrixUnitTest {
}
return cell;
}
-}
+
+}
\ No newline at end of file
diff --git a/java-math/src/test/java/com/baeldung/matrices/la4j/Basic2DMatrixUnitTest.java b/java-math/src/test/java/com/baeldung/matrices/la4j/Basic2DMatrixUnitTest.java
index afb84ff3db..01731a3dd5 100644
--- a/java-math/src/test/java/com/baeldung/matrices/la4j/Basic2DMatrixUnitTest.java
+++ b/java-math/src/test/java/com/baeldung/matrices/la4j/Basic2DMatrixUnitTest.java
@@ -7,15 +7,10 @@ import org.openjdk.jmh.annotations.*;
import static org.assertj.core.api.Assertions.assertThat;
-@BenchmarkMode(Mode.AverageTime)
-@Fork(value = 2)
-@Warmup(iterations = 5)
-@Measurement(iterations = 10)
-public class Basic2DMatrixUnitTest {
+class Basic2DMatrixUnitTest {
@Test
- @Benchmark
- public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
Matrix firstMatrix = new Basic2DMatrix(
new double[][]{
new double[]{1d, 5d},
@@ -44,4 +39,4 @@ public class Basic2DMatrixUnitTest {
assertThat(actual).isEqualTo(expected);
}
-}
+}
\ No newline at end of file
diff --git a/java-math/src/test/java/com/baeldung/matrices/nd4j/INDArrayUnitTest.java b/java-math/src/test/java/com/baeldung/matrices/nd4j/INDArrayUnitTest.java
index fb3030bccf..72ef60a571 100644
--- a/java-math/src/test/java/com/baeldung/matrices/nd4j/INDArrayUnitTest.java
+++ b/java-math/src/test/java/com/baeldung/matrices/nd4j/INDArrayUnitTest.java
@@ -7,14 +7,10 @@ import org.openjdk.jmh.annotations.*;
import static org.assertj.core.api.Assertions.assertThat;
-@BenchmarkMode(Mode.AverageTime)
-@Fork(value = 2)
-@Warmup(iterations = 5)
-@Measurement(iterations = 10)
-public class INDArrayUnitTest {
+class INDArrayUnitTest {
@Test
- public void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
+ void givenTwoMatrices_whenMultiply_thenMultiplicatedMatrix() {
INDArray firstMatrix = Nd4j.create(
new double[][]{
new double[]{1d, 5d},
@@ -43,4 +39,4 @@ public class INDArrayUnitTest {
assertThat(actual).isEqualTo(expected);
}
-}
+}
\ No newline at end of file
diff --git a/java-numbers-2/README.md b/java-numbers-2/README.md
new file mode 100644
index 0000000000..52ffc822b9
--- /dev/null
+++ b/java-numbers-2/README.md
@@ -0,0 +1,2 @@
+## Relevant Articles
+- [Lossy Conversion in Java](https://www.baeldung.com/java-lossy-conversion)
diff --git a/java-strings-2/README.md b/java-strings-2/README.md
index 55760bfac7..ad0a46fd96 100644
--- a/java-strings-2/README.md
+++ b/java-strings-2/README.md
@@ -23,3 +23,4 @@
- [Java Multi-line String](https://www.baeldung.com/java-multiline-string)
- [Checking If a String Is a Repeated Substring](https://www.baeldung.com/java-repeated-substring)
- [How to Reverse a String in Java](https://www.baeldung.com/java-reverse-string)
+- [String toLowerCase and toUpperCase Methods in Java](https://www.baeldung.com/java-string-convert-case)
diff --git a/jee-kotlin/README.md b/jee-kotlin/README.md
index 7d843af9ea..43dcd992ca 100644
--- a/jee-kotlin/README.md
+++ b/jee-kotlin/README.md
@@ -1 +1,2 @@
### Relevant Articles:
+- [Java EE Application with Kotlin](https://www.baeldung.com/java-ee-kotlin-app)
diff --git a/kotlin-quasar/README.md b/kotlin-quasar/README.md
index b3b84e0446..b3693284f9 100644
--- a/kotlin-quasar/README.md
+++ b/kotlin-quasar/README.md
@@ -1,3 +1,4 @@
### Relevant Articles
- [Introduction to Quasar in Kotlin](https://www.baeldung.com/kotlin-quasar)
+- [Advanced Quasar Usage for Kotlin](https://www.baeldung.com/kotlin-quasar-advanced)
diff --git a/libraries-data-3/README.md b/libraries-data-3/README.md
new file mode 100644
index 0000000000..7f939e7909
--- /dev/null
+++ b/libraries-data-3/README.md
@@ -0,0 +1,5 @@
+### Relevant articles
+- [Parsing YAML with SnakeYAML](http://www.baeldung.com/java-snake-yaml)
+- [Guide to JMapper](https://www.baeldung.com/jmapper)
+- [An Introduction to SuanShu](https://www.baeldung.com/suanshu)
+- [Intro to Derive4J](https://www.baeldung.com/derive4j)
diff --git a/libraries-data-3/log4j.properties b/libraries-data-3/log4j.properties
new file mode 100644
index 0000000000..2173c5d96f
--- /dev/null
+++ b/libraries-data-3/log4j.properties
@@ -0,0 +1 @@
+log4j.rootLogger=INFO, stdout
diff --git a/libraries-data-3/pom.xml b/libraries-data-3/pom.xml
new file mode 100644
index 0000000000..f55701f51c
--- /dev/null
+++ b/libraries-data-3/pom.xml
@@ -0,0 +1,55 @@
+
+
+
+ 4.0.0
+ libraries-data-3
+ libraries-data-3
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ org.yaml
+ snakeyaml
+ ${snakeyaml.version}
+
+
+ com.googlecode.jmapper-framework
+ jmapper-core
+ ${jmapper.version}
+
+
+ com.numericalmethod
+ suanshu
+ ${suanshu.version}
+
+
+ org.derive4j
+ derive4j
+ ${derive4j.version}
+
+
+
+
+
+
+ nm-repo
+ Numerical Method's Maven Repository
+ http://repo.numericalmethod.com/maven/
+ default
+
+
+
+
+ 1.21
+ 1.6.0.1
+ 4.0.0
+ 1.1.0
+
+
\ No newline at end of file
diff --git a/libraries/src/main/java/com/baeldung/derive4j/adt/Either.java b/libraries-data-3/src/main/java/com/baeldung/derive4j/adt/Either.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/derive4j/adt/Either.java
rename to libraries-data-3/src/main/java/com/baeldung/derive4j/adt/Either.java
diff --git a/libraries/src/main/java/com/baeldung/derive4j/lazy/LazyRequest.java b/libraries-data-3/src/main/java/com/baeldung/derive4j/lazy/LazyRequest.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/derive4j/lazy/LazyRequest.java
rename to libraries-data-3/src/main/java/com/baeldung/derive4j/lazy/LazyRequest.java
diff --git a/libraries/src/main/java/com/baeldung/derive4j/pattern/HTTPRequest.java b/libraries-data-3/src/main/java/com/baeldung/derive4j/pattern/HTTPRequest.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/derive4j/pattern/HTTPRequest.java
rename to libraries-data-3/src/main/java/com/baeldung/derive4j/pattern/HTTPRequest.java
diff --git a/libraries/src/main/java/com/baeldung/derive4j/pattern/HTTPResponse.java b/libraries-data-3/src/main/java/com/baeldung/derive4j/pattern/HTTPResponse.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/derive4j/pattern/HTTPResponse.java
rename to libraries-data-3/src/main/java/com/baeldung/derive4j/pattern/HTTPResponse.java
diff --git a/libraries/src/main/java/com/baeldung/derive4j/pattern/HTTPServer.java b/libraries-data-3/src/main/java/com/baeldung/derive4j/pattern/HTTPServer.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/derive4j/pattern/HTTPServer.java
rename to libraries-data-3/src/main/java/com/baeldung/derive4j/pattern/HTTPServer.java
diff --git a/libraries-data/src/main/java/com/baeldung/jmapper/User.java b/libraries-data-3/src/main/java/com/baeldung/jmapper/User.java
similarity index 100%
rename from libraries-data/src/main/java/com/baeldung/jmapper/User.java
rename to libraries-data-3/src/main/java/com/baeldung/jmapper/User.java
diff --git a/libraries-data/src/main/java/com/baeldung/jmapper/UserDto.java b/libraries-data-3/src/main/java/com/baeldung/jmapper/UserDto.java
similarity index 100%
rename from libraries-data/src/main/java/com/baeldung/jmapper/UserDto.java
rename to libraries-data-3/src/main/java/com/baeldung/jmapper/UserDto.java
diff --git a/libraries-data/src/main/java/com/baeldung/jmapper/UserDto1.java b/libraries-data-3/src/main/java/com/baeldung/jmapper/UserDto1.java
similarity index 100%
rename from libraries-data/src/main/java/com/baeldung/jmapper/UserDto1.java
rename to libraries-data-3/src/main/java/com/baeldung/jmapper/UserDto1.java
diff --git a/libraries-data/src/main/java/com/baeldung/jmapper/relational/User.java b/libraries-data-3/src/main/java/com/baeldung/jmapper/relational/User.java
similarity index 100%
rename from libraries-data/src/main/java/com/baeldung/jmapper/relational/User.java
rename to libraries-data-3/src/main/java/com/baeldung/jmapper/relational/User.java
diff --git a/libraries-data/src/main/java/com/baeldung/jmapper/relational/UserDto1.java b/libraries-data-3/src/main/java/com/baeldung/jmapper/relational/UserDto1.java
similarity index 100%
rename from libraries-data/src/main/java/com/baeldung/jmapper/relational/UserDto1.java
rename to libraries-data-3/src/main/java/com/baeldung/jmapper/relational/UserDto1.java
diff --git a/libraries-data/src/main/java/com/baeldung/jmapper/relational/UserDto2.java b/libraries-data-3/src/main/java/com/baeldung/jmapper/relational/UserDto2.java
similarity index 100%
rename from libraries-data/src/main/java/com/baeldung/jmapper/relational/UserDto2.java
rename to libraries-data-3/src/main/java/com/baeldung/jmapper/relational/UserDto2.java
diff --git a/libraries/src/main/java/com/baeldung/snakeyaml/Address.java b/libraries-data-3/src/main/java/com/baeldung/snakeyaml/Address.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/snakeyaml/Address.java
rename to libraries-data-3/src/main/java/com/baeldung/snakeyaml/Address.java
diff --git a/libraries/src/main/java/com/baeldung/snakeyaml/Contact.java b/libraries-data-3/src/main/java/com/baeldung/snakeyaml/Contact.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/snakeyaml/Contact.java
rename to libraries-data-3/src/main/java/com/baeldung/snakeyaml/Contact.java
diff --git a/libraries/src/main/java/com/baeldung/snakeyaml/Customer.java b/libraries-data-3/src/main/java/com/baeldung/snakeyaml/Customer.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/snakeyaml/Customer.java
rename to libraries-data-3/src/main/java/com/baeldung/snakeyaml/Customer.java
diff --git a/libraries/src/main/java/com/baeldung/suanshu/SuanShuMath.java b/libraries-data-3/src/main/java/com/baeldung/suanshu/SuanShuMath.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/suanshu/SuanShuMath.java
rename to libraries-data-3/src/main/java/com/baeldung/suanshu/SuanShuMath.java
diff --git a/libraries-data-3/src/main/resources/user_jmapper.xml b/libraries-data-3/src/main/resources/user_jmapper.xml
new file mode 100644
index 0000000000..f007de9f0a
--- /dev/null
+++ b/libraries-data-3/src/main/resources/user_jmapper.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libraries-data-3/src/main/resources/user_jmapper1.xml b/libraries-data-3/src/main/resources/user_jmapper1.xml
new file mode 100644
index 0000000000..abcfd77e1c
--- /dev/null
+++ b/libraries-data-3/src/main/resources/user_jmapper1.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/libraries-data-3/src/main/resources/user_jmapper2.xml b/libraries-data-3/src/main/resources/user_jmapper2.xml
new file mode 100644
index 0000000000..1e708e14bf
--- /dev/null
+++ b/libraries-data-3/src/main/resources/user_jmapper2.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libraries/src/test/java/com/baeldung/derive4j/adt/EitherUnitTest.java b/libraries-data-3/src/test/java/com/baeldung/derive4j/adt/EitherUnitTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/derive4j/adt/EitherUnitTest.java
rename to libraries-data-3/src/test/java/com/baeldung/derive4j/adt/EitherUnitTest.java
diff --git a/libraries/src/test/java/com/baeldung/derive4j/lazy/LazyRequestUnitTest.java b/libraries-data-3/src/test/java/com/baeldung/derive4j/lazy/LazyRequestUnitTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/derive4j/lazy/LazyRequestUnitTest.java
rename to libraries-data-3/src/test/java/com/baeldung/derive4j/lazy/LazyRequestUnitTest.java
diff --git a/libraries/src/test/java/com/baeldung/derive4j/pattern/HTTPRequestUnitTest.java b/libraries-data-3/src/test/java/com/baeldung/derive4j/pattern/HTTPRequestUnitTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/derive4j/pattern/HTTPRequestUnitTest.java
rename to libraries-data-3/src/test/java/com/baeldung/derive4j/pattern/HTTPRequestUnitTest.java
diff --git a/libraries-data/src/test/java/com/baeldung/jmapper/JMapperIntegrationTest.java b/libraries-data-3/src/test/java/com/baeldung/jmapper/JMapperIntegrationTest.java
similarity index 100%
rename from libraries-data/src/test/java/com/baeldung/jmapper/JMapperIntegrationTest.java
rename to libraries-data-3/src/test/java/com/baeldung/jmapper/JMapperIntegrationTest.java
diff --git a/libraries-data/src/test/java/com/baeldung/jmapper/JMapperRelationalIntegrationTest.java b/libraries-data-3/src/test/java/com/baeldung/jmapper/JMapperRelationalIntegrationTest.java
similarity index 100%
rename from libraries-data/src/test/java/com/baeldung/jmapper/JMapperRelationalIntegrationTest.java
rename to libraries-data-3/src/test/java/com/baeldung/jmapper/JMapperRelationalIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/snakeyaml/JavaToYAMLSerializationUnitTest.java b/libraries-data-3/src/test/java/com/baeldung/snakeyaml/JavaToYAMLSerializationUnitTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/snakeyaml/JavaToYAMLSerializationUnitTest.java
rename to libraries-data-3/src/test/java/com/baeldung/snakeyaml/JavaToYAMLSerializationUnitTest.java
diff --git a/libraries/src/test/java/com/baeldung/snakeyaml/YAMLToJavaDeserialisationUnitTest.java b/libraries-data-3/src/test/java/com/baeldung/snakeyaml/YAMLToJavaDeserialisationUnitTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/snakeyaml/YAMLToJavaDeserialisationUnitTest.java
rename to libraries-data-3/src/test/java/com/baeldung/snakeyaml/YAMLToJavaDeserialisationUnitTest.java
diff --git a/libraries-data-3/src/test/resources/yaml/customer.yaml b/libraries-data-3/src/test/resources/yaml/customer.yaml
new file mode 100644
index 0000000000..aa76141c7d
--- /dev/null
+++ b/libraries-data-3/src/test/resources/yaml/customer.yaml
@@ -0,0 +1,3 @@
+firstName: "John"
+lastName: "Doe"
+age: 20
\ No newline at end of file
diff --git a/libraries-data-3/src/test/resources/yaml/customer_with_contact_details.yaml b/libraries-data-3/src/test/resources/yaml/customer_with_contact_details.yaml
new file mode 100644
index 0000000000..34563cbd21
--- /dev/null
+++ b/libraries-data-3/src/test/resources/yaml/customer_with_contact_details.yaml
@@ -0,0 +1,7 @@
+firstName: "John"
+lastName: "Doe"
+age: 31
+contactDetails:
+ - { type: "mobile", number: 123456789}
+ - { type: "landline", number: 456786868}
+
\ No newline at end of file
diff --git a/libraries-data-3/src/test/resources/yaml/customer_with_contact_details_and_address.yaml b/libraries-data-3/src/test/resources/yaml/customer_with_contact_details_and_address.yaml
new file mode 100644
index 0000000000..664afe8594
--- /dev/null
+++ b/libraries-data-3/src/test/resources/yaml/customer_with_contact_details_and_address.yaml
@@ -0,0 +1,13 @@
+firstName: "John"
+lastName: "Doe"
+age: 31
+contactDetails:
+ - type: "mobile"
+ number: 123456789
+ - type: "landline"
+ number: 456786868
+homeAddress:
+ line: "Xyz, DEF Street"
+ city: "City Y"
+ state: "State Y"
+ zip: 345657
diff --git a/libraries-data-3/src/test/resources/yaml/customer_with_contact_details_and_tags.yaml b/libraries-data-3/src/test/resources/yaml/customer_with_contact_details_and_tags.yaml
new file mode 100644
index 0000000000..145da256d9
--- /dev/null
+++ b/libraries-data-3/src/test/resources/yaml/customer_with_contact_details_and_tags.yaml
@@ -0,0 +1,6 @@
+firstName: "John"
+lastName: "Doe"
+age: 31
+contactDetails:
+ - !contact { type: "mobile", number: 123456789}
+ - !contact { type: "landline", number: 456786868}
diff --git a/libraries-data-3/src/test/resources/yaml/customer_with_type.yaml b/libraries-data-3/src/test/resources/yaml/customer_with_type.yaml
new file mode 100644
index 0000000000..6e13c26cea
--- /dev/null
+++ b/libraries-data-3/src/test/resources/yaml/customer_with_type.yaml
@@ -0,0 +1,4 @@
+!!com.baeldung.snakeyaml.Customer
+firstName: "John"
+lastName: "Doe"
+age: 20
\ No newline at end of file
diff --git a/libraries-data-3/src/test/resources/yaml/customers.yaml b/libraries-data-3/src/test/resources/yaml/customers.yaml
new file mode 100644
index 0000000000..23b9039c2e
--- /dev/null
+++ b/libraries-data-3/src/test/resources/yaml/customers.yaml
@@ -0,0 +1,8 @@
+---
+firstName: "John"
+lastName: "Doe"
+age: 20
+---
+firstName: "Jack"
+lastName: "Jones"
+age: 25
\ No newline at end of file
diff --git a/libraries-data/README.md b/libraries-data/README.md
index 1ad7e94a1f..92c546c258 100644
--- a/libraries-data/README.md
+++ b/libraries-data/README.md
@@ -9,7 +9,6 @@
- [Introduction to JCache](http://www.baeldung.com/jcache)
- [A Guide to Apache Ignite](http://www.baeldung.com/apache-ignite)
- [Apache Ignite with Spring Data](http://www.baeldung.com/apache-ignite-spring-data)
-- [Guide to JMapper](https://www.baeldung.com/jmapper)
- [A Guide to Apache Crunch](https://www.baeldung.com/apache-crunch)
- [Intro to Apache Storm](https://www.baeldung.com/apache-storm)
- [Guide to Ebean ORM](https://www.baeldung.com/ebean-orm)
diff --git a/libraries-data/pom.xml b/libraries-data/pom.xml
index 88dcceafaa..e255236480 100644
--- a/libraries-data/pom.xml
+++ b/libraries-data/pom.xml
@@ -141,12 +141,7 @@
hazelcast
${hazelcast.version}
-
-
- com.googlecode.jmapper-framework
- jmapper-core
- ${jmapper.version}
-
+
org.apache.crunch
@@ -460,7 +455,6 @@
5.0.2
5.0.0-release
5.0.4
- 1.6.0.1
0.15.0
2.2.0
11.22.4
diff --git a/libraries-http/README.md b/libraries-http/README.md
index dd8c6a5f67..d5eaed0736 100644
--- a/libraries-http/README.md
+++ b/libraries-http/README.md
@@ -5,3 +5,7 @@
- [A Guide to Google-Http-Client](http://www.baeldung.com/google-http-client)
- [Asynchronous HTTP with async-http-client in Java](http://www.baeldung.com/async-http-client)
- [WebSockets with AsyncHttpClient](http://www.baeldung.com/async-http-client-websockets)
+- [Integrating Retrofit with RxJava](http://www.baeldung.com/retrofit-rxjava)
+- [Introduction to Retrofit](http://www.baeldung.com/retrofit)
+- [A Guide to Unirest](http://www.baeldung.com/unirest)
+- [Creating REST Microservices with Javalin](http://www.baeldung.com/javalin-rest-microservices)
\ No newline at end of file
diff --git a/libraries-http/pom.xml b/libraries-http/pom.xml
index 6006a93aef..44280d848c 100644
--- a/libraries-http/pom.xml
+++ b/libraries-http/pom.xml
@@ -44,6 +44,23 @@
${googleclient.version}
+
+
+ com.squareup.retrofit2
+ retrofit
+ ${retrofit.version}
+
+
+ com.squareup.retrofit2
+ converter-gson
+ ${retrofit.version}
+
+
+ com.squareup.retrofit2
+ adapter-rxjava
+ ${retrofit.version}
+
+
org.asynchttpclient
@@ -69,13 +86,52 @@
${com.squareup.okhttp3.version}
test
+
+
+ com.mashape.unirest
+ unirest-java
+ ${unirest.version}
+
+
+
+ io.javalin
+ javalin
+ ${javalin.version}
+
+
+ com.squareup.okhttp3
+ logging-interceptor
+ ${logging-interceptor.version}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+ org.apache.httpcomponents
+ httpclient
+ ${httpclient.version}
+
+
+ commons-logging
+ commons-logging
+
+
+
+ 4.5.3
+ 2.9.8
3.6.2
3.14.2
1.23.0
2.2.0
+ 2.3.0
+ 1.4.9
+ 1.6.0
+ 3.9.0
diff --git a/libraries/src/main/java/com/baeldung/javalin/JavalinApp.java b/libraries-http/src/main/java/com/baeldung/javalin/JavalinApp.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/javalin/JavalinApp.java
rename to libraries-http/src/main/java/com/baeldung/javalin/JavalinApp.java
diff --git a/libraries/src/main/java/com/baeldung/javalin/User/User.java b/libraries-http/src/main/java/com/baeldung/javalin/User/User.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/javalin/User/User.java
rename to libraries-http/src/main/java/com/baeldung/javalin/User/User.java
diff --git a/libraries/src/main/java/com/baeldung/javalin/User/UserController.java b/libraries-http/src/main/java/com/baeldung/javalin/User/UserController.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/javalin/User/UserController.java
rename to libraries-http/src/main/java/com/baeldung/javalin/User/UserController.java
diff --git a/libraries/src/main/java/com/baeldung/javalin/User/UserDao.java b/libraries-http/src/main/java/com/baeldung/javalin/User/UserDao.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/javalin/User/UserDao.java
rename to libraries-http/src/main/java/com/baeldung/javalin/User/UserDao.java
diff --git a/libraries/src/main/java/com/baeldung/retrofit/basic/GitHubBasicApi.java b/libraries-http/src/main/java/com/baeldung/retrofit/basic/GitHubBasicApi.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofit/basic/GitHubBasicApi.java
rename to libraries-http/src/main/java/com/baeldung/retrofit/basic/GitHubBasicApi.java
diff --git a/libraries/src/main/java/com/baeldung/retrofit/basic/GitHubBasicApp.java b/libraries-http/src/main/java/com/baeldung/retrofit/basic/GitHubBasicApp.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofit/basic/GitHubBasicApp.java
rename to libraries-http/src/main/java/com/baeldung/retrofit/basic/GitHubBasicApp.java
diff --git a/libraries/src/main/java/com/baeldung/retrofit/basic/GitHubBasicService.java b/libraries-http/src/main/java/com/baeldung/retrofit/basic/GitHubBasicService.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofit/basic/GitHubBasicService.java
rename to libraries-http/src/main/java/com/baeldung/retrofit/basic/GitHubBasicService.java
diff --git a/libraries/src/main/java/com/baeldung/retrofit/models/Contributor.java b/libraries-http/src/main/java/com/baeldung/retrofit/models/Contributor.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofit/models/Contributor.java
rename to libraries-http/src/main/java/com/baeldung/retrofit/models/Contributor.java
diff --git a/libraries/src/main/java/com/baeldung/retrofit/models/Repository.java b/libraries-http/src/main/java/com/baeldung/retrofit/models/Repository.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofit/models/Repository.java
rename to libraries-http/src/main/java/com/baeldung/retrofit/models/Repository.java
diff --git a/libraries/src/main/java/com/baeldung/retrofit/rx/GitHubRxApi.java b/libraries-http/src/main/java/com/baeldung/retrofit/rx/GitHubRxApi.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofit/rx/GitHubRxApi.java
rename to libraries-http/src/main/java/com/baeldung/retrofit/rx/GitHubRxApi.java
diff --git a/libraries/src/main/java/com/baeldung/retrofit/rx/GitHubRxApp.java b/libraries-http/src/main/java/com/baeldung/retrofit/rx/GitHubRxApp.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofit/rx/GitHubRxApp.java
rename to libraries-http/src/main/java/com/baeldung/retrofit/rx/GitHubRxApp.java
diff --git a/libraries/src/main/java/com/baeldung/retrofit/rx/GitHubRxService.java b/libraries-http/src/main/java/com/baeldung/retrofit/rx/GitHubRxService.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofit/rx/GitHubRxService.java
rename to libraries-http/src/main/java/com/baeldung/retrofit/rx/GitHubRxService.java
diff --git a/libraries/src/main/java/com/baeldung/retrofitguide/GitHubServiceGenerator.java b/libraries-http/src/main/java/com/baeldung/retrofitguide/GitHubServiceGenerator.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofitguide/GitHubServiceGenerator.java
rename to libraries-http/src/main/java/com/baeldung/retrofitguide/GitHubServiceGenerator.java
diff --git a/libraries/src/main/java/com/baeldung/retrofitguide/Main.java b/libraries-http/src/main/java/com/baeldung/retrofitguide/Main.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofitguide/Main.java
rename to libraries-http/src/main/java/com/baeldung/retrofitguide/Main.java
diff --git a/libraries/src/main/java/com/baeldung/retrofitguide/User.java b/libraries-http/src/main/java/com/baeldung/retrofitguide/User.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofitguide/User.java
rename to libraries-http/src/main/java/com/baeldung/retrofitguide/User.java
diff --git a/libraries/src/main/java/com/baeldung/retrofitguide/UserService.java b/libraries-http/src/main/java/com/baeldung/retrofitguide/UserService.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/retrofitguide/UserService.java
rename to libraries-http/src/main/java/com/baeldung/retrofitguide/UserService.java
diff --git a/libraries/src/test/java/com/baeldung/retrofit/basic/GitHubBasicApiLiveTest.java b/libraries-http/src/test/java/com/baeldung/retrofit/basic/GitHubBasicApiLiveTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/retrofit/basic/GitHubBasicApiLiveTest.java
rename to libraries-http/src/test/java/com/baeldung/retrofit/basic/GitHubBasicApiLiveTest.java
diff --git a/libraries/src/test/java/com/baeldung/retrofit/rx/GitHubRxLiveTest.java b/libraries-http/src/test/java/com/baeldung/retrofit/rx/GitHubRxLiveTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/retrofit/rx/GitHubRxLiveTest.java
rename to libraries-http/src/test/java/com/baeldung/retrofit/rx/GitHubRxLiveTest.java
diff --git a/libraries/src/test/java/com/baeldung/unirest/Article.java b/libraries-http/src/test/java/com/baeldung/unirest/Article.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/unirest/Article.java
rename to libraries-http/src/test/java/com/baeldung/unirest/Article.java
diff --git a/libraries/src/test/java/com/baeldung/unirest/HttpClientLiveTest.java b/libraries-http/src/test/java/com/baeldung/unirest/HttpClientLiveTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/unirest/HttpClientLiveTest.java
rename to libraries-http/src/test/java/com/baeldung/unirest/HttpClientLiveTest.java
diff --git a/libraries-security/README.md b/libraries-security/README.md
index b9bbf11cdf..96f3fcdac6 100644
--- a/libraries-security/README.md
+++ b/libraries-security/README.md
@@ -3,3 +3,5 @@
- [Guide to ScribeJava](https://www.baeldung.com/scribejava)
- [Guide to Passay](https://www.baeldung.com/java-passay)
- [Guide to Google Tink](https://www.baeldung.com/google-tink)
+- [Introduction to BouncyCastle with Java](https://www.baeldung.com/java-bouncy-castle)
+- [Intro to Jasypt](https://www.baeldung.com/jasypt)
diff --git a/libraries-security/pom.xml b/libraries-security/pom.xml
index 17d57fe203..eb16575be8 100644
--- a/libraries-security/pom.xml
+++ b/libraries-security/pom.xml
@@ -25,6 +25,11 @@
spring-security-oauth2
${spring-security-oauth2.version}
+
+ org.springframework
+ spring-web
+ ${spring.version}
+
com.github.scribejava
@@ -37,7 +42,16 @@
tink
${tink.version}
-
+
+ org.bouncycastle
+ bcprov-jdk15on
+ ${bouncycastle.version}
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ ${bouncycastle.version}
+
junit
junit
@@ -54,6 +68,11 @@
cryptacular
${cryptacular.version}
+
+ org.jasypt
+ jasypt
+ ${jasypt.version}
+
@@ -63,5 +82,8 @@
1.3.1
1.2.2
1.2.2
+ 1.9.2
+ 1.58
+ 4.3.8.RELEASE
diff --git a/libraries/src/main/java/com/baeldung/bouncycastle/BouncyCastleCrypto.java b/libraries-security/src/main/java/com/baeldung/bouncycastle/BouncyCastleCrypto.java
similarity index 98%
rename from libraries/src/main/java/com/baeldung/bouncycastle/BouncyCastleCrypto.java
rename to libraries-security/src/main/java/com/baeldung/bouncycastle/BouncyCastleCrypto.java
index d7040407db..e351552c78 100644
--- a/libraries/src/main/java/com/baeldung/bouncycastle/BouncyCastleCrypto.java
+++ b/libraries-security/src/main/java/com/baeldung/bouncycastle/BouncyCastleCrypto.java
@@ -1,105 +1,105 @@
-package com.baeldung.bouncycastle;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.security.PrivateKey;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.cms.ContentInfo;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.jcajce.JcaCertStore;
-import org.bouncycastle.cms.CMSAlgorithm;
-import org.bouncycastle.cms.CMSEnvelopedData;
-import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
-import org.bouncycastle.cms.CMSException;
-import org.bouncycastle.cms.CMSProcessableByteArray;
-import org.bouncycastle.cms.CMSSignedData;
-import org.bouncycastle.cms.CMSSignedDataGenerator;
-import org.bouncycastle.cms.CMSTypedData;
-import org.bouncycastle.cms.KeyTransRecipientInformation;
-import org.bouncycastle.cms.RecipientInformation;
-import org.bouncycastle.cms.SignerInformation;
-import org.bouncycastle.cms.SignerInformationStore;
-import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
-import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
-import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
-import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
-import org.bouncycastle.cms.jcajce.JceKeyTransRecipient;
-import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.OutputEncryptor;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
-import org.bouncycastle.util.Store;
-
-public class BouncyCastleCrypto {
-
- public static byte[] signData(byte[] data, final X509Certificate signingCertificate, final PrivateKey signingKey) throws CertificateEncodingException, OperatorCreationException, CMSException, IOException {
- byte[] signedMessage = null;
- List certList = new ArrayList();
- CMSTypedData cmsData = new CMSProcessableByteArray(data);
- certList.add(signingCertificate);
- Store certs = new JcaCertStore(certList);
- CMSSignedDataGenerator cmsGenerator = new CMSSignedDataGenerator();
- ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withRSA").build(signingKey);
- cmsGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(contentSigner, signingCertificate));
- cmsGenerator.addCertificates(certs);
- CMSSignedData cms = cmsGenerator.generate(cmsData, true);
- signedMessage = cms.getEncoded();
- return signedMessage;
- }
-
- public static boolean verifSignData(final byte[] signedData) throws CMSException, IOException, OperatorCreationException, CertificateException {
- ByteArrayInputStream bIn = new ByteArrayInputStream(signedData);
- ASN1InputStream aIn = new ASN1InputStream(bIn);
- CMSSignedData s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
- aIn.close();
- bIn.close();
- Store certs = s.getCertificates();
- SignerInformationStore signers = s.getSignerInfos();
- Collection c = signers.getSigners();
- SignerInformation signer = c.iterator().next();
- Collection certCollection = certs.getMatches(signer.getSID());
- Iterator certIt = certCollection.iterator();
- X509CertificateHolder certHolder = certIt.next();
- boolean verifResult = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certHolder));
- if (!verifResult) {
- return false;
- }
- return true;
- }
-
- public static byte[] encryptData(final byte[] data, X509Certificate encryptionCertificate) throws CertificateEncodingException, CMSException, IOException {
- byte[] encryptedData = null;
- if (null != data && null != encryptionCertificate) {
- CMSEnvelopedDataGenerator cmsEnvelopedDataGenerator = new CMSEnvelopedDataGenerator();
- JceKeyTransRecipientInfoGenerator jceKey = new JceKeyTransRecipientInfoGenerator(encryptionCertificate);
- cmsEnvelopedDataGenerator.addRecipientInfoGenerator(jceKey);
- CMSTypedData msg = new CMSProcessableByteArray(data);
- OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider("BC").build();
- CMSEnvelopedData cmsEnvelopedData = cmsEnvelopedDataGenerator.generate(msg, encryptor);
- encryptedData = cmsEnvelopedData.getEncoded();
- }
- return encryptedData;
- }
-
- public static byte[] decryptData(final byte[] encryptedData, final PrivateKey decryptionKey) throws CMSException {
- byte[] decryptedData = null;
- if (null != encryptedData && null != decryptionKey) {
- CMSEnvelopedData envelopedData = new CMSEnvelopedData(encryptedData);
- Collection recip = envelopedData.getRecipientInfos().getRecipients();
- KeyTransRecipientInformation recipientInfo = (KeyTransRecipientInformation) recip.iterator().next();
- JceKeyTransRecipient recipient = new JceKeyTransEnvelopedRecipient(decryptionKey);
- decryptedData = recipientInfo.getContent(recipient);
- }
- return decryptedData;
- }
-}
+package com.baeldung.bouncycastle;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.cms.ContentInfo;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaCertStore;
+import org.bouncycastle.cms.CMSAlgorithm;
+import org.bouncycastle.cms.CMSEnvelopedData;
+import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSSignedDataGenerator;
+import org.bouncycastle.cms.CMSTypedData;
+import org.bouncycastle.cms.KeyTransRecipientInformation;
+import org.bouncycastle.cms.RecipientInformation;
+import org.bouncycastle.cms.SignerInformation;
+import org.bouncycastle.cms.SignerInformationStore;
+import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.bouncycastle.cms.jcajce.JceKeyTransRecipient;
+import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.OutputEncryptor;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.bouncycastle.util.Store;
+
+public class BouncyCastleCrypto {
+
+ public static byte[] signData(byte[] data, final X509Certificate signingCertificate, final PrivateKey signingKey) throws CertificateEncodingException, OperatorCreationException, CMSException, IOException {
+ byte[] signedMessage = null;
+ List certList = new ArrayList();
+ CMSTypedData cmsData = new CMSProcessableByteArray(data);
+ certList.add(signingCertificate);
+ Store certs = new JcaCertStore(certList);
+ CMSSignedDataGenerator cmsGenerator = new CMSSignedDataGenerator();
+ ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withRSA").build(signingKey);
+ cmsGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(contentSigner, signingCertificate));
+ cmsGenerator.addCertificates(certs);
+ CMSSignedData cms = cmsGenerator.generate(cmsData, true);
+ signedMessage = cms.getEncoded();
+ return signedMessage;
+ }
+
+ public static boolean verifSignData(final byte[] signedData) throws CMSException, IOException, OperatorCreationException, CertificateException {
+ ByteArrayInputStream bIn = new ByteArrayInputStream(signedData);
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+ CMSSignedData s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+ aIn.close();
+ bIn.close();
+ Store certs = s.getCertificates();
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ SignerInformation signer = c.iterator().next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder certHolder = certIt.next();
+ boolean verifResult = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certHolder));
+ if (!verifResult) {
+ return false;
+ }
+ return true;
+ }
+
+ public static byte[] encryptData(final byte[] data, X509Certificate encryptionCertificate) throws CertificateEncodingException, CMSException, IOException {
+ byte[] encryptedData = null;
+ if (null != data && null != encryptionCertificate) {
+ CMSEnvelopedDataGenerator cmsEnvelopedDataGenerator = new CMSEnvelopedDataGenerator();
+ JceKeyTransRecipientInfoGenerator jceKey = new JceKeyTransRecipientInfoGenerator(encryptionCertificate);
+ cmsEnvelopedDataGenerator.addRecipientInfoGenerator(jceKey);
+ CMSTypedData msg = new CMSProcessableByteArray(data);
+ OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider("BC").build();
+ CMSEnvelopedData cmsEnvelopedData = cmsEnvelopedDataGenerator.generate(msg, encryptor);
+ encryptedData = cmsEnvelopedData.getEncoded();
+ }
+ return encryptedData;
+ }
+
+ public static byte[] decryptData(final byte[] encryptedData, final PrivateKey decryptionKey) throws CMSException {
+ byte[] decryptedData = null;
+ if (null != encryptedData && null != decryptionKey) {
+ CMSEnvelopedData envelopedData = new CMSEnvelopedData(encryptedData);
+ Collection recip = envelopedData.getRecipientInfos().getRecipients();
+ KeyTransRecipientInformation recipientInfo = (KeyTransRecipientInformation) recip.iterator().next();
+ JceKeyTransRecipient recipient = new JceKeyTransEnvelopedRecipient(decryptionKey);
+ decryptedData = recipientInfo.getContent(recipient);
+ }
+ return decryptedData;
+ }
+}
diff --git a/libraries-security/src/main/resources/Baeldung.cer b/libraries-security/src/main/resources/Baeldung.cer
new file mode 100644
index 0000000000..72d0918424
--- /dev/null
+++ b/libraries-security/src/main/resources/Baeldung.cer
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAiagAwIBAgIJAPvd1gx14C3CMA0GCSqGSIb3DQEBBQUAMEcxCzAJBgNV
+BAYTAk1BMRAwDgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREw
+DwYDVQQDEwhCYWVsZHVuZzAeFw0xNzEwMTIxMDQzMTRaFw0yNzEwMTMxMDQzMTRa
+MEcxCzAJBgNVBAYTAk1BMRAwDgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNh
+YmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAMyi5GmOeN4QaH/CP5gSOyHX8znb5TDHWV8wc+ZT7kNU8zt5tGMh
+jozK6hax155/6tOsBDR0rSYBhL+Dm/+uCVS7qOlRHhf6cNGtzGF1gnNJB2WjI8oM
+AYm24xpLj1WphKUwKrn3nTMPnQup5OoNAMYl99flANrRYVjjxrLQvDZDUio6Iujr
+CZ2TtXGM0g/gP++28KT7g1KlUui3xtB0u33wx7UN8Fix3JmjOaPHGwxGpwP3VGSj
+fs8cuhqVwRQaZpCOoHU/P8wpXKw80sSdhz+SRueMPtVYqK0CiLL5/O0h0Y3le4IV
+whgg3KG1iTGOWn60UMFn1EYmQ18k5Nsma6UCAwEAAaMtMCswCQYDVR0TBAIwADAR
+BglghkgBhvhCAQEEBAMCBPAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEBBQUAA4IB
+AQC8DDBmJ3p4xytxBiE0s4p1715WT6Dm/QJHp0XC0hkSoyZKDh+XVmrzm+J3SiW1
+vpswb5hLgPo040YX9jnDmgOD+TpleTuKHxZRYj92UYWmdjkWLVtFMcvOh+gxBiAP
+pHIqZsqo8lfcyAuh8Jx834IXbknfCUtERDLG/rU9P/3XJhrM2GC5qPQznrW4EYhU
+CGPyIJXmvATMVvXMWCtfogAL+n42vjYXQXZoAWomHhLHoNbSJUErnNdWDOh4WoJt
+XJCxA6U5LSBplqb3wB2hUTqw+0admKltvmy+KA1PD7OxoGiY7V544zeGqJam1qxU
+ia7y5BL6uOa/4ShSV8pcJDYz
+-----END CERTIFICATE-----
diff --git a/libraries/src/test/java/com/baeldung/bouncycastle/BouncyCastleLiveTest.java b/libraries-security/src/test/java/com/baeldung/bouncycastle/BouncyCastleLiveTest.java
similarity index 97%
rename from libraries/src/test/java/com/baeldung/bouncycastle/BouncyCastleLiveTest.java
rename to libraries-security/src/test/java/com/baeldung/bouncycastle/BouncyCastleLiveTest.java
index 009119d97a..37e8e5f6ba 100644
--- a/libraries/src/test/java/com/baeldung/bouncycastle/BouncyCastleLiveTest.java
+++ b/libraries-security/src/test/java/com/baeldung/bouncycastle/BouncyCastleLiveTest.java
@@ -1,50 +1,50 @@
-package com.baeldung.bouncycastle;
-
-import static org.junit.Assert.assertTrue;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.PrivateKey;
-import java.security.Security;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-
-import org.bouncycastle.cms.CMSException;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.junit.Test;
-
-public class BouncyCastleLiveTest {
-
- String certificatePath = "src/main/resources/Baeldung.cer";
- String privateKeyPath = "src/main/resources/Baeldung.p12";
- char[] p12Password = "password".toCharArray();
- char[] keyPassword = "password".toCharArray();
-
- @Test
- public void givenCryptographicResource_whenOperationSuccess_returnTrue() throws CertificateException, NoSuchProviderException, NoSuchAlgorithmException, IOException, KeyStoreException, UnrecoverableKeyException, CMSException, OperatorCreationException {
- Security.addProvider(new BouncyCastleProvider());
-
- CertificateFactory certFactory = CertificateFactory.getInstance("X.509", "BC");
- X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(new FileInputStream(certificatePath));
- KeyStore keystore = KeyStore.getInstance("PKCS12");
- keystore.load(new FileInputStream(privateKeyPath), p12Password);
- PrivateKey privateKey = (PrivateKey) keystore.getKey("baeldung", keyPassword);
- String secretMessage = "My password is 123456Seven";
- System.out.println("Original Message : " + secretMessage);
- byte[] stringToEncrypt = secretMessage.getBytes();
- byte[] encryptedData = BouncyCastleCrypto.encryptData(stringToEncrypt, certificate);
- byte[] rawData = BouncyCastleCrypto.decryptData(encryptedData, privateKey);
- String decryptedMessage = new String(rawData);
- assertTrue(decryptedMessage.equals(secretMessage));
- byte[] signedData = BouncyCastleCrypto.signData(rawData, certificate, privateKey);
- Boolean check = BouncyCastleCrypto.verifSignData(signedData);
- assertTrue(check);
- }
-}
+package com.baeldung.bouncycastle;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.junit.Test;
+
+public class BouncyCastleLiveTest {
+
+ String certificatePath = "src/main/resources/Baeldung.cer";
+ String privateKeyPath = "src/main/resources/Baeldung.p12";
+ char[] p12Password = "password".toCharArray();
+ char[] keyPassword = "password".toCharArray();
+
+ @Test
+ public void givenCryptographicResource_whenOperationSuccess_returnTrue() throws CertificateException, NoSuchProviderException, NoSuchAlgorithmException, IOException, KeyStoreException, UnrecoverableKeyException, CMSException, OperatorCreationException {
+ Security.addProvider(new BouncyCastleProvider());
+
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509", "BC");
+ X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(new FileInputStream(certificatePath));
+ KeyStore keystore = KeyStore.getInstance("PKCS12");
+ keystore.load(new FileInputStream(privateKeyPath), p12Password);
+ PrivateKey privateKey = (PrivateKey) keystore.getKey("baeldung", keyPassword);
+ String secretMessage = "My password is 123456Seven";
+ System.out.println("Original Message : " + secretMessage);
+ byte[] stringToEncrypt = secretMessage.getBytes();
+ byte[] encryptedData = BouncyCastleCrypto.encryptData(stringToEncrypt, certificate);
+ byte[] rawData = BouncyCastleCrypto.decryptData(encryptedData, privateKey);
+ String decryptedMessage = new String(rawData);
+ assertTrue(decryptedMessage.equals(secretMessage));
+ byte[] signedData = BouncyCastleCrypto.signData(rawData, certificate, privateKey);
+ Boolean check = BouncyCastleCrypto.verifSignData(signedData);
+ assertTrue(check);
+ }
+}
diff --git a/libraries/src/test/java/com/baeldung/jasypt/JasyptUnitTest.java b/libraries-security/src/test/java/com/baeldung/jasypt/JasyptUnitTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/jasypt/JasyptUnitTest.java
rename to libraries-security/src/test/java/com/baeldung/jasypt/JasyptUnitTest.java
diff --git a/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java b/libraries-security/src/test/java/com/baeldung/tink/TinkLiveTest.java
similarity index 96%
rename from libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java
rename to libraries-security/src/test/java/com/baeldung/tink/TinkLiveTest.java
index b98c698016..c4bd487457 100644
--- a/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java
+++ b/libraries-security/src/test/java/com/baeldung/tink/TinkLiveTest.java
@@ -18,7 +18,9 @@ import org.junit.Test;
import java.security.GeneralSecurityException;
-public class TinkUnitTest {
+public class TinkLiveTest {
+
+ //need to download policy files and put them into ${java.home}/jre/lib/security/
private static final String PLAINTEXT = "BAELDUNG";
private static final String DATA = "TINK";
diff --git a/libraries-testing/README.md b/libraries-testing/README.md
new file mode 100644
index 0000000000..6b25a3b875
--- /dev/null
+++ b/libraries-testing/README.md
@@ -0,0 +1,8 @@
+### Relevant articles
+
+- [Introduction to Serenity BDD](http://www.baeldung.com/serenity-bdd)
+- [Introduction to JSONassert](http://www.baeldung.com/jsonassert)
+- [Serenity BDD and Screenplay](http://www.baeldung.com/serenity-screenplay)
+- [Serenity BDD with Spring and JBehave](http://www.baeldung.com/serenity-spring-jbehave)
+- [Introduction to Awaitlity](http://www.baeldung.com/awaitlity-testing)
+- [Introduction to Hoverfly in Java](http://www.baeldung.com/hoverfly)
\ No newline at end of file
diff --git a/libraries-testing/log4j.properties b/libraries-testing/log4j.properties
new file mode 100644
index 0000000000..ed367509d1
--- /dev/null
+++ b/libraries-testing/log4j.properties
@@ -0,0 +1,5 @@
+log4j.rootLogger=INFO, stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
\ No newline at end of file
diff --git a/libraries-testing/pom.xml b/libraries-testing/pom.xml
new file mode 100644
index 0000000000..8f7a27bbfa
--- /dev/null
+++ b/libraries-testing/pom.xml
@@ -0,0 +1,170 @@
+
+
+
+ 4.0.0
+ libraries-testing
+ libraries-testing
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ net.serenity-bdd
+ serenity-core
+ ${serenity.version}
+ test
+
+
+ org.asciidoctor
+ asciidoctorj
+
+
+
+
+ net.serenity-bdd
+ serenity-junit
+ ${serenity.version}
+ test
+
+
+ net.serenity-bdd
+ serenity-jbehave
+ ${serenity.jbehave.version}
+ test
+
+
+ net.serenity-bdd
+ serenity-rest-assured
+ ${serenity.version}
+ test
+
+
+ net.serenity-bdd
+ serenity-jira-requirements-provider
+ ${serenity.jira.version}
+ test
+
+
+ net.serenity-bdd
+ serenity-spring
+ ${serenity.version}
+ test
+
+
+ org.springframework
+ spring-test
+
+
+
+
+ net.serenity-bdd
+ serenity-screenplay
+ ${serenity.version}
+ test
+
+
+ net.serenity-bdd
+ serenity-screenplay-webdriver
+ ${serenity.version}
+ test
+
+
+ org.skyscreamer
+ jsonassert
+ ${jsonassert.version}
+
+
+ org.awaitility
+ awaitility
+ ${awaitility.version}
+ test
+
+
+ org.awaitility
+ awaitility-proxy
+ ${awaitility.version}
+ test
+
+
+ io.specto
+ hoverfly-java
+ ${hoverfly-java.version}
+
+
+ org.springframework
+ spring-web
+ ${spring.version}
+
+
+ io.rest-assured
+ spring-mock-mvc
+ ${spring-mock-mvc.version}
+ test
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+
+
+
+ net.serenity-bdd
+ serenity-core
+ ${serenity.version}
+ test
+
+
+ org.asciidoctor
+ asciidoctorj
+
+
+
+
+ org.asciidoctor
+ asciidoctor-maven-plugin
+ 1.5.7.1
+
+
+
+
+
+
+
+
+ net.serenity-bdd.maven.plugins
+ serenity-maven-plugin
+ ${serenity.plugin.version}
+
+
+ serenity-reports
+ post-integration-test
+
+ aggregate
+
+
+
+
+
+
+
+
+
+ 1.9.26
+ 1.41.0
+ 1.9.0
+ 1.9.27
+ 1.5.0
+ 3.0.0
+ 0.8.1
+ 4.3.8.RELEASE
+ 3.0.3
+ 3.6.2
+
+
+
diff --git a/libraries-testing/serenity.properties b/libraries-testing/serenity.properties
new file mode 100644
index 0000000000..c77df9c0f7
--- /dev/null
+++ b/libraries-testing/serenity.properties
@@ -0,0 +1,4 @@
+jira.url=
+jira.project=
+jira.username=
+jira.password=
\ No newline at end of file
diff --git a/libraries/src/main/java/com/baeldung/awaitility/AsyncService.java b/libraries-testing/src/main/java/com/baeldung/awaitility/AsyncService.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/awaitility/AsyncService.java
rename to libraries-testing/src/main/java/com/baeldung/awaitility/AsyncService.java
diff --git a/libraries/src/main/java/com/baeldung/serenity/github/GitHubUser.java b/libraries-testing/src/main/java/com/baeldung/serenity/github/GitHubUser.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/serenity/github/GitHubUser.java
rename to libraries-testing/src/main/java/com/baeldung/serenity/github/GitHubUser.java
diff --git a/libraries/src/main/java/com/baeldung/serenity/membership/Commodity.java b/libraries-testing/src/main/java/com/baeldung/serenity/membership/Commodity.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/serenity/membership/Commodity.java
rename to libraries-testing/src/main/java/com/baeldung/serenity/membership/Commodity.java
diff --git a/libraries/src/main/java/com/baeldung/serenity/membership/Member.java b/libraries-testing/src/main/java/com/baeldung/serenity/membership/Member.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/serenity/membership/Member.java
rename to libraries-testing/src/main/java/com/baeldung/serenity/membership/Member.java
diff --git a/libraries/src/main/java/com/baeldung/serenity/membership/MemberGrade.java b/libraries-testing/src/main/java/com/baeldung/serenity/membership/MemberGrade.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/serenity/membership/MemberGrade.java
rename to libraries-testing/src/main/java/com/baeldung/serenity/membership/MemberGrade.java
diff --git a/libraries/src/main/java/com/baeldung/serenity/spring/AdderController.java b/libraries-testing/src/main/java/com/baeldung/serenity/spring/AdderController.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/serenity/spring/AdderController.java
rename to libraries-testing/src/main/java/com/baeldung/serenity/spring/AdderController.java
diff --git a/libraries/src/main/java/com/baeldung/serenity/spring/AdderService.java b/libraries-testing/src/main/java/com/baeldung/serenity/spring/AdderService.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/serenity/spring/AdderService.java
rename to libraries-testing/src/main/java/com/baeldung/serenity/spring/AdderService.java
diff --git a/libraries/src/main/java/com/baeldung/serenity/spring/PlainAdderController.java b/libraries-testing/src/main/java/com/baeldung/serenity/spring/PlainAdderController.java
similarity index 100%
rename from libraries/src/main/java/com/baeldung/serenity/spring/PlainAdderController.java
rename to libraries-testing/src/main/java/com/baeldung/serenity/spring/PlainAdderController.java
diff --git a/libraries/src/test/java/com/baeldung/awaitility/AsyncServiceLongRunningManualTest.java b/libraries-testing/src/test/java/com/baeldung/awaitility/AsyncServiceLongRunningManualTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/awaitility/AsyncServiceLongRunningManualTest.java
rename to libraries-testing/src/test/java/com/baeldung/awaitility/AsyncServiceLongRunningManualTest.java
diff --git a/libraries/src/test/java/com/baeldung/hoverfly/HoverflyApiLiveTest.java b/libraries-testing/src/test/java/com/baeldung/hoverfly/HoverflyApiLiveTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/hoverfly/HoverflyApiLiveTest.java
rename to libraries-testing/src/test/java/com/baeldung/hoverfly/HoverflyApiLiveTest.java
diff --git a/libraries/src/test/java/com/baeldung/jsonassert/JsonAssertUnitTest.java b/libraries-testing/src/test/java/com/baeldung/jsonassert/JsonAssertUnitTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/jsonassert/JsonAssertUnitTest.java
rename to libraries-testing/src/test/java/com/baeldung/jsonassert/JsonAssertUnitTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/GithubUserProfilePayloadIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/GithubUserProfilePayloadIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/GithubUserProfilePayloadIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/GithubUserProfilePayloadIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/GoogleSearchLiveTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchLiveTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/GoogleSearchLiveTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchLiveTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/GoogleSearchPageObjectLiveTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchPageObjectLiveTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/GoogleSearchPageObjectLiveTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchPageObjectLiveTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/GoogleSearchScreenplayLiveTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchScreenplayLiveTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/GoogleSearchScreenplayLiveTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/GoogleSearchScreenplayLiveTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/MemberStatusIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/MemberStatusIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/MemberStatusIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/MemberStatusIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/github/GithubRestAssuredUserAPISteps.java b/libraries-testing/src/test/java/com/baeldung/serenity/github/GithubRestAssuredUserAPISteps.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/github/GithubRestAssuredUserAPISteps.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/github/GithubRestAssuredUserAPISteps.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/github/GithubRestUserAPISteps.java b/libraries-testing/src/test/java/com/baeldung/serenity/github/GithubRestUserAPISteps.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/github/GithubRestUserAPISteps.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/github/GithubRestUserAPISteps.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/github/GithubUserProfilePayloadStepDefinitions.java b/libraries-testing/src/test/java/com/baeldung/serenity/github/GithubUserProfilePayloadStepDefinitions.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/github/GithubUserProfilePayloadStepDefinitions.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/github/GithubUserProfilePayloadStepDefinitions.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/membership/MemberStatusSteps.java b/libraries-testing/src/test/java/com/baeldung/serenity/membership/MemberStatusSteps.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/membership/MemberStatusSteps.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/membership/MemberStatusSteps.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/pageobjects/GoogleSearchPageObject.java b/libraries-testing/src/test/java/com/baeldung/serenity/pageobjects/GoogleSearchPageObject.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/pageobjects/GoogleSearchPageObject.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/pageobjects/GoogleSearchPageObject.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/screenplay/GoogleSearchPage.java b/libraries-testing/src/test/java/com/baeldung/serenity/screenplay/GoogleSearchPage.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/screenplay/GoogleSearchPage.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/screenplay/GoogleSearchPage.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/screenplay/GoogleSearchResults.java b/libraries-testing/src/test/java/com/baeldung/serenity/screenplay/GoogleSearchResults.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/screenplay/GoogleSearchResults.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/screenplay/GoogleSearchResults.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/screenplay/SearchForKeyword.java b/libraries-testing/src/test/java/com/baeldung/serenity/screenplay/SearchForKeyword.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/screenplay/SearchForKeyword.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/screenplay/SearchForKeyword.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/screenplay/StartWith.java b/libraries-testing/src/test/java/com/baeldung/serenity/screenplay/StartWith.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/screenplay/StartWith.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/screenplay/StartWith.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderClassDirtiesContextIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderClassDirtiesContextIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/AdderClassDirtiesContextIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderClassDirtiesContextIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/AdderIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextDependencyWorkaroundIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextDependencyWorkaroundIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextDependencyWorkaroundIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextDependencyWorkaroundIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextInitWorkaroundIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextInitWorkaroundIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextInitWorkaroundIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextInitWorkaroundIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderMethodDirtiesContextIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodRuleIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderMethodRuleIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/AdderMethodRuleIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderMethodRuleIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderMockMvcIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderMockMvcIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/AdderMockMvcIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderMockMvcIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderServiceIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderServiceIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/AdderServiceIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderServiceIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/AdderSpringSerenityRunnerIntegrationTest.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderSpringSerenityRunnerIntegrationTest.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/AdderSpringSerenityRunnerIntegrationTest.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/AdderSpringSerenityRunnerIntegrationTest.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/RandomNumberUtil.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/RandomNumberUtil.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/RandomNumberUtil.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/RandomNumberUtil.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderConstructorDependencySteps.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/steps/AdderConstructorDependencySteps.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderConstructorDependencySteps.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/steps/AdderConstructorDependencySteps.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderRestSteps.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/steps/AdderRestSteps.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderRestSteps.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/steps/AdderRestSteps.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderServiceSteps.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/steps/AdderServiceSteps.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderServiceSteps.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/steps/AdderServiceSteps.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderSteps.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/steps/AdderSteps.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/steps/AdderSteps.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/steps/AdderSteps.java
diff --git a/libraries/src/test/java/com/baeldung/serenity/spring/stories/AdderStory.java b/libraries-testing/src/test/java/com/baeldung/serenity/spring/stories/AdderStory.java
similarity index 100%
rename from libraries/src/test/java/com/baeldung/serenity/spring/stories/AdderStory.java
rename to libraries-testing/src/test/java/com/baeldung/serenity/spring/stories/AdderStory.java
diff --git a/libraries/src/test/resources/adder-beans.xml b/libraries-testing/src/test/resources/adder-beans.xml
similarity index 100%
rename from libraries/src/test/resources/adder-beans.xml
rename to libraries-testing/src/test/resources/adder-beans.xml
diff --git a/libraries/README.md b/libraries/README.md
index 375863a5ab..ebf087ccd8 100644
--- a/libraries/README.md
+++ b/libraries/README.md
@@ -1,58 +1,41 @@
### Relevant articles
-- [Intro to Jasypt](http://www.baeldung.com/jasypt)
- [Introduction to Javatuples](http://www.baeldung.com/java-tuples)
- [Introduction to Javassist](http://www.baeldung.com/javassist)
- [Introduction to Apache Flink with Java](http://www.baeldung.com/apache-flink)
-- [Introduction to JSONassert](http://www.baeldung.com/jsonassert)
- [Intro to JaVers](http://www.baeldung.com/javers)
-- [Introduction to Serenity BDD](http://www.baeldung.com/serenity-bdd)
- [Merging Streams in Java](http://www.baeldung.com/java-merge-streams)
-- [Serenity BDD and Screenplay](http://www.baeldung.com/serenity-screenplay)
- [Introduction to Quartz](http://www.baeldung.com/quartz)
- [How to Warm Up the JVM](http://www.baeldung.com/java-jvm-warmup)
- [Software Transactional Memory in Java Using Multiverse](http://www.baeldung.com/java-multiverse-stm)
-- [Serenity BDD with Spring and JBehave](http://www.baeldung.com/serenity-spring-jbehave)
- [Locality-Sensitive Hashing in Java Using Java-LSH](http://www.baeldung.com/locality-sensitive-hashing)
-- [Introduction to Awaitlity](http://www.baeldung.com/awaitlity-testing)
- [Introduction to Neuroph](http://www.baeldung.com/neuroph)
- [Quick Guide to RSS with Rome](http://www.baeldung.com/rome-rss)
- [Introduction to PCollections](http://www.baeldung.com/java-pcollections)
-- [Introduction to Hoverfly in Java](http://www.baeldung.com/hoverfly)
- [Introduction to Eclipse Collections](http://www.baeldung.com/eclipse-collections)
- [DistinctBy in the Java Stream API](http://www.baeldung.com/java-streams-distinct-by)
- [Introduction to NoException](http://www.baeldung.com/no-exception)
- [Spring Yarg Integration](http://www.baeldung.com/spring-yarg)
- [Delete a Directory Recursively in Java](http://www.baeldung.com/java-delete-directory)
- [Guide to JDeferred](http://www.baeldung.com/jdeferred)
-- [Integrating Retrofit with RxJava](http://www.baeldung.com/retrofit-rxjava)
- [Introduction to MBassador](http://www.baeldung.com/mbassador)
-- [Introduction to Retrofit](http://www.baeldung.com/retrofit)
- [Using Pairs in Java](http://www.baeldung.com/java-pairs)
- [Introduction to Caffeine](http://www.baeldung.com/java-caching-caffeine)
- [Introduction to StreamEx](http://www.baeldung.com/streamex)
-- [Introduction to BouncyCastle with Java](http://www.baeldung.com/java-bouncy-castle)
- [A Docker Guide for Java](http://www.baeldung.com/docker-java-api)
- [Introduction to Akka Actors in Java](http://www.baeldung.com/akka-actors-java)
-- [A Guide to Unirest](http://www.baeldung.com/unirest)
-- [Introduction to Akka Actors in Java](http://www.baeldung.com/akka-actors-java)
- [A Guide to Byte Buddy](http://www.baeldung.com/byte-buddy)
- [Introduction to jOOL](http://www.baeldung.com/jool)
- [Consumer Driven Contracts with Pact](http://www.baeldung.com/pact-junit-consumer-driven-contracts)
- [Introduction to Atlassian Fugue](http://www.baeldung.com/java-fugue)
- [Publish and Receive Messages with Nats Java Client](http://www.baeldung.com/nats-java-client)
- [Java Concurrency Utility with JCTools](http://www.baeldung.com/java-concurrency-jc-tools)
-- [Creating REST Microservices with Javalin](http://www.baeldung.com/javalin-rest-microservices)
- [Introduction to JavaPoet](http://www.baeldung.com/java-poet)
- [Convert String to Date in Java](http://www.baeldung.com/java-string-to-date)
- [Guide to Resilience4j](http://www.baeldung.com/resilience4j)
-- [Parsing YAML with SnakeYAML](http://www.baeldung.com/java-snake-yaml)
-- [Guide to JMapper](http://www.baeldung.com/jmapper)
- [Exactly Once Processing in Kafka](https://www.baeldung.com/kafka-exactly-once)
-- [An Introduction to SuanShu](https://www.baeldung.com/suanshu)
- [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 438fe6a519..a8ded19a1e 100644
--- a/libraries/pom.xml
+++ b/libraries/pom.xml
@@ -46,11 +46,7 @@
commons-net
${commons-net.version}
-
- org.jasypt
- jasypt
- ${jasypt.version}
-
+
org.javatuples
javatuples
@@ -106,17 +102,17 @@
- net.serenity-bdd
- serenity-core
- ${serenity.version}
- test
-
-
- org.asciidoctor
- asciidoctorj
-
-
-
+ net.serenity-bdd
+ serenity-core
+ ${serenity.version}
+ test
+
+
+ org.asciidoctor
+ asciidoctorj
+
+
+
net.serenity-bdd
serenity-junit
@@ -367,22 +363,7 @@
${vavr.version}
-
-
- com.squareup.retrofit2
- retrofit
- ${retrofit.version}
-
-
- com.squareup.retrofit2
- converter-gson
- ${retrofit.version}
-
-
- com.squareup.retrofit2
- adapter-rxjava
- ${retrofit.version}
-
+
com.squareup.okhttp3
logging-interceptor
@@ -453,16 +434,6 @@
caffeine
${caffeine.version}
-
- org.bouncycastle
- bcprov-jdk15on
- ${bouncycastle.version}
-
-
- org.bouncycastle
- bcpkix-jdk15on
- ${bouncycastle.version}
-
com.google.http-client
google-http-client
@@ -540,18 +511,9 @@
test
test
-
- com.mashape.unirest
- unirest-java
- ${unirest.version}
-
-
-
- io.javalin
- javalin
- ${javalin.version}
-
+
+
io.atlassian.fugue
@@ -608,24 +570,6 @@
test
-
- org.yaml
- snakeyaml
- ${snakeyaml.version}
-
-
-
- com.numericalmethod
- suanshu
- ${suanshu.version}
-
-
-
- org.derive4j
- derive4j
- ${derive4j.version}
- true
-
org.mockftpserver
MockFtpServer
@@ -765,12 +709,10 @@
- 4.0.0
- 1.21
+
1.23.0
0.7.0
3.2.7
- 1.9.2
1.2
3.21.0-GA
3.6.2
@@ -799,7 +741,7 @@
0.9.0
15.2
1.5.1
- 2.3.0
+
2.10
1.5.1
1.15
@@ -810,7 +752,7 @@
v4-rev493-1.21.0
2.0.0
3.0.14
- 1.4.9
+
2.1.2
1.10.L001
0.9.4.0006L
@@ -840,13 +782,10 @@
1.2.6
4.8.1
1.0.1
- 1.58
1.19.4
- 1.6.0
4.5.1
3.3.0
3.0.2
- 1.1.0
2.7.1
3.6
0.9.11
diff --git a/patterns/design-patterns-2/pom.xml b/patterns/design-patterns-2/pom.xml
index 17afff87ae..f99bb4dc9c 100644
--- a/patterns/design-patterns-2/pom.xml
+++ b/patterns/design-patterns-2/pom.xml
@@ -30,6 +30,12 @@
org.apache.commons
commons-lang3
${commons-lang3.version}
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
org.inferred
@@ -49,6 +55,7 @@
1.8
1.8
16.0.2
+ 3.12.2
2.4.1
3.0.2
diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/memento/TextEditor.java b/patterns/design-patterns-2/src/main/java/com/baeldung/memento/TextEditor.java
new file mode 100644
index 0000000000..37ac962773
--- /dev/null
+++ b/patterns/design-patterns-2/src/main/java/com/baeldung/memento/TextEditor.java
@@ -0,0 +1,27 @@
+package com.baeldung.memento;
+
+public class TextEditor {
+
+ private TextWindow textWindow;
+ private TextWindowState savedTextWindow;
+
+ public TextEditor(TextWindow textWindow) {
+ this.textWindow = textWindow;
+ }
+
+ public void write(String text) {
+ textWindow.addText(text);
+ }
+
+ public String print() {
+ return textWindow.getCurrentText();
+ }
+
+ public void hitSave() {
+ savedTextWindow = textWindow.save();
+ }
+
+ public void hitUndo() {
+ textWindow.restore(savedTextWindow);
+ }
+}
diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/memento/TextWindow.java b/patterns/design-patterns-2/src/main/java/com/baeldung/memento/TextWindow.java
new file mode 100644
index 0000000000..08778561b0
--- /dev/null
+++ b/patterns/design-patterns-2/src/main/java/com/baeldung/memento/TextWindow.java
@@ -0,0 +1,26 @@
+package com.baeldung.memento;
+
+public class TextWindow {
+
+ private StringBuilder currentText;
+
+ public TextWindow() {
+ this.currentText = new StringBuilder();
+ }
+
+ public String getCurrentText() {
+ return currentText.toString();
+ }
+
+ public void addText(String text) {
+ currentText.append(text);
+ }
+
+ public TextWindowState save() {
+ return new TextWindowState(currentText.toString());
+ }
+
+ public void restore(TextWindowState save) {
+ currentText = new StringBuilder(save.getText());
+ }
+}
diff --git a/patterns/design-patterns-2/src/main/java/com/baeldung/memento/TextWindowState.java b/patterns/design-patterns-2/src/main/java/com/baeldung/memento/TextWindowState.java
new file mode 100644
index 0000000000..10015a84d1
--- /dev/null
+++ b/patterns/design-patterns-2/src/main/java/com/baeldung/memento/TextWindowState.java
@@ -0,0 +1,14 @@
+package com.baeldung.memento;
+
+public class TextWindowState {
+
+ private String text;
+
+ public TextWindowState(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+}
diff --git a/patterns/design-patterns-2/src/test/java/com/baeldung/memento/TextEditorUnitTest.java b/patterns/design-patterns-2/src/test/java/com/baeldung/memento/TextEditorUnitTest.java
new file mode 100644
index 0000000000..09f6df70a2
--- /dev/null
+++ b/patterns/design-patterns-2/src/test/java/com/baeldung/memento/TextEditorUnitTest.java
@@ -0,0 +1,20 @@
+package com.baeldung.memento;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class TextEditorUnitTest {
+
+ @Test
+ void givenTextEditor_whenAddTextSaveAddMoreAndUndo_thenSavecStateRestored() {
+ TextEditor textEditor = new TextEditor(new TextWindow());
+ textEditor.write("The Memento Design Pattern\n");
+ textEditor.write("How to implement it in Java?\n");
+ textEditor.hitSave();
+ textEditor.write("Buy milk and eggs before coming home\n");
+ textEditor.hitUndo();
+
+ assertThat(textEditor.print()).isEqualTo("The Memento Design Pattern\nHow to implement it in Java?\n");
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/java-jpa-2/README.md b/persistence-modules/java-jpa-2/README.md
index 7a7429008b..579dcbdab0 100644
--- a/persistence-modules/java-jpa-2/README.md
+++ b/persistence-modules/java-jpa-2/README.md
@@ -1,6 +1,4 @@
# Relevant Articles
-<<<<<<< HEAD
- [JPA Query Parameters Usage](http://www.baeldung.com/jpa-query-parameters-usage)
-=======
->>>>>>> refs/heads/master
+- [Mapping Entitiy Class Names to SQL Table Names with JPA](https://www.baeldung.com/jpa-entity-table-names)
diff --git a/persistence-modules/java-mongodb/README.md b/persistence-modules/java-mongodb/README.md
index 045b245030..f1542e3ee9 100644
--- a/persistence-modules/java-mongodb/README.md
+++ b/persistence-modules/java-mongodb/README.md
@@ -4,3 +4,4 @@
- [A Simple Tagging Implementation with MongoDB](http://www.baeldung.com/mongodb-tagging)
- [MongoDB BSON Guide](https://www.baeldung.com/mongodb-bson)
- [Geospatial Support in MongoDB](https://www.baeldung.com/mongodb-geospatial-support)
+- [Introduction to Morphia – Java ODM for MongoDB](https://www.baeldung.com/mongodb-morphia)
diff --git a/persistence-modules/java-sql2o/README.md b/persistence-modules/java-sql2o/README.md
index d3586dc9ed..340ad0fc97 100644
--- a/persistence-modules/java-sql2o/README.md
+++ b/persistence-modules/java-sql2o/README.md
@@ -1,3 +1,3 @@
### Relevant Articles:
-- [A Guide to Sql2o](https://www.baeldung.com/java-sql2o)
+- [A Guide to the sql2o JDBC Wrapper](https://www.baeldung.com/java-sql2o)
diff --git a/persistence-modules/spring-hibernate-5/README.md b/persistence-modules/spring-hibernate-5/README.md
index dfcc4e7eb8..adfb152afd 100644
--- a/persistence-modules/spring-hibernate-5/README.md
+++ b/persistence-modules/spring-hibernate-5/README.md
@@ -4,3 +4,4 @@
- [Programmatic Transactions in the Spring TestContext Framework](http://www.baeldung.com/spring-test-programmatic-transactions)
- [JPA Criteria Queries](http://www.baeldung.com/hibernate-criteria-queries)
- [Introduction to Hibernate Search](http://www.baeldung.com/hibernate-search)
+- [@DynamicUpdate with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-dynamicupdate)
diff --git a/persistence-modules/spring-mybatis/README.md b/persistence-modules/spring-mybatis/README.md
new file mode 100644
index 0000000000..5be328285f
--- /dev/null
+++ b/persistence-modules/spring-mybatis/README.md
@@ -0,0 +1,3 @@
+##Relevant Articles
+
+- [MyBatis with Spring](https://www.baeldung.com/spring-mybatis)
diff --git a/pom.xml b/pom.xml
index afe165cf4d..fc3567be51 100644
--- a/pom.xml
+++ b/pom.xml
@@ -507,6 +507,7 @@
libraries-data-2
libraries-apache-commons
libraries-primitive
+ libraries-testing
libraries-security
libraries-server
libraries-http
@@ -650,6 +651,7 @@
spring-boot-keycloak
spring-boot-kotlin
spring-boot-logging-log4j2
+ spring-boot-management
spring-boot-mvc
spring-boot-mvc-birt
spring-boot-ops
@@ -1200,6 +1202,7 @@
libraries-data
libraries-data-2
libraries-apache-commons
+ libraries-testing
libraries-security
libraries-server
libraries-http
@@ -1326,6 +1329,7 @@
spring-boot-jasypt
spring-boot-keycloak
spring-boot-logging-log4j2
+ spring-boot-management
spring-boot-mvc
spring-boot-mvc-birt
spring-boot-ops
diff --git a/resteasy/bin/pom.xml b/resteasy/bin/pom.xml
deleted file mode 100644
index 15d8b5bd18..0000000000
--- a/resteasy/bin/pom.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
- 4.0.0
- com.baeldung
- resteasy-tutorial
- 1.0
- war
-
-
- com.baeldung
- resteasy-tutorial
- 1.0
-
-
-
- RestEasyTutorial
-
-
- org.codehaus.cargo
- cargo-maven2-plugin
- ${cargo-maven2-plugin.version}
-
- true
-
- jetty8x
- embedded
-
-
-
- 8082
-
-
-
-
-
-
-
-
-
-
-
-
- org.jboss.resteasy
- resteasy-servlet-initializer
- ${resteasy.version}
-
-
-
-
- org.jboss.resteasy
- resteasy-client
- ${resteasy.version}
-
-
-
-
-
- org.jboss.resteasy
- resteasy-jaxb-provider
- ${resteasy.version}
-
-
-
- org.jboss.resteasy
- resteasy-jackson-provider
- ${resteasy.version}
-
-
-
- commons-io
- commons-io
- ${commons-io.version}
-
-
-
-
- 3.0.19.Final
- 2.5
- 1.6.1
-
-
\ No newline at end of file
diff --git a/resteasy/bin/src/main/webapp/WEB-INF/classes/logback.xml b/resteasy/bin/src/main/webapp/WEB-INF/classes/logback.xml
deleted file mode 100644
index ec0dc2469a..0000000000
--- a/resteasy/bin/src/main/webapp/WEB-INF/classes/logback.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
- web - %date [%thread] %-5level %logger{36} - %message%n
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/resteasy/bin/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/resteasy/bin/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
deleted file mode 100644
index cb258374a1..0000000000
--- a/resteasy/bin/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/resteasy/bin/src/main/webapp/WEB-INF/jboss-web.xml b/resteasy/bin/src/main/webapp/WEB-INF/jboss-web.xml
deleted file mode 100644
index 694bb71332..0000000000
--- a/resteasy/bin/src/main/webapp/WEB-INF/jboss-web.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/resteasy/bin/src/main/webapp/WEB-INF/web.xml b/resteasy/bin/src/main/webapp/WEB-INF/web.xml
deleted file mode 100644
index d5f00293f4..0000000000
--- a/resteasy/bin/src/main/webapp/WEB-INF/web.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- RestEasy Example
-
-
- resteasy.servlet.mapping.prefix
- /rest
-
-
-
\ No newline at end of file
diff --git a/resteasy/bin/src/main/webapp/script.js b/resteasy/bin/src/main/webapp/script.js
deleted file mode 100644
index 88198887b0..0000000000
--- a/resteasy/bin/src/main/webapp/script.js
+++ /dev/null
@@ -1,16 +0,0 @@
-function call(url, type, data) {
- var request = $.ajax({
- url : url,
- method : "GET",
- data : (data) ? JSON.stringify(data) : "",
- dataType : type
- });
-
- request.done(function(resp) {
- console.log(resp);
- });
-
- request.fail(function(jqXHR, textStatus) {
- console.log("Request failed: " + textStatus);
- });
-};
\ No newline at end of file
diff --git a/resteasy/bin/src/test/resources/com/baeldung/server/movies/batman.json b/resteasy/bin/src/test/resources/com/baeldung/server/movies/batman.json
deleted file mode 100644
index 82aaaa8f40..0000000000
--- a/resteasy/bin/src/test/resources/com/baeldung/server/movies/batman.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "title": "Batman",
- "imdbId": "tt0096895"
-}
\ No newline at end of file
diff --git a/resteasy/bin/src/test/resources/com/baeldung/server/movies/transformer.json b/resteasy/bin/src/test/resources/com/baeldung/server/movies/transformer.json
deleted file mode 100644
index 634cefc73c..0000000000
--- a/resteasy/bin/src/test/resources/com/baeldung/server/movies/transformer.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "title": "Transformers",
- "imdbId": "tt0418279"
-}
\ No newline at end of file
diff --git a/spring-5-data-reactive/README.md b/spring-5-data-reactive/README.md
index f3205c23bc..4c2347dc77 100644
--- a/spring-5-data-reactive/README.md
+++ b/spring-5-data-reactive/README.md
@@ -7,3 +7,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Reactive Flow with MongoDB, Kotlin, and Spring WebFlux](http://www.baeldung.com/kotlin-mongodb-spring-webflux)
- [Spring Data Reactive Repositories with MongoDB](http://www.baeldung.com/spring-data-mongodb-reactive)
- [Spring Data MongoDB Tailable Cursors](https://www.baeldung.com/spring-data-mongodb-tailable-cursors)
+- [A Quick Look at R2DBC with Spring Data](https://www.baeldung.com/spring-data-r2dbc)
diff --git a/spring-5-reactive-2/README.md b/spring-5-reactive-2/README.md
index bbb45e9f8c..7aec8f94bf 100644
--- a/spring-5-reactive-2/README.md
+++ b/spring-5-reactive-2/README.md
@@ -1 +1,2 @@
## Spring 5 Reactive Project
+- [Spring WebClient vs. RestTemplate](https://www.baeldung.com/spring-webclient-resttemplate)
diff --git a/spring-5-reactive/pom.xml b/spring-5-reactive/pom.xml
index 8d5324a673..99cdd11f24 100644
--- a/spring-5-reactive/pom.xml
+++ b/spring-5-reactive/pom.xml
@@ -120,6 +120,12 @@
${project-reactor-test}
test
+
+ org.apache.httpcomponents
+ httpclient
+ ${httpclient.version}
+
+
@@ -165,6 +171,7 @@
1.0
4.1
3.2.3.RELEASE
+ 4.5.8
diff --git a/spring-all/README.md b/spring-all/README.md
index 22c51525f3..c5825b47fb 100644
--- a/spring-all/README.md
+++ b/spring-all/README.md
@@ -33,4 +33,3 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Spring Events](https://www.baeldung.com/spring-events)
- [Spring Null-Safety Annotations](https://www.baeldung.com/spring-null-safety-annotations)
- [Using @Autowired in Abstract Classes](https://www.baeldung.com/spring-autowired-abstract-class)
-- [The Spring @Qualifier Annotation](https://www.baeldung.com/spring-qualifier-annotation)
diff --git a/spring-boot-angular/src/main/java/com/baeldung/pom.xml b/spring-boot-angular/src/main/java/com/baeldung/pom.xml
deleted file mode 100644
index ac86f932b4..0000000000
--- a/spring-boot-angular/src/main/java/com/baeldung/pom.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
- 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
-
-
-
-
-
- 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
-
-
-
-
-
- 1.8
-
-
\ No newline at end of file
diff --git a/spring-boot-crud/README.md b/spring-boot-crud/README.md
index 566cb327a8..ab2cbe1e3a 100644
--- a/spring-boot-crud/README.md
+++ b/spring-boot-crud/README.md
@@ -1,2 +1,3 @@
### Relevant Articles:
- [Spring Boot CRUD Application with Thymeleaf](https://www.baeldung.com/spring-boot-crud-thymeleaf)
+- [Using a Spring Boot Application as a Dependency](https://www.baeldung.com/spring-boot-dependency)
diff --git a/spring-boot-management/pom.xml b/spring-boot-management/pom.xml
new file mode 100644
index 0000000000..2b3e8f5d06
--- /dev/null
+++ b/spring-boot-management/pom.xml
@@ -0,0 +1,47 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ parent-boot-2
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
+
+ com.baeldung
+ spring-boot-management
+ 0.0.1-SNAPSHOT
+ spring-boot-management
+
+
+ 1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/App.java b/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/App.java
new file mode 100644
index 0000000000..150e451c57
--- /dev/null
+++ b/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/App.java
@@ -0,0 +1,13 @@
+package com.baeldung.spring.boot.management.trace;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class App {
+
+ public static void main(String[] args) {
+ SpringApplication.run(App.class);
+ }
+
+}
diff --git a/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/CustomTraceRepository.java b/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/CustomTraceRepository.java
new file mode 100644
index 0000000000..d85c043dc0
--- /dev/null
+++ b/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/CustomTraceRepository.java
@@ -0,0 +1,29 @@
+package com.baeldung.spring.boot.management.trace;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.springframework.boot.actuate.trace.http.HttpTrace;
+import org.springframework.boot.actuate.trace.http.HttpTraceRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class CustomTraceRepository implements HttpTraceRepository {
+
+ AtomicReference lastTrace = new AtomicReference<>();
+
+ @Override
+ public List findAll() {
+ return Collections.singletonList(lastTrace.get());
+ }
+
+ @Override
+ public void add(HttpTrace trace) {
+ if ("GET".equals(trace.getRequest()
+ .getMethod())) {
+ lastTrace.set(trace);
+ }
+ }
+
+}
diff --git a/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/EchoController.java b/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/EchoController.java
new file mode 100644
index 0000000000..70bc27a3bb
--- /dev/null
+++ b/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/EchoController.java
@@ -0,0 +1,15 @@
+package com.baeldung.spring.boot.management.trace;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController("echo")
+public class EchoController {
+
+ @GetMapping
+ public String echo(@RequestParam("msg") String msg) {
+ return "echoing " + msg;
+ }
+
+}
diff --git a/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/TraceRequestFilter.java b/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/TraceRequestFilter.java
new file mode 100644
index 0000000000..fd6312df47
--- /dev/null
+++ b/spring-boot-management/src/main/java/com/baeldung/spring/boot/management/trace/TraceRequestFilter.java
@@ -0,0 +1,27 @@
+package com.baeldung.spring.boot.management.trace;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.boot.actuate.trace.http.HttpExchangeTracer;
+import org.springframework.boot.actuate.trace.http.HttpTraceRepository;
+import org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TraceRequestFilter extends HttpTraceFilter {
+ /**
+ * Create a new {@link HttpTraceFilter} instance.
+ *
+ * @param repository the trace repository
+ * @param tracer used to trace exchanges
+ */
+ public TraceRequestFilter(HttpTraceRepository repository, HttpExchangeTracer tracer) {
+ super(repository, tracer);
+ }
+
+ @Override
+ protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
+ return request.getServletPath().contains("actuator");
+ }
+}
diff --git a/spring-boot-management/src/main/resources/application.properties b/spring-boot-management/src/main/resources/application.properties
new file mode 100644
index 0000000000..835ca64eac
--- /dev/null
+++ b/spring-boot-management/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+management.endpoints.web.exposure.include=httptrace
+management.trace.http.include=RESPONSE_HEADERS
+
diff --git a/spring-boot-properties/README.md b/spring-boot-properties/README.md
index e467e129dd..9aea5b4871 100644
--- a/spring-boot-properties/README.md
+++ b/spring-boot-properties/README.md
@@ -1,10 +1,10 @@
### Relevant Articles:
-- [Reloading Properties in Spring](https://www.baeldung.com/reloading-properties-files-in-spring/)
+- [Reloading Properties Files in Spring](https://www.baeldung.com/spring-reloading-properties)
- [Guide to @ConfigurationProperties in Spring Boot](http://www.baeldung.com/configuration-properties-in-spring-boot)
- [Load Spring Boot Properties From a JSON File](https://www.baeldung.com/spring-boot-json-properties)
- [Guide to @EnableConfigurationProperties](https://www.baeldung.com/spring-enable-config-properties)
-- [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
+- [Properties with Spring and Spring Boot](http://www.baeldung.com/properties-with-spring) - checkout the `com.baeldung.properties` package for all scenarios of properties injection and usage
- [A Quick Guide to Spring @Value](http://www.baeldung.com/spring-value-annotation)
- [Spring YAML Configuration](http://www.baeldung.com/spring-yaml)
- [Using Spring @Value with Defaults](http://www.baeldung.com/spring-value-defaults)
-- [How to Inject a Property Value Into a Class Not Managed by Spring?](http://www.baeldung.com/inject-properties-value-non-spring-class)
\ No newline at end of file
+- [How to Inject a Property Value Into a Class Not Managed by Spring?](http://www.baeldung.com/inject-properties-value-non-spring-class)
diff --git a/spring-boot-testing/README.MD b/spring-boot-testing/README.MD
index 99d7db5743..7a4c4f53a1 100644
--- a/spring-boot-testing/README.MD
+++ b/spring-boot-testing/README.MD
@@ -6,3 +6,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Testing with Spring and Spock](https://www.baeldung.com/spring-spock-testing)
- [Exclude Auto-Configuration Classes in Spring Boot Tests](https://www.baeldung.com/spring-boot-exclude-auto-configuration-test)
- [Setting the Log Level in Spring Boot when Testing](https://www.baeldung.com/spring-boot-testing-log-level)
+- [Embedded Redis Server with Spring Boot Test](https://www.baeldung.com/spring-embedded-redis)
diff --git a/spring-di/README.md b/spring-di/README.md
new file mode 100644
index 0000000000..a61ebe5127
--- /dev/null
+++ b/spring-di/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles
+
+- [The Spring @Qualifier Annotation](https://www.baeldung.com/spring-qualifier-annotation)
diff --git a/spring-jooq/src/test/java/com/baeldung/jooq/introduction/QueryIntegrationTest.java b/spring-jooq/src/test/java/com/baeldung/jooq/introduction/QueryIntegrationTest.java
index 28bc4c63c7..ff1e8dc6f8 100644
--- a/spring-jooq/src/test/java/com/baeldung/jooq/introduction/QueryIntegrationTest.java
+++ b/spring-jooq/src/test/java/com/baeldung/jooq/introduction/QueryIntegrationTest.java
@@ -47,12 +47,14 @@ public class QueryIntegrationTest {
.from(AUTHOR)
.join(AUTHOR_BOOK).on(AUTHOR.ID.equal(AUTHOR_BOOK.AUTHOR_ID))
.join(BOOK).on(AUTHOR_BOOK.BOOK_ID.equal(BOOK.ID))
- .groupBy(AUTHOR.LAST_NAME).fetch();
+ .groupBy(AUTHOR.LAST_NAME)
+ .orderBy(AUTHOR.LAST_NAME.desc())
+ .fetch();
assertEquals(3, result.size());
assertEquals("Sierra", result.getValue(0, AUTHOR.LAST_NAME));
assertEquals(Integer.valueOf(2), result.getValue(0, DSL.count()));
- assertEquals("Schildt", result.getValue(2, AUTHOR.LAST_NAME));
+ assertEquals("Bates", result.getValue(2, AUTHOR.LAST_NAME));
assertEquals(Integer.valueOf(1), result.getValue(2, DSL.count()));
}
diff --git a/spring-jooq/src/test/java/com/baeldung/jooq/springboot/SpringBootIntegrationTest.java b/spring-jooq/src/test/java/com/baeldung/jooq/springboot/SpringBootIntegrationTest.java
index 5e76fb3c93..3b3e865108 100644
--- a/spring-jooq/src/test/java/com/baeldung/jooq/springboot/SpringBootIntegrationTest.java
+++ b/spring-jooq/src/test/java/com/baeldung/jooq/springboot/SpringBootIntegrationTest.java
@@ -49,12 +49,13 @@ public class SpringBootIntegrationTest {
.from(AUTHOR).join(AUTHOR_BOOK).on(AUTHOR.ID.equal(AUTHOR_BOOK.AUTHOR_ID))
.join(BOOK).on(AUTHOR_BOOK.BOOK_ID.equal(BOOK.ID))
.groupBy(AUTHOR.LAST_NAME)
+ .orderBy(AUTHOR.LAST_NAME.desc())
.fetch();
assertEquals(3, result.size());
assertEquals("Sierra", result.getValue(0, AUTHOR.LAST_NAME));
assertEquals(Integer.valueOf(2), result.getValue(0, DSL.count()));
- assertEquals("Schildt", result.getValue(2, AUTHOR.LAST_NAME));
+ assertEquals("Bates", result.getValue(2, AUTHOR.LAST_NAME));
assertEquals(Integer.valueOf(1), result.getValue(2, DSL.count()));
}
diff --git a/spring-roo/pom.xml b/spring-roo/pom.xml
index baa0e7f5e6..eb3a680d93 100644
--- a/spring-roo/pom.xml
+++ b/spring-roo/pom.xml
@@ -604,14 +604,14 @@
- 2.0.0.RC1
+ 2.0.0.RELEASE
8
UTF-8
1.8
1.5.4
- 1.4.1.RELEASE
+ 2.1.7.RELEASE
1.8
- 1.2.0.RC1
+ 1.2.0.RELEASE
1.1.2
3.0.0.RELEASE
2.0.0
diff --git a/spring-thymeleaf-2/README.md b/spring-thymeleaf-2/README.md
index 9bd441a6bd..9e12f2d99f 100644
--- a/spring-thymeleaf-2/README.md
+++ b/spring-thymeleaf-2/README.md
@@ -1,3 +1,4 @@
## Relevant Articles:
- [Working with Enums in Thymeleaf](https://www.baeldung.com/thymeleaf-enums)
+- [Changing the Thymeleaf Template Directory in Spring Boot](https://www.baeldung.com/spring-thymeleaf-template-directory)
diff --git a/spring-thymeleaf/README.md b/spring-thymeleaf/README.md
index b6824003db..082a65f55b 100644
--- a/spring-thymeleaf/README.md
+++ b/spring-thymeleaf/README.md
@@ -18,6 +18,7 @@
- [Spring with Thymeleaf Pagination for a List](http://www.baeldung.com/spring-thymeleaf-pagination)
- [Working with Select and Option in Thymeleaf](http://www.baeldung.com/thymeleaf-select-option)
- [Working With Custom HTML Attributes in Thymeleaf](https://www.baeldung.com/thymeleaf-custom-html-attributes)
+- [Spring Request Parameters with Thymeleaf](https://www.baeldung.com/spring-thymeleaf-request-parameters)
### Build the Project
diff --git a/testing-modules/junit-5-basics/README.md b/testing-modules/junit-5-basics/README.md
index dbe6803401..31eb75a792 100644
--- a/testing-modules/junit-5-basics/README.md
+++ b/testing-modules/junit-5-basics/README.md
@@ -8,3 +8,4 @@
- [JUnit 5 @Test Annotation](http://www.baeldung.com/junit-5-test-annotation)
- [Migrating from JUnit 4 to JUnit 5](http://www.baeldung.com/junit-5-migration)
- [Assert an Exception is Thrown in JUnit 4 and 5](http://www.baeldung.com/junit-assert-exception)
+- [The Difference Between Failure and Error in JUnit](https://www.baeldung.com/junit-failure-vs-error)
diff --git a/testing-modules/rest-assured/pom.xml b/testing-modules/rest-assured/pom.xml
index eb85c6c8be..75f33c26f1 100644
--- a/testing-modules/rest-assured/pom.xml
+++ b/testing-modules/rest-assured/pom.xml
@@ -162,11 +162,6 @@
commons-collections
${commons-collections.version}
-
-
- org.springframework.boot
- spring-boot-starter-security
-
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
index a55c0a69e4..83a6e544b7 100644
--- 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
@@ -17,7 +17,7 @@ import java.util.Set;
import javax.annotation.PostConstruct;
-import org.junit.jupiter.api.Test;
+import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;