Date: Sun, 12 Apr 2020 22:45:54 +0000
Subject: [PATCH 008/225] Java 11 migraiton: monad
---
.../src/main/java/com/iluwatar/monad/App.java | 9 ++---
.../main/java/com/iluwatar/monad/User.java | 8 ++--
.../java/com/iluwatar/monad/Validator.java | 19 +++++----
.../test/java/com/iluwatar/monad/AppTest.java | 3 +-
.../java/com/iluwatar/monad/MonadTest.java | 39 +++++++++++--------
5 files changed, 42 insertions(+), 36 deletions(-)
diff --git a/monad/src/main/java/com/iluwatar/monad/App.java b/monad/src/main/java/com/iluwatar/monad/App.java
index ccb42edd0..bb3315064 100644
--- a/monad/src/main/java/com/iluwatar/monad/App.java
+++ b/monad/src/main/java/com/iluwatar/monad/App.java
@@ -41,9 +41,8 @@ import org.slf4j.LoggerFactory;
* instance of a plain object with {@link Validator#of(Object)} and validates it {@link
* Validator#validate(Function, Predicate, String)} against given predicates.
*
- * As a validation result {@link Validator#get()} it either returns valid object {@link
- * Validator#t} or throws a list of exceptions {@link Validator#exceptions} collected during
- * validation.
+ *
As a validation result {@link Validator#get()} either returns valid object
+ * or throws {@link IllegalStateException} with list of exceptions collected during validation.
*/
public class App {
@@ -55,10 +54,10 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
- User user = new User("user", 24, Sex.FEMALE, "foobar.com");
+ var user = new User("user", 24, Sex.FEMALE, "foobar.com");
LOGGER.info(Validator.of(user).validate(User::getName, Objects::nonNull, "name is null")
.validate(User::getName, name -> !name.isEmpty(), "name is empty")
- .validate(User::getEmail, email -> !email.contains("@"), "email doesn't containt '@'")
+ .validate(User::getEmail, email -> !email.contains("@"), "email doesn't contains '@'")
.validate(User::getAge, age -> age > 20 && age < 30, "age isn't between...").get()
.toString());
}
diff --git a/monad/src/main/java/com/iluwatar/monad/User.java b/monad/src/main/java/com/iluwatar/monad/User.java
index 77766d1aa..f67009bc3 100644
--- a/monad/src/main/java/com/iluwatar/monad/User.java
+++ b/monad/src/main/java/com/iluwatar/monad/User.java
@@ -28,10 +28,10 @@ package com.iluwatar.monad;
*/
public class User {
- private String name;
- private int age;
- private Sex sex;
- private String email;
+ private final String name;
+ private final int age;
+ private final Sex sex;
+ private final String email;
/**
* Constructor.
diff --git a/monad/src/main/java/com/iluwatar/monad/Validator.java b/monad/src/main/java/com/iluwatar/monad/Validator.java
index 2d1f1bdab..47acc8a42 100644
--- a/monad/src/main/java/com/iluwatar/monad/Validator.java
+++ b/monad/src/main/java/com/iluwatar/monad/Validator.java
@@ -85,18 +85,21 @@ public class Validator {
}
/**
- * Extension for the {@link Validator#validate(Function, Predicate, String)} method, dedicated for
- * objects, that need to be projected before requested validation.
+ * Extension for the {@link Validator#validate(Predicate, String)} method, dedicated for objects,
+ * that need to be projected before requested validation.
*
* @param projection function that gets an objects, and returns projection representing element to
* be validated.
- * @param validation see {@link Validator#validate(Function, Predicate, String)}
- * @param message see {@link Validator#validate(Function, Predicate, String)}
- * @param see {@link Validator#validate(Function, Predicate, String)}
+ * @param validation see {@link Validator#validate(Predicate, String)}
+ * @param message see {@link Validator#validate(Predicate, String)}
+ * @param see {@link Validator#validate(Predicate, String)}
* @return this
*/
- public Validator validate(Function projection, Predicate validation,
- String message) {
+ public Validator validate(
+ Function projection,
+ Predicate validation,
+ String message
+ ) {
return validate(projection.andThen(validation::test)::apply, message);
}
@@ -110,7 +113,7 @@ public class Validator {
if (exceptions.isEmpty()) {
return obj;
}
- IllegalStateException e = new IllegalStateException();
+ var e = new IllegalStateException();
exceptions.forEach(e::addSuppressed);
throw e;
}
diff --git a/monad/src/test/java/com/iluwatar/monad/AppTest.java b/monad/src/test/java/com/iluwatar/monad/AppTest.java
index f4d89a7cd..d56270173 100644
--- a/monad/src/test/java/com/iluwatar/monad/AppTest.java
+++ b/monad/src/test/java/com/iluwatar/monad/AppTest.java
@@ -32,8 +32,7 @@ public class AppTest {
@Test
public void testMain() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/monad/src/test/java/com/iluwatar/monad/MonadTest.java b/monad/src/test/java/com/iluwatar/monad/MonadTest.java
index d1bdd7487..afd5b50f8 100644
--- a/monad/src/test/java/com/iluwatar/monad/MonadTest.java
+++ b/monad/src/test/java/com/iluwatar/monad/MonadTest.java
@@ -23,13 +23,12 @@
package com.iluwatar.monad;
-import org.junit.jupiter.api.Test;
-
-import java.util.Objects;
-
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import java.util.Objects;
+import org.junit.jupiter.api.Test;
+
/**
* Test for Monad Pattern
*/
@@ -37,27 +36,33 @@ public class MonadTest {
@Test
public void testForInvalidName() {
- User tom = new User(null, 21, Sex.MALE, "tom@foo.bar");
- assertThrows(IllegalStateException.class, () -> {
- Validator.of(tom).validate(User::getName, Objects::nonNull, "name cannot be null").get();
- });
+ var tom = new User(null, 21, Sex.MALE, "tom@foo.bar");
+ assertThrows(
+ IllegalStateException.class,
+ () -> Validator.of(tom)
+ .validate(User::getName, Objects::nonNull, "name cannot be null")
+ .get()
+ );
}
@Test
public void testForInvalidAge() {
- User john = new User("John", 17, Sex.MALE, "john@qwe.bar");
- assertThrows(IllegalStateException.class, () -> {
- Validator.of(john).validate(User::getName, Objects::nonNull, "name cannot be null")
- .validate(User::getAge, age -> age > 21, "user is underaged")
- .get();
- });
+ var john = new User("John", 17, Sex.MALE, "john@qwe.bar");
+ assertThrows(
+ IllegalStateException.class,
+ () -> Validator.of(john)
+ .validate(User::getName, Objects::nonNull, "name cannot be null")
+ .validate(User::getAge, age -> age > 21, "user is underage")
+ .get()
+ );
}
@Test
public void testForValid() {
- User sarah = new User("Sarah", 42, Sex.FEMALE, "sarah@det.org");
- User validated = Validator.of(sarah).validate(User::getName, Objects::nonNull, "name cannot be null")
- .validate(User::getAge, age -> age > 21, "user is underaged")
+ var sarah = new User("Sarah", 42, Sex.FEMALE, "sarah@det.org");
+ var validated = Validator.of(sarah)
+ .validate(User::getName, Objects::nonNull, "name cannot be null")
+ .validate(User::getAge, age -> age > 21, "user is underage")
.validate(User::getSex, sex -> sex == Sex.FEMALE, "user is not female")
.validate(User::getEmail, email -> email.contains("@"), "email does not contain @ sign")
.get();
From 109d33c710fbb1db43bf2ecf6354682041f141b5 Mon Sep 17 00:00:00 2001
From: Anurag Agarwal
Date: Sun, 12 Apr 2020 22:49:00 +0000
Subject: [PATCH 009/225] Java 11 migraiton: monostate
---
.../src/main/java/com/iluwatar/monostate/App.java | 6 +++---
.../java/com/iluwatar/monostate/LoadBalancer.java | 6 +++---
.../test/java/com/iluwatar/monostate/AppTest.java | 3 +--
.../com/iluwatar/monostate/LoadBalancerTest.java | 12 ++++++------
4 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/monostate/src/main/java/com/iluwatar/monostate/App.java b/monostate/src/main/java/com/iluwatar/monostate/App.java
index 64cb38461..9f5b2c173 100644
--- a/monostate/src/main/java/com/iluwatar/monostate/App.java
+++ b/monostate/src/main/java/com/iluwatar/monostate/App.java
@@ -30,7 +30,7 @@ package com.iluwatar.monostate;
*
* In the following example, The {@link LoadBalancer} class represents the app's logic. It
* contains a series of Servers, which can handle requests of type {@link Request}. Two instances of
- * LoadBalacer are created. When a request is made to a server via the first LoadBalancer the state
+ * LoadBalancer are created. When a request is made to a server via the first LoadBalancer the state
* change in the first load balancer affects the second. So if the first LoadBalancer selects the
* Server 1, the second LoadBalancer on a new request will select the Second server. If a third
* LoadBalancer is created and a new request is made to it, then it will select the third server as
@@ -43,8 +43,8 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
- LoadBalancer loadBalancer1 = new LoadBalancer();
- LoadBalancer loadBalancer2 = new LoadBalancer();
+ var loadBalancer1 = new LoadBalancer();
+ var loadBalancer2 = new LoadBalancer();
loadBalancer1.serverRequest(new Request("Hello"));
loadBalancer2.serverRequest(new Request("Hello World"));
}
diff --git a/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java b/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
index 8546ae177..7a784f514 100644
--- a/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
+++ b/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
@@ -38,8 +38,8 @@ public class LoadBalancer {
private static int lastServedId;
static {
- int id = 0;
- for (int port : new int[]{8080, 8081, 8082, 8083, 8084}) {
+ var id = 0;
+ for (var port : new int[]{8080, 8081, 8082, 8083, 8084}) {
SERVERS.add(new Server("localhost", port, ++id));
}
}
@@ -69,7 +69,7 @@ public class LoadBalancer {
if (lastServedId >= SERVERS.size()) {
lastServedId = 0;
}
- Server server = SERVERS.get(lastServedId++);
+ var server = SERVERS.get(lastServedId++);
server.serve(request);
}
diff --git a/monostate/src/test/java/com/iluwatar/monostate/AppTest.java b/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
index c914f136e..d17a56bb9 100644
--- a/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
+++ b/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
@@ -32,8 +32,7 @@ public class AppTest {
@Test
public void testMain() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java b/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
index 736bf6ea6..d62c029e2 100644
--- a/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
+++ b/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
@@ -44,8 +44,8 @@ public class LoadBalancerTest {
@Test
public void testSameStateAmongstAllInstances() {
- final LoadBalancer firstBalancer = new LoadBalancer();
- final LoadBalancer secondBalancer = new LoadBalancer();
+ final var firstBalancer = new LoadBalancer();
+ final var secondBalancer = new LoadBalancer();
firstBalancer.addServer(new Server("localhost", 8085, 6));
// Both should have the same number of servers.
assertEquals(firstBalancer.getNoOfServers(), secondBalancer.getNoOfServers());
@@ -55,18 +55,18 @@ public class LoadBalancerTest {
@Test
public void testServe() {
- final Server server = mock(Server.class);
+ final var server = mock(Server.class);
when(server.getHost()).thenReturn("testhost");
when(server.getPort()).thenReturn(1234);
doNothing().when(server).serve(any(Request.class));
- final LoadBalancer loadBalancer = new LoadBalancer();
+ final var loadBalancer = new LoadBalancer();
loadBalancer.addServer(server);
verifyZeroInteractions(server);
- final Request request = new Request("test");
- for (int i = 0; i < loadBalancer.getNoOfServers() * 2; i++) {
+ final var request = new Request("test");
+ for (var i = 0; i < loadBalancer.getNoOfServers() * 2; i++) {
loadBalancer.serverRequest(request);
}
From 9b105d770df2ca56ffd725e88fdbf17666e7cd1b Mon Sep 17 00:00:00 2001
From: Anurag Agarwal
Date: Sun, 12 Apr 2020 22:51:37 +0000
Subject: [PATCH 010/225] Java 11 migraiton: multiton
---
.../src/main/java/com/iluwatar/multiton/Nazgul.java | 2 +-
.../main/java/com/iluwatar/multiton/NazgulEnum.java | 12 +++++++++---
.../main/java/com/iluwatar/multiton/NazgulName.java | 12 +++++++++---
.../src/test/java/com/iluwatar/multiton/AppTest.java | 5 +----
.../java/com/iluwatar/multiton/NazgulEnumTest.java | 8 ++++----
.../test/java/com/iluwatar/multiton/NazgulTest.java | 4 ++--
6 files changed, 26 insertions(+), 17 deletions(-)
diff --git a/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java b/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java
index f55f85aca..bd1fc70ef 100644
--- a/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java
+++ b/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java
@@ -31,7 +31,7 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public final class Nazgul {
- private static Map nazguls;
+ private static final Map nazguls;
private NazgulName name;
diff --git a/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java b/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java
index 5b5c48d66..bb1454b9f 100644
--- a/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java
+++ b/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java
@@ -27,7 +27,13 @@ package com.iluwatar.multiton;
* enum based multiton implementation.
*/
public enum NazgulEnum {
-
- KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA;
-
+ KHAMUL,
+ MURAZOR,
+ DWAR,
+ JI_INDUR,
+ AKHORAHIL,
+ HOARMURATH,
+ ADUNAPHEL,
+ REN,
+ UVATHA
}
diff --git a/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java b/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java
index c7865dceb..cce19c6ff 100644
--- a/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java
+++ b/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java
@@ -27,7 +27,13 @@ package com.iluwatar.multiton;
* Each Nazgul has different {@link NazgulName}.
*/
public enum NazgulName {
-
- KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA;
-
+ KHAMUL,
+ MURAZOR,
+ DWAR,
+ JI_INDUR,
+ AKHORAHIL,
+ HOARMURATH,
+ ADUNAPHEL,
+ REN,
+ UVATHA
}
diff --git a/multiton/src/test/java/com/iluwatar/multiton/AppTest.java b/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
index f577b7f07..0496ebdaf 100644
--- a/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
+++ b/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
@@ -26,15 +26,12 @@ package com.iluwatar.multiton;
import org.junit.jupiter.api.Test;
/**
- *
* Application test
- *
*/
public class AppTest {
@Test
public void test() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java b/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java
index 6668874f4..4d107a181 100644
--- a/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java
+++ b/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java
@@ -39,10 +39,10 @@ class NazgulEnumTest {
*/
@Test
public void testTheSameObjectIsReturnedWithMultipleCalls() {
- for (int i = 0; i < NazgulEnum.values().length; i++) {
- NazgulEnum instance1 = NazgulEnum.values()[i];
- NazgulEnum instance2 = NazgulEnum.values()[i];
- NazgulEnum instance3 = NazgulEnum.values()[i];
+ for (var i = 0; i < NazgulEnum.values().length; i++) {
+ var instance1 = NazgulEnum.values()[i];
+ var instance2 = NazgulEnum.values()[i];
+ var instance3 = NazgulEnum.values()[i];
assertSame(instance1, instance2);
assertSame(instance1, instance3);
assertSame(instance2, instance3);
diff --git a/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java b/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
index 0429f8e29..f900659a8 100644
--- a/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
+++ b/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
@@ -41,8 +41,8 @@ public class NazgulTest {
*/
@Test
public void testGetInstance() {
- for (final NazgulName name : NazgulName.values()) {
- final Nazgul nazgul = Nazgul.getInstance(name);
+ for (final var name : NazgulName.values()) {
+ final var nazgul = Nazgul.getInstance(name);
assertNotNull(nazgul);
assertSame(nazgul, Nazgul.getInstance(name));
assertEquals(name, nazgul.getName());
From 2fa938c02d64edff93757f631fa36fd445624113 Mon Sep 17 00:00:00 2001
From: Anurag Agarwal
Date: Sun, 12 Apr 2020 22:58:50 +0000
Subject: [PATCH 011/225] Java 11 migraiton: mute-idiom
---
.../src/main/java/com/iluwatar/mute/App.java | 23 +++++++++----------
.../test/java/com/iluwatar/mute/AppTest.java | 5 ++--
.../test/java/com/iluwatar/mute/MuteTest.java | 18 ++++++---------
3 files changed, 20 insertions(+), 26 deletions(-)
diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/App.java b/mute-idiom/src/main/java/com/iluwatar/mute/App.java
index d4f140bf0..eca345014 100644
--- a/mute-idiom/src/main/java/com/iluwatar/mute/App.java
+++ b/mute-idiom/src/main/java/com/iluwatar/mute/App.java
@@ -25,7 +25,7 @@ package com.iluwatar.mute;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.sql.SQLException;
+import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -52,9 +52,8 @@ public class App {
* Program entry point.
*
* @param args command line args.
- * @throws Exception if any exception occurs
*/
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
useOfLoggedMute();
@@ -68,17 +67,17 @@ public class App {
* exception occurs.
*/
private static void useOfMute() {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
+ var out = new ByteArrayOutputStream();
Mute.mute(() -> out.write("Hello".getBytes()));
}
- private static void useOfLoggedMute() throws SQLException {
- Resource resource = null;
+ private static void useOfLoggedMute() {
+ Optional resource = Optional.empty();
try {
- resource = acquireResource();
- utilizeResource(resource);
+ resource = Optional.of(acquireResource());
+ utilizeResource(resource.get());
} finally {
- closeResource(resource);
+ resource.ifPresent(App::closeResource);
}
}
@@ -86,14 +85,14 @@ public class App {
* All we can do while failed close of a resource is to log it.
*/
private static void closeResource(Resource resource) {
- Mute.loggedMute(() -> resource.close());
+ Mute.loggedMute(resource::close);
}
- private static void utilizeResource(Resource resource) throws SQLException {
+ private static void utilizeResource(Resource resource) {
LOGGER.info("Utilizing acquired resource: {}", resource);
}
- private static Resource acquireResource() throws SQLException {
+ private static Resource acquireResource() {
return new Resource() {
@Override
diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java
index 5ca525a9d..5883812c7 100644
--- a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java
+++ b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java
@@ -27,12 +27,11 @@ import org.junit.jupiter.api.Test;
/**
* Tests that Mute idiom example runs without errors.
- *
*/
public class AppTest {
@Test
- public void test() throws Exception {
- App.main(null);
+ public void test() {
+ App.main(new String[]{});
}
}
diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java
index f2743113b..33d104ffc 100644
--- a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java
+++ b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java
@@ -23,17 +23,15 @@
package com.iluwatar.mute;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
/**
* Test for the mute-idiom pattern
*/
@@ -50,9 +48,7 @@ public class MuteTest {
@Test
public void muteShouldRethrowUnexpectedExceptionAsAssertionError() {
- assertThrows(AssertionError.class, () -> {
- Mute.mute(this::methodThrowingException);
- });
+ assertThrows(AssertionError.class, () -> Mute.mute(this::methodThrowingException));
}
@Test
@@ -62,7 +58,7 @@ public class MuteTest {
@Test
public void loggedMuteShouldLogExceptionTraceBeforeSwallowingIt() {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ var stream = new ByteArrayOutputStream();
System.setErr(new PrintStream(stream));
Mute.loggedMute(this::methodThrowingException);
From d733122e7ac0ee6d169acae38734d6c0a95d6a03 Mon Sep 17 00:00:00 2001
From: Anurag Agarwal
Date: Sun, 12 Apr 2020 23:00:49 +0000
Subject: [PATCH 012/225] Java 11 migraiton: mutex
---
mutex/src/main/java/com/iluwatar/mutex/App.java | 8 ++++----
mutex/src/main/java/com/iluwatar/mutex/Jar.java | 2 +-
.../src/main/java/com/iluwatar/mutex/Thief.java | 2 +-
.../test/java/com/iluwatar/mutex/AppTest.java | 7 ++-----
.../test/java/com/iluwatar/mutex/JarTest.java | 17 ++++++++---------
.../test/java/com/iluwatar/mutex/MutexTest.java | 6 +++---
6 files changed, 19 insertions(+), 23 deletions(-)
diff --git a/mutex/src/main/java/com/iluwatar/mutex/App.java b/mutex/src/main/java/com/iluwatar/mutex/App.java
index e4a952ef9..c50acc65a 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/App.java
+++ b/mutex/src/main/java/com/iluwatar/mutex/App.java
@@ -38,10 +38,10 @@ public class App {
* main method.
*/
public static void main(String[] args) {
- Mutex mutex = new Mutex();
- Jar jar = new Jar(1000, mutex);
- Thief peter = new Thief("Peter", jar);
- Thief john = new Thief("John", jar);
+ var mutex = new Mutex();
+ var jar = new Jar(1000, mutex);
+ var peter = new Thief("Peter", jar);
+ var john = new Thief("John", jar);
peter.start();
john.start();
}
diff --git a/mutex/src/main/java/com/iluwatar/mutex/Jar.java b/mutex/src/main/java/com/iluwatar/mutex/Jar.java
index f68b266ad..4a0861e1a 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/Jar.java
+++ b/mutex/src/main/java/com/iluwatar/mutex/Jar.java
@@ -48,7 +48,7 @@ public class Jar {
* Method for a thief to take a bean.
*/
public boolean takeBean() {
- boolean success = false;
+ var success = false;
try {
lock.acquire();
success = beans > 0;
diff --git a/mutex/src/main/java/com/iluwatar/mutex/Thief.java b/mutex/src/main/java/com/iluwatar/mutex/Thief.java
index 29caba540..a9a715970 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/Thief.java
+++ b/mutex/src/main/java/com/iluwatar/mutex/Thief.java
@@ -54,7 +54,7 @@ public class Thief extends Thread {
*/
@Override
public void run() {
- int beans = 0;
+ var beans = 0;
while (jar.takeBean()) {
beans = beans + 1;
diff --git a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
index 1793bf90b..0bee249a6 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
+++ b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
@@ -25,15 +25,12 @@ package com.iluwatar.mutex;
import org.junit.jupiter.api.Test;
-import java.io.IOException;
-
/**
* Application Test Entrypoint
*/
public class AppTest {
@Test
- public void test() throws IOException {
- String[] args = {};
- App.main(args);
+ public void test() {
+ App.main(new String[]{});
}
}
diff --git a/mutex/src/test/java/com/iluwatar/mutex/JarTest.java b/mutex/src/test/java/com/iluwatar/mutex/JarTest.java
index e0a316072..786f96e44 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/JarTest.java
+++ b/mutex/src/test/java/com/iluwatar/mutex/JarTest.java
@@ -23,10 +23,11 @@
package com.iluwatar.mutex;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.stream.IntStream;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
/**
* Test case for taking beans from a Jar
@@ -35,12 +36,10 @@ public class JarTest {
@Test
public void testTakeBeans() {
- Mutex mutex = new Mutex();
- Jar jar = new Jar(10, mutex);
- for (int i = 0; i < 10; i++) {
- assertTrue(jar.takeBean());
- }
+ var mutex = new Mutex();
+ var jar = new Jar(10, mutex);
+ IntStream.range(0, 10).mapToObj(i -> jar.takeBean()).forEach(Assertions::assertTrue);
assertFalse(jar.takeBean());
}
-}
\ No newline at end of file
+}
diff --git a/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java b/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java
index 2e3184c51..d6d0cc1d7 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java
+++ b/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java
@@ -23,12 +23,12 @@
package com.iluwatar.mutex;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.fail;
+import org.junit.jupiter.api.Test;
+
/**
* Test case for acquiring and releasing a Mutex
*/
@@ -36,7 +36,7 @@ public class MutexTest {
@Test
public void acquireReleaseTest() {
- Mutex mutex = new Mutex();
+ var mutex = new Mutex();
assertNull(mutex.getOwner());
try {
mutex.acquire();
From daf53225d8977f2a8998e54e4d5001a3d15a8a03 Mon Sep 17 00:00:00 2001
From: Anurag Agarwal
Date: Fri, 1 May 2020 08:04:45 +0000
Subject: [PATCH 013/225] Resolves CR comments
---
marker/src/main/java/App.java | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/marker/src/main/java/App.java b/marker/src/main/java/App.java
index c7b4530c6..8a08a8f70 100644
--- a/marker/src/main/java/App.java
+++ b/marker/src/main/java/App.java
@@ -21,6 +21,9 @@
* THE SOFTWARE.
*/
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* Created by Alexis on 28-Apr-17. With Marker interface idea is to make empty interface and extend
* it. Basically it is just to identify the special objects from normal objects. Like in case of
@@ -43,10 +46,23 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
+ final Logger logger = LoggerFactory.getLogger(App.class);
var guard = new Guard();
var thief = new Thief();
- guard.enter();
- thief.doNothing();
+
+ //noinspection ConstantConditions
+ if (guard instanceof Permission) {
+ guard.enter();
+ } else {
+ logger.info("You have no permission to enter, please leave this area");
+ }
+
+ //noinspection ConstantConditions
+ if (thief instanceof Permission) {
+ thief.doNothing();
+ } else {
+ thief.doNothing();
+ }
}
}
From 9a81ddb7d8680c9bfb1e9cfbf4a9eeb8c976c939 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 19 Jul 2020 17:14:02 +0300
Subject: [PATCH 014/225] #590 add explanation for Observer
---
observer/README.md | 146 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 143 insertions(+), 3 deletions(-)
diff --git a/observer/README.md b/observer/README.md
index 034a90e7d..5d76ab61f 100644
--- a/observer/README.md
+++ b/observer/README.md
@@ -13,9 +13,149 @@ tags:
Dependents, Publish-Subscribe
## Intent
-Define a one-to-many dependency between objects so that when one
-object changes state, all its dependents are notified and updated
-automatically.
+Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified
+and updated automatically.
+
+## Explanation
+
+Real world example
+
+> In a land far away lives the races of hobbits and orcs. Both of them are mostly outdoors so they closely follow the changes in weather. One could say that they are constantly observing the weather.
+
+In plain words
+
+> Register as an observer to receive state changes in the object.
+
+Wikipedia says
+
+> The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
+
+**Programmatic Example**
+
+Let's first introduce the weather observer interface and our races, orcs and hobbits.
+
+```java
+public interface WeatherObserver {
+
+ void update(WeatherType currentWeather);
+}
+
+public class Orcs implements WeatherObserver {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Orcs.class);
+
+ @Override
+ public void update(WeatherType currentWeather) {
+ switch (currentWeather) {
+ case COLD:
+ LOGGER.info("The orcs are freezing cold.");
+ break;
+ case RAINY:
+ LOGGER.info("The orcs are dripping wet.");
+ break;
+ case SUNNY:
+ LOGGER.info("The sun hurts the orcs' eyes.");
+ break;
+ case WINDY:
+ LOGGER.info("The orc smell almost vanishes in the wind.");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+public class Hobbits implements WeatherObserver {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Hobbits.class);
+
+ @Override
+ public void update(WeatherType currentWeather) {
+ switch (currentWeather) {
+ case COLD:
+ LOGGER.info("The hobbits are shivering in the cold weather.");
+ break;
+ case RAINY:
+ LOGGER.info("The hobbits look for cover from the rain.");
+ break;
+ case SUNNY:
+ LOGGER.info("The happy hobbits bade in the warm sun.");
+ break;
+ case WINDY:
+ LOGGER.info("The hobbits hold their hats tightly in the windy weather.");
+ break;
+ default:
+ break;
+ }
+ }
+}
+```
+
+Then here's the weather that is constantly changing.
+
+```java
+public class Weather {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Weather.class);
+
+ private WeatherType currentWeather;
+ private List observers;
+
+ public Weather() {
+ observers = new ArrayList<>();
+ currentWeather = WeatherType.SUNNY;
+ }
+
+ public void addObserver(WeatherObserver obs) {
+ observers.add(obs);
+ }
+
+ public void removeObserver(WeatherObserver obs) {
+ observers.remove(obs);
+ }
+
+ /**
+ * Makes time pass for weather.
+ */
+ public void timePasses() {
+ var enumValues = WeatherType.values();
+ currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
+ LOGGER.info("The weather changed to {}.", currentWeather);
+ notifyObservers();
+ }
+
+ private void notifyObservers() {
+ for (var obs : observers) {
+ obs.update(currentWeather);
+ }
+ }
+}
+```
+
+Here's the full example in action.
+
+```java
+ var weather = new Weather();
+ weather.addObserver(new Orcs());
+ weather.addObserver(new Hobbits());
+
+ weather.timePasses();
+ // The weather changed to rainy.
+ // The orcs are dripping wet.
+ // The hobbits look for cover from the rain.
+ weather.timePasses();
+ // The weather changed to windy.
+ // The orc smell almost vanishes in the wind.
+ // The hobbits hold their hats tightly in the windy weather.
+ weather.timePasses();
+ // The weather changed to cold.
+ // The orcs are freezing cold.
+ // The hobbits are shivering in the cold weather.
+ weather.timePasses();
+ // The weather changed to sunny.
+ //The sun hurts the orcs' eyes.
+ // The happy hobbits bade in the warm sun.
+```
## Class diagram

From d2724e8091d3d12b451dabfac2411eebf0df0fc9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 19 Jul 2020 17:34:58 +0300
Subject: [PATCH 015/225] #590 add explanation for Strategy
---
strategy/README.md | 103 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 100 insertions(+), 3 deletions(-)
diff --git a/strategy/README.md b/strategy/README.md
index c78753535..21ac1c94b 100644
--- a/strategy/README.md
+++ b/strategy/README.md
@@ -12,9 +12,106 @@ tags:
Policy
## Intent
-Define a family of algorithms, encapsulate each one, and make them
-interchangeable. Strategy lets the algorithm vary independently from clients
-that use it.
+Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary
+independently from clients that use it.
+
+## Explanation
+
+Real world example
+
+> Slaying dragons is a dangerous profession. With experience it becomes easier. Veteran dragonslayers have developed different fighting strategies against different types of dragons.
+
+In plain words
+
+> Strategy pattern allows choosing the best suited algorithm at runtime.
+
+Wikipedia says
+
+> In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime.
+
+**Programmatic Example**
+
+Let's first introduce the dragon slaying strategy interface and its implementations.
+
+```java
+@FunctionalInterface
+public interface DragonSlayingStrategy {
+
+ void execute();
+}
+
+public class MeleeStrategy implements DragonSlayingStrategy {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(MeleeStrategy.class);
+
+ @Override
+ public void execute() {
+ LOGGER.info("With your Excalibur you sever the dragon's head!");
+ }
+}
+
+public class ProjectileStrategy implements DragonSlayingStrategy {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ProjectileStrategy.class);
+
+ @Override
+ public void execute() {
+ LOGGER.info("You shoot the dragon with the magical crossbow and it falls dead on the ground!");
+ }
+}
+
+public class SpellStrategy implements DragonSlayingStrategy {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SpellStrategy.class);
+
+ @Override
+ public void execute() {
+ LOGGER.info("You cast the spell of disintegration and the dragon vaporizes in a pile of dust!");
+ }
+}
+```
+
+And here is the mighty dragonslayer who is able to pick his fighting strategy based on the opponent.
+
+```java
+public class DragonSlayer {
+
+ private DragonSlayingStrategy strategy;
+
+ public DragonSlayer(DragonSlayingStrategy strategy) {
+ this.strategy = strategy;
+ }
+
+ public void changeStrategy(DragonSlayingStrategy strategy) {
+ this.strategy = strategy;
+ }
+
+ public void goToBattle() {
+ strategy.execute();
+ }
+}
+```
+
+Finally here's dragonslayer in action.
+
+```java
+ LOGGER.info("Green dragon spotted ahead!");
+ var dragonSlayer = new DragonSlayer(new MeleeStrategy());
+ dragonSlayer.goToBattle();
+ LOGGER.info("Red dragon emerges.");
+ dragonSlayer.changeStrategy(new ProjectileStrategy());
+ dragonSlayer.goToBattle();
+ LOGGER.info("Black dragon lands before you.");
+ dragonSlayer.changeStrategy(new SpellStrategy());
+ dragonSlayer.goToBattle();
+
+ // Green dragon spotted ahead!
+ // With your Excalibur you sever the dragon's head!
+ // Red dragon emerges.
+ // You shoot the dragon with the magical crossbow and it falls dead on the ground!
+ // Black dragon lands before you.
+ // You cast the spell of disintegration and the dragon vaporizes in a pile of dust!
+```
## Class diagram

From 4d95d38b8d3a2c1b7b9d60bbf338635ecfed4164 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 19 Jul 2020 19:37:40 +0300
Subject: [PATCH 016/225] #590 explanation for Multiton
---
multiton/README.md | 84 ++++++++++++++++++++++++++++++++++++++++++++--
observer/README.md | 2 +-
2 files changed, 83 insertions(+), 3 deletions(-)
diff --git a/multiton/README.md b/multiton/README.md
index 4387cf7ac..ec1429a8f 100644
--- a/multiton/README.md
+++ b/multiton/README.md
@@ -12,8 +12,88 @@ tags:
Registry
## Intent
-Ensure a class only has limited number of instances, and provide a
-global point of access to them.
+Ensure a class only has limited number of instances and provide a global point of access to them.
+
+## Explanation
+
+Real world example
+
+> The Nazgûl, also called ringwraiths or the Nine Riders, are Sauron's most terrible servants. By definition there's always nine of them.
+
+In plain words
+
+> Multiton pattern ensures there's predefined amount of instances available globally.
+
+Wikipedia says
+
+> In software engineering, the multiton pattern is a design pattern which generalizes the singleton pattern. Whereas the singleton allows only one instance of a class to be created, the multiton pattern allows for the controlled creation of multiple instances, which it manages through the use of a map.
+
+**Programmatic Example**
+
+Nazgul is the multiton class.
+
+```java
+public enum NazgulName {
+
+ KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA;
+}
+
+public final class Nazgul {
+
+ private static Map nazguls;
+
+ private NazgulName name;
+
+ static {
+ nazguls = new ConcurrentHashMap<>();
+ nazguls.put(NazgulName.KHAMUL, new Nazgul(NazgulName.KHAMUL));
+ nazguls.put(NazgulName.MURAZOR, new Nazgul(NazgulName.MURAZOR));
+ nazguls.put(NazgulName.DWAR, new Nazgul(NazgulName.DWAR));
+ nazguls.put(NazgulName.JI_INDUR, new Nazgul(NazgulName.JI_INDUR));
+ nazguls.put(NazgulName.AKHORAHIL, new Nazgul(NazgulName.AKHORAHIL));
+ nazguls.put(NazgulName.HOARMURATH, new Nazgul(NazgulName.HOARMURATH));
+ nazguls.put(NazgulName.ADUNAPHEL, new Nazgul(NazgulName.ADUNAPHEL));
+ nazguls.put(NazgulName.REN, new Nazgul(NazgulName.REN));
+ nazguls.put(NazgulName.UVATHA, new Nazgul(NazgulName.UVATHA));
+ }
+
+ private Nazgul(NazgulName name) {
+ this.name = name;
+ }
+
+ public static Nazgul getInstance(NazgulName name) {
+ return nazguls.get(name);
+ }
+
+ public NazgulName getName() {
+ return name;
+ }
+}
+```
+
+And here's how we access the Nazgul instances.
+
+```java
+ LOGGER.info("KHAMUL={}", Nazgul.getInstance(NazgulName.KHAMUL));
+ LOGGER.info("MURAZOR={}", Nazgul.getInstance(NazgulName.MURAZOR));
+ LOGGER.info("DWAR={}", Nazgul.getInstance(NazgulName.DWAR));
+ LOGGER.info("JI_INDUR={}", Nazgul.getInstance(NazgulName.JI_INDUR));
+ LOGGER.info("AKHORAHIL={}", Nazgul.getInstance(NazgulName.AKHORAHIL));
+ LOGGER.info("HOARMURATH={}", Nazgul.getInstance(NazgulName.HOARMURATH));
+ LOGGER.info("ADUNAPHEL={}", Nazgul.getInstance(NazgulName.ADUNAPHEL));
+ LOGGER.info("REN={}", Nazgul.getInstance(NazgulName.REN));
+ LOGGER.info("UVATHA={}", Nazgul.getInstance(NazgulName.UVATHA));
+
+ // KHAMUL=com.iluwatar.multiton.Nazgul@2b214b94
+ // MURAZOR=com.iluwatar.multiton.Nazgul@17814b1c
+ // DWAR=com.iluwatar.multiton.Nazgul@7ac9af2a
+ // JI_INDUR=com.iluwatar.multiton.Nazgul@7bb004b8
+ // AKHORAHIL=com.iluwatar.multiton.Nazgul@78e89bfe
+ // HOARMURATH=com.iluwatar.multiton.Nazgul@652ce654
+ // ADUNAPHEL=com.iluwatar.multiton.Nazgul@522ba524
+ // REN=com.iluwatar.multiton.Nazgul@29c5ee1d
+ // UVATHA=com.iluwatar.multiton.Nazgul@15cea7b0
+```
## Class diagram

diff --git a/observer/README.md b/observer/README.md
index 5d76ab61f..edc72ae24 100644
--- a/observer/README.md
+++ b/observer/README.md
@@ -153,7 +153,7 @@ Here's the full example in action.
// The hobbits are shivering in the cold weather.
weather.timePasses();
// The weather changed to sunny.
- //The sun hurts the orcs' eyes.
+ // The sun hurts the orcs' eyes.
// The happy hobbits bade in the warm sun.
```
From e34de39ae72f6e3a2ff0f1b2be743e4a4cb1831c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 19 Jul 2020 19:53:31 +0300
Subject: [PATCH 017/225] #590 explanation for Null Object
---
null-object/README.md | 137 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 137 insertions(+)
diff --git a/null-object/README.md b/null-object/README.md
index 184e903a0..0fce86f0e 100644
--- a/null-object/README.md
+++ b/null-object/README.md
@@ -18,6 +18,143 @@ implements the expected interface, but whose method body is empty. The
advantage of this approach over a working default implementation is that a Null
Object is very predictable and has no side effects: it does nothing.
+## Explanation
+
+Real world example
+
+> We are building a binary tree from nodes. There are ordinary nodes and "empty" nodes. Traversing the tree normally should not cause errors, so we use null object pattern where necessary.
+
+In plain words
+
+> Null Object pattern handles "empty" objects gracefully.
+
+Wikipedia says
+
+> In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).
+
+**Programmatic Example**
+
+Here's the definitions for node interface and its implementations.
+
+```java
+public interface Node {
+
+ String getName();
+
+ int getTreeSize();
+
+ Node getLeft();
+
+ Node getRight();
+
+ void walk();
+}
+
+public class NodeImpl implements Node {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NodeImpl.class);
+
+ private final String name;
+ private final Node left;
+ private final Node right;
+
+ /**
+ * Constructor.
+ */
+ public NodeImpl(String name, Node left, Node right) {
+ this.name = name;
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public int getTreeSize() {
+ return 1 + left.getTreeSize() + right.getTreeSize();
+ }
+
+ @Override
+ public Node getLeft() {
+ return left;
+ }
+
+ @Override
+ public Node getRight() {
+ return right;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public void walk() {
+ LOGGER.info(name);
+ if (left.getTreeSize() > 0) {
+ left.walk();
+ }
+ if (right.getTreeSize() > 0) {
+ right.walk();
+ }
+ }
+}
+
+public final class NullNode implements Node {
+
+ private static NullNode instance = new NullNode();
+
+ private NullNode() {
+ }
+
+ public static NullNode getInstance() {
+ return instance;
+ }
+
+ @Override
+ public int getTreeSize() {
+ return 0;
+ }
+
+ @Override
+ public Node getLeft() {
+ return null;
+ }
+
+ @Override
+ public Node getRight() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public void walk() {
+ // Do nothing
+ }
+}
+
+```
+
+Then we can construct and traverse the binary tree without errors as follows.
+
+```java
+ Node root =
+ new NodeImpl("1", new NodeImpl("11", new NodeImpl("111", NullNode.getInstance(),
+ NullNode.getInstance()), NullNode.getInstance()), new NodeImpl("12",
+ NullNode.getInstance(), new NodeImpl("122", NullNode.getInstance(),
+ NullNode.getInstance())));
+ root.walk();
+
+ // 1
+ // 11
+ // 111
+ // 12
+ // 122
+```
+
## Class diagram

From a18c0f76ea07ca5fb4f7dc94e3a6b2537919ca02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 19 Jul 2020 20:23:12 +0300
Subject: [PATCH 018/225] #590 add explanation for Poison Pill
---
poison-pill/README.md | 246 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 244 insertions(+), 2 deletions(-)
diff --git a/poison-pill/README.md b/poison-pill/README.md
index 7fd152891..823bb7df8 100644
--- a/poison-pill/README.md
+++ b/poison-pill/README.md
@@ -10,8 +10,250 @@ tags:
---
## Intent
-Poison Pill is known predefined data item that allows to provide
-graceful shutdown for separate distributed consumption process.
+Poison Pill is known predefined data item that allows to provide graceful shutdown for separate distributed consumption
+process.
+
+## Explanation
+
+Real world example
+
+> Let's think about a message queue with one producer and one consumer. The producer keeps pushing new messages in the queue and the consumer keeps reading them. Finally when it's time to gracefully shut down the producer sends the poison pill message.
+
+In plain words
+
+> Poison Pill is a known message structure that ends the message exchange.
+
+**Programmatic Example**
+
+Let's define the message structure first.
+
+```java
+public interface Message {
+
+ Message POISON_PILL = new Message() {
+
+ @Override
+ public void addHeader(Headers header, String value) {
+ throw poison();
+ }
+
+ @Override
+ public String getHeader(Headers header) {
+ throw poison();
+ }
+
+ @Override
+ public Map getHeaders() {
+ throw poison();
+ }
+
+ @Override
+ public void setBody(String body) {
+ throw poison();
+ }
+
+ @Override
+ public String getBody() {
+ throw poison();
+ }
+
+ private RuntimeException poison() {
+ return new UnsupportedOperationException("Poison");
+ }
+
+ };
+
+ enum Headers {
+ DATE, SENDER
+ }
+
+ void addHeader(Headers header, String value);
+
+ String getHeader(Headers header);
+
+ Map getHeaders();
+
+ void setBody(String body);
+
+ String getBody();
+}
+
+public class SimpleMessage implements Message {
+
+ private Map headers = new HashMap<>();
+ private String body;
+
+ @Override
+ public void addHeader(Headers header, String value) {
+ headers.put(header, value);
+ }
+
+ @Override
+ public String getHeader(Headers header) {
+ return headers.get(header);
+ }
+
+ @Override
+ public Map getHeaders() {
+ return Collections.unmodifiableMap(headers);
+ }
+
+ @Override
+ public void setBody(String body) {
+ this.body = body;
+ }
+
+ @Override
+ public String getBody() {
+ return body;
+ }
+}
+```
+
+Next we define the types related to the message queue.
+
+```java
+public interface MqPublishPoint {
+
+ void put(Message msg) throws InterruptedException;
+}
+
+public interface MqSubscribePoint {
+
+ Message take() throws InterruptedException;
+}
+
+public interface MessageQueue extends MqPublishPoint, MqSubscribePoint {
+}
+
+public class SimpleMessageQueue implements MessageQueue {
+
+ private final BlockingQueue queue;
+
+ public SimpleMessageQueue(int bound) {
+ queue = new ArrayBlockingQueue<>(bound);
+ }
+
+ @Override
+ public void put(Message msg) throws InterruptedException {
+ queue.put(msg);
+ }
+
+ @Override
+ public Message take() throws InterruptedException {
+ return queue.take();
+ }
+}
+```
+
+Now we need to create the message producer and consumer.
+
+```java
+public class Producer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);
+
+ private final MqPublishPoint queue;
+ private final String name;
+ private boolean isStopped;
+
+ /**
+ * Constructor.
+ */
+ public Producer(String name, MqPublishPoint queue) {
+ this.name = name;
+ this.queue = queue;
+ this.isStopped = false;
+ }
+
+ /**
+ * Send message to queue.
+ */
+ public void send(String body) {
+ if (isStopped) {
+ throw new IllegalStateException(String.format(
+ "Producer %s was stopped and fail to deliver requested message [%s].", body, name));
+ }
+ var msg = new SimpleMessage();
+ msg.addHeader(Headers.DATE, new Date().toString());
+ msg.addHeader(Headers.SENDER, name);
+ msg.setBody(body);
+
+ try {
+ queue.put(msg);
+ } catch (InterruptedException e) {
+ // allow thread to exit
+ LOGGER.error("Exception caught.", e);
+ }
+ }
+
+ /**
+ * Stop system by sending poison pill.
+ */
+ public void stop() {
+ isStopped = true;
+ try {
+ queue.put(Message.POISON_PILL);
+ } catch (InterruptedException e) {
+ // allow thread to exit
+ LOGGER.error("Exception caught.", e);
+ }
+ }
+}
+
+public class Consumer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class);
+
+ private final MqSubscribePoint queue;
+ private final String name;
+
+ public Consumer(String name, MqSubscribePoint queue) {
+ this.name = name;
+ this.queue = queue;
+ }
+
+ /**
+ * Consume message.
+ */
+ public void consume() {
+ while (true) {
+ try {
+ var msg = queue.take();
+ if (Message.POISON_PILL.equals(msg)) {
+ LOGGER.info("Consumer {} receive request to terminate.", name);
+ break;
+ }
+ var sender = msg.getHeader(Headers.SENDER);
+ var body = msg.getBody();
+ LOGGER.info("Message [{}] from [{}] received by [{}]", body, sender, name);
+ } catch (InterruptedException e) {
+ // allow thread to exit
+ LOGGER.error("Exception caught.", e);
+ return;
+ }
+ }
+ }
+}
+```
+
+Finally we are ready to present the whole example in action.
+
+```java
+ var queue = new SimpleMessageQueue(10000);
+
+ final var producer = new Producer("PRODUCER_1", queue);
+ final var consumer = new Consumer("CONSUMER_1", queue);
+
+ new Thread(consumer::consume).start();
+
+ new Thread(() -> {
+ producer.send("hand shake");
+ producer.send("some very important information");
+ producer.send("bye!");
+ producer.stop();
+ }).start();
+```
## Class diagram

From 467f647ca266306d72f35749c661d0867efd1dfb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Mon, 20 Jul 2020 17:31:58 +0300
Subject: [PATCH 019/225] #590 add explanation for Repository
---
repository/README.md | 236 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 231 insertions(+), 5 deletions(-)
diff --git a/repository/README.md b/repository/README.md
index 7b5258ea5..09a9a2bba 100644
--- a/repository/README.md
+++ b/repository/README.md
@@ -9,11 +9,236 @@ tags:
---
## Intent
-Repository layer is added between the domain and data mapping
-layers to isolate domain objects from details of the database access code and
-to minimize scattering and duplication of query code. The Repository pattern is
-especially useful in systems where number of domain classes is large or heavy
-querying is utilized.
+Repository layer is added between the domain and data mapping layers to isolate domain objects from details of the
+database access code and to minimize scattering and duplication of query code. The Repository pattern is especially
+useful in systems where number of domain classes is large or heavy querying is utilized.
+
+## Explanation
+Real world example
+
+> Let's say we need a persistent data store for persons. Adding new persons and searching for them according to different criteria must be easy.
+
+In plain words
+
+> Repository architectural pattern creates a uniform layer of data repositories that can be used for CRUD operations.
+
+[Microsoft documentation](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design) says
+
+> Repositories are classes or components that encapsulate the logic required to access data sources. They centralize common data access functionality, providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model layer.
+
+**Programmatic Example**
+
+Let's first look at the person class that we need to persist.
+
+```java
+@Entity
+public class Person {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+ private String name;
+ private String surname;
+
+ private int age;
+
+ public Person() {
+ }
+
+ /**
+ * Constructor.
+ */
+ public Person(String name, String surname, int age) {
+ this.name = name;
+ this.surname = surname;
+ this.age = age;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getSurname() {
+ return surname;
+ }
+
+ public void setSurname(String surname) {
+ this.surname = surname;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ @Override
+ public String toString() {
+ return "Person [id=" + id + ", name=" + name + ", surname=" + surname + ", age=" + age + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final var prime = 31;
+ var result = 1;
+ result = prime * result + age;
+ result = prime * result + (id == null ? 0 : id.hashCode());
+ result = prime * result + (name == null ? 0 : name.hashCode());
+ result = prime * result + (surname == null ? 0 : surname.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ var other = (Person) obj;
+ if (age != other.age) {
+ return false;
+ }
+ if (id == null) {
+ if (other.id != null) {
+ return false;
+ }
+ } else if (!id.equals(other.id)) {
+ return false;
+ }
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ if (surname == null) {
+ return other.surname == null;
+ }
+ return surname.equals(other.surname);
+ }
+}
+```
+
+We are using Spring Data to create the repository so it becomes really simple.
+
+```java
+@Repository
+public interface PersonRepository
+ extends CrudRepository, JpaSpecificationExecutor {
+
+ Person findByName(String name);
+}
+```
+
+Additionally we define a helper class for specification queries.
+
+```java
+public class PersonSpecifications {
+
+ public static class AgeBetweenSpec implements Specification {
+
+ private int from;
+
+ private int to;
+
+ public AgeBetweenSpec(int from, int to) {
+ this.from = from;
+ this.to = to;
+ }
+
+ @Override
+ public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) {
+ return cb.between(root.get("age"), from, to);
+ }
+
+ }
+
+ public static class NameEqualSpec implements Specification {
+
+ public String name;
+
+ public NameEqualSpec(String name) {
+ this.name = name;
+ }
+
+ public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) {
+ return cb.equal(root.get("name"), this.name);
+ }
+ }
+
+}
+```
+
+And here's the repository in action.
+
+```java
+ var peter = new Person("Peter", "Sagan", 17);
+ var nasta = new Person("Nasta", "Kuzminova", 25);
+ var john = new Person("John", "lawrence", 35);
+ var terry = new Person("Terry", "Law", 36);
+
+ repository.save(peter);
+ repository.save(nasta);
+ repository.save(john);
+ repository.save(terry);
+
+ LOGGER.info("Count Person records: {}", repository.count());
+
+ var persons = (List) repository.findAll();
+ persons.stream().map(Person::toString).forEach(LOGGER::info);
+
+ nasta.setName("Barbora");
+ nasta.setSurname("Spotakova");
+ repository.save(nasta);
+
+ repository.findById(2L).ifPresent(p -> LOGGER.info("Find by id 2: {}", p));
+ repository.deleteById(2L);
+
+ LOGGER.info("Count Person records: {}", repository.count());
+
+ repository
+ .findOne(new PersonSpecifications.NameEqualSpec("John"))
+ .ifPresent(p -> LOGGER.info("Find by John is {}", p));
+
+ persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
+
+ LOGGER.info("Find Person with age between 20,40: ");
+ persons.stream().map(Person::toString).forEach(LOGGER::info);
+
+ repository.deleteAll();
+
+ // Count Person records: 4
+ // Person [id=1, name=Peter, surname=Sagan, age=17]
+ // Person [id=2, name=Nasta, surname=Kuzminova, age=25]
+ // Person [id=3, name=John, surname=lawrence, age=35]
+ // Person [id=4, name=Terry, surname=Law, age=36]
+ // Find by id 2: Person [id=2, name=Barbora, surname=Spotakova, age=25]
+ // Count Person records: 3
+ // Find by John is Person [id=3, name=John, surname=lawrence, age=35]
+ // Find Person with age between 20,40:
+ // Person [id=3, name=John, surname=lawrence, age=35]
+ // Person [id=4, name=Terry, surname=Law, age=36]
+```
## Class diagram

@@ -36,3 +261,4 @@ Use the Repository pattern when
* [Advanced Spring Data JPA - Specifications and Querydsl](https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/)
* [Repository Pattern Benefits and Spring Implementation](https://stackoverflow.com/questions/40068965/repository-pattern-benefits-and-spring-implementation)
* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a)
+* [Design patterns that I often avoid: Repository pattern](https://www.infoworld.com/article/3117713/design-patterns-that-i-often-avoid-repository-pattern.html)
From b907a2a9bc41be02e5f375c5bf06055940cdcb60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Mon, 20 Jul 2020 17:52:44 +0300
Subject: [PATCH 020/225] #590 add explanation for Memento
---
memento/README.md | 173 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 171 insertions(+), 2 deletions(-)
diff --git a/memento/README.md b/memento/README.md
index 1bf6e442b..8011dfc49 100644
--- a/memento/README.md
+++ b/memento/README.md
@@ -12,8 +12,177 @@ tags:
Token
## Intent
-Without violating encapsulation, capture and externalize an
-object's internal state so that the object can be restored to this state later.
+Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored
+to this state later.
+
+## Explanation
+Real world example
+
+> We are working on astrology application where we need to analyze star properties over time. We are creating snapshots of star state using Memento pattern.
+
+In plain words
+
+> Memento pattern captures object internal state making it easy to store and restore objects in any point of time.
+
+Wikipedia says
+
+> The memento pattern is a software design pattern that provides the ability to restore an object to its previous state (undo via rollback).
+
+**Programmatic Example**
+
+Let's first define the types of stars we are capable to handle.
+
+```java
+public enum StarType {
+
+ SUN("sun"), RED_GIANT("red giant"), WHITE_DWARF("white dwarf"), SUPERNOVA("supernova"), DEAD(
+ "dead star"), UNDEFINED("");
+
+ private String title;
+
+ StarType(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String toString() {
+ return title;
+ }
+}
+```
+
+Next let's jump straight to the essentials. Here's the star class along with the mementos that we need manipulate.
+
+```java
+public interface StarMemento {
+}
+
+public class Star {
+
+ private StarType type;
+ private int ageYears;
+ private int massTons;
+
+ public Star(StarType startType, int startAge, int startMass) {
+ this.type = startType;
+ this.ageYears = startAge;
+ this.massTons = startMass;
+ }
+
+ public void timePasses() {
+ ageYears *= 2;
+ massTons *= 8;
+ switch (type) {
+ case RED_GIANT:
+ type = StarType.WHITE_DWARF;
+ break;
+ case SUN:
+ type = StarType.RED_GIANT;
+ break;
+ case SUPERNOVA:
+ type = StarType.DEAD;
+ break;
+ case WHITE_DWARF:
+ type = StarType.SUPERNOVA;
+ break;
+ case DEAD:
+ ageYears *= 2;
+ massTons = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ StarMemento getMemento() {
+
+ StarMementoInternal state = new StarMementoInternal();
+ state.setAgeYears(ageYears);
+ state.setMassTons(massTons);
+ state.setType(type);
+ return state;
+ }
+
+ void setMemento(StarMemento memento) {
+
+ StarMementoInternal state = (StarMementoInternal) memento;
+ this.type = state.getType();
+ this.ageYears = state.getAgeYears();
+ this.massTons = state.getMassTons();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s age: %d years mass: %d tons", type.toString(), ageYears, massTons);
+ }
+
+ private static class StarMementoInternal implements StarMemento {
+
+ private StarType type;
+ private int ageYears;
+ private int massTons;
+
+ public StarType getType() {
+ return type;
+ }
+
+ public void setType(StarType type) {
+ this.type = type;
+ }
+
+ public int getAgeYears() {
+ return ageYears;
+ }
+
+ public void setAgeYears(int ageYears) {
+ this.ageYears = ageYears;
+ }
+
+ public int getMassTons() {
+ return massTons;
+ }
+
+ public void setMassTons(int massTons) {
+ this.massTons = massTons;
+ }
+ }
+}
+```
+
+And finally here's how we use the mementos to store and restore star states.
+
+```java
+ Stack states = new Stack<>();
+ Star star = new Star(StarType.SUN, 10000000, 500000);
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ while (states.size() > 0) {
+ star.setMemento(states.pop());
+ LOGGER.info(star.toString());
+ }
+
+ // sun age: 10000000 years mass: 500000 tons
+ // red giant age: 20000000 years mass: 4000000 tons
+ // white dwarf age: 40000000 years mass: 32000000 tons
+ // supernova age: 80000000 years mass: 256000000 tons
+ // dead star age: 160000000 years mass: 2048000000 tons
+ // supernova age: 80000000 years mass: 256000000 tons
+ // white dwarf age: 40000000 years mass: 32000000 tons
+ // red giant age: 20000000 years mass: 4000000 tons
+ // sun age: 10000000 years mass: 500000 tons
+```
+
## Class diagram

From ab4e53a468fe1de6dc0ad731e2308ad80d37465c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Mon, 20 Jul 2020 20:06:39 +0300
Subject: [PATCH 021/225] #590 add explanation for State
---
state/README.md | 122 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 120 insertions(+), 2 deletions(-)
diff --git a/state/README.md b/state/README.md
index 4f61d3025..7be4d3351 100644
--- a/state/README.md
+++ b/state/README.md
@@ -12,8 +12,126 @@ tags:
Objects for States
## Intent
-Allow an object to alter its behavior when its internal state
-changes. The object will appear to change its class.
+Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
+
+## Explanation
+Real world example
+
+> When observing a mammoth in its natural habitat it seems to change its behavior based on the situation. It may first appear calm but over time when it detects a threat it gets angry and dangerous to its surroundings.
+
+In plain words
+
+> State pattern allows an object to change its behavior.
+
+Wikipedia says
+
+> The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. This pattern is close to the concept of finite-state machines. The state pattern can be interpreted as a strategy pattern, which is able to switch a strategy through invocations of methods defined in the pattern's interface.
+
+**Programmatic Example**
+
+Here is the state interface and its concrete implementations.
+
+```java
+public interface State {
+
+ void onEnterState();
+
+ void observe();
+}
+
+public class PeacefulState implements State {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PeacefulState.class);
+
+ private Mammoth mammoth;
+
+ public PeacefulState(Mammoth mammoth) {
+ this.mammoth = mammoth;
+ }
+
+ @Override
+ public void observe() {
+ LOGGER.info("{} is calm and peaceful.", mammoth);
+ }
+
+ @Override
+ public void onEnterState() {
+ LOGGER.info("{} calms down.", mammoth);
+ }
+}
+
+public class AngryState implements State {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AngryState.class);
+
+ private Mammoth mammoth;
+
+ public AngryState(Mammoth mammoth) {
+ this.mammoth = mammoth;
+ }
+
+ @Override
+ public void observe() {
+ LOGGER.info("{} is furious!", mammoth);
+ }
+
+ @Override
+ public void onEnterState() {
+ LOGGER.info("{} gets angry!", mammoth);
+ }
+}
+```
+
+And here is the mammoth containing the state.
+
+```java
+public class Mammoth {
+
+ private State state;
+
+ public Mammoth() {
+ state = new PeacefulState(this);
+ }
+
+ public void timePasses() {
+ if (state.getClass().equals(PeacefulState.class)) {
+ changeStateTo(new AngryState(this));
+ } else {
+ changeStateTo(new PeacefulState(this));
+ }
+ }
+
+ private void changeStateTo(State newState) {
+ this.state = newState;
+ this.state.onEnterState();
+ }
+
+ @Override
+ public String toString() {
+ return "The mammoth";
+ }
+
+ public void observe() {
+ this.state.observe();
+ }
+}
+```
+
+And here is the full example how the mammoth behaves over time.
+
+```java
+ var mammoth = new Mammoth();
+ mammoth.observe();
+ mammoth.timePasses();
+ mammoth.observe();
+ mammoth.timePasses();
+ mammoth.observe();
+
+ // The mammoth gets angry!
+ // The mammoth is furious!
+ // The mammoth calms down.
+ // The mammoth is calm and peaceful.
+```
## Class diagram

From 172964e75c1c299e19b38b9058db77aabcd5f1e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Mon, 20 Jul 2020 20:23:39 +0300
Subject: [PATCH 022/225] #590 explanation for Template Method
---
template-method/README.md | 112 ++++++++++++++++++++++++++++++++++++--
1 file changed, 108 insertions(+), 4 deletions(-)
diff --git a/template-method/README.md b/template-method/README.md
index e87cfd6de..695644488 100644
--- a/template-method/README.md
+++ b/template-method/README.md
@@ -9,11 +9,115 @@ tags:
---
## Intent
-Define the skeleton of an algorithm in an operation, deferring some
-steps to subclasses. Template method lets subclasses redefine certain steps of
-an algorithm without changing the algorithm's structure.
+Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets
+subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
-To make sure that subclasses don’t override the template method, the template method should be declared `final`.
+## Explanation
+Real world example
+
+> The general steps in stealing an item are the same. First you pick the target, next you confuse him somehow and finally you steal the item. However there are many ways to implement these steps.
+
+In plain words
+
+> Template Method pattern outlines the general steps in the parent class and lets the concrete child implementations define the details.
+
+Wikipedia says
+
+> In object-oriented programming, the template method is one of the behavioral design patterns identified by Gamma et al. in the book Design Patterns. The template method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps. These steps are themselves implemented by additional helper methods in the same class as the template method.
+
+**Programmatic Example**
+
+Let's first introduce the template method class along with its concrete implementations.
+
+```java
+public abstract class StealingMethod {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(StealingMethod.class);
+
+ protected abstract String pickTarget();
+
+ protected abstract void confuseTarget(String target);
+
+ protected abstract void stealTheItem(String target);
+
+ public void steal() {
+ var target = pickTarget();
+ LOGGER.info("The target has been chosen as {}.", target);
+ confuseTarget(target);
+ stealTheItem(target);
+ }
+}
+
+public class SubtleMethod extends StealingMethod {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SubtleMethod.class);
+
+ @Override
+ protected String pickTarget() {
+ return "shop keeper";
+ }
+
+ @Override
+ protected void confuseTarget(String target) {
+ LOGGER.info("Approach the {} with tears running and hug him!", target);
+ }
+
+ @Override
+ protected void stealTheItem(String target) {
+ LOGGER.info("While in close contact grab the {}'s wallet.", target);
+ }
+}
+
+public class HitAndRunMethod extends StealingMethod {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HitAndRunMethod.class);
+
+ @Override
+ protected String pickTarget() {
+ return "old goblin woman";
+ }
+
+ @Override
+ protected void confuseTarget(String target) {
+ LOGGER.info("Approach the {} from behind.", target);
+ }
+
+ @Override
+ protected void stealTheItem(String target) {
+ LOGGER.info("Grab the handbag and run away fast!");
+ }
+}
+```
+
+Here's the halfling thief class containing the template method.
+
+```java
+public class HalflingThief {
+
+ private StealingMethod method;
+
+ public HalflingThief(StealingMethod method) {
+ this.method = method;
+ }
+
+ public void steal() {
+ method.steal();
+ }
+
+ public void changeMethod(StealingMethod method) {
+ this.method = method;
+ }
+}
+```
+
+And finally we show how the halfling thief utilizes the different stealing methods.
+
+```java
+ var thief = new HalflingThief(new HitAndRunMethod());
+ thief.steal();
+ thief.changeMethod(new SubtleMethod());
+ thief.steal();
+```
## Class diagram

From 6c2114330396b579efedfec610362bf1a50014d0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Tue, 21 Jul 2020 20:04:06 +0300
Subject: [PATCH 023/225] #590 add explanation for Dependency Injection
---
dependency-injection/README.md | 89 +++++++++++++++++++++++++++++++---
1 file changed, 81 insertions(+), 8 deletions(-)
diff --git a/dependency-injection/README.md b/dependency-injection/README.md
index 90edd4061..abf647b50 100644
--- a/dependency-injection/README.md
+++ b/dependency-injection/README.md
@@ -9,12 +9,78 @@ tags:
---
## Intent
-Dependency Injection is a software design pattern in which one or
-more dependencies (or services) are injected, or passed by reference, into a
-dependent object (or client) and are made part of the client's state. The
-pattern separates the creation of a client's dependencies from its own
-behavior, which allows program designs to be loosely coupled and to follow the
-inversion of control and single responsibility principles.
+Dependency Injection is a software design pattern in which one or more dependencies (or services) are injected, or
+passed by reference, into a dependent object (or client) and are made part of the client's state. The pattern separates
+the creation of a client's dependencies from its own behavior, which allows program designs to be loosely coupled and
+to follow the inversion of control and single responsibility principles.
+
+## Explanation
+Real world example
+
+> The old wizard likes to fill his pipe and smoke tobacco once in a while. However, he doesn't want to depend on a single tobacco brand only but likes to be able to enjoy them all interchangeably.
+
+In plain words
+
+> Dependency Injection separates creation of client's dependencies from its own behavior.
+
+Wikipedia says
+
+> In software engineering, dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies.
+
+**Programmatic Example**
+
+Let's first introduce the tobacco brands.
+
+```java
+public abstract class Tobacco {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Tobacco.class);
+
+ public void smoke(Wizard wizard) {
+ LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(),
+ this.getClass().getSimpleName());
+ }
+}
+
+public class SecondBreakfastTobacco extends Tobacco {
+}
+
+public class RivendellTobacco extends Tobacco {
+}
+
+public class OldTobyTobacco extends Tobacco {
+}
+```
+
+Next here's the wizard class hierarchy.
+
+```java
+public interface Wizard {
+
+ void smoke();
+}
+
+public class AdvancedWizard implements Wizard {
+
+ private Tobacco tobacco;
+
+ public AdvancedWizard(Tobacco tobacco) {
+ this.tobacco = tobacco;
+ }
+
+ @Override
+ public void smoke() {
+ tobacco.smoke(this);
+ }
+}
+```
+
+And lastly we can show how easy it is to give the old wizard any brand of tobacco.
+
+```java
+ var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco());
+ advancedWizard.smoke();
+```
## Class diagram

@@ -22,5 +88,12 @@ inversion of control and single responsibility principles.
## Applicability
Use the Dependency Injection pattern when
-* when you need to remove knowledge of concrete implementation from object
-* to enable unit testing of classes in isolation using mock objects or stubs
+* When you need to remove knowledge of concrete implementation from object
+* To enable unit testing of classes in isolation using mock objects or stubs
+
+## Credits
+
+* [Dependency Injection Principles, Practices, and Patterns](https://www.amazon.com/gp/product/161729473X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=161729473X&linkId=57079257a5c7d33755493802f3b884bd)
+* [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0132350882&linkCode=as2&tag=javadesignpat-20&linkId=2c390d89cc9e61c01b9e7005c7842871)
+* [Java 9 Dependency Injection: Write loosely coupled code with Spring 5 and Guice](https://www.amazon.com/gp/product/1788296257/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1788296257&linkId=4e9137a3bf722a8b5b156cce1eec0fc1)
+* [Google Guice Tutorial: Open source Java based dependency injection framework](https://www.amazon.com/gp/product/B083P7DZ8M/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B083P7DZ8M&linkId=04f0f902c877921e45215b624a124bfe)
From 082d63a1b3186bc9dcd60fd2fa0b0f66d90dcf49 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Tue, 21 Jul 2020 22:57:11 +0300
Subject: [PATCH 024/225] #590 add explanation for Tolerant Reader
---
tolerant-reader/README.md | 188 +++++++++++++++++++++++++++++++++++++-
1 file changed, 184 insertions(+), 4 deletions(-)
diff --git a/tolerant-reader/README.md b/tolerant-reader/README.md
index c60e75707..a62e5f4cd 100644
--- a/tolerant-reader/README.md
+++ b/tolerant-reader/README.md
@@ -9,10 +9,189 @@ tags:
---
## Intent
-Tolerant Reader is an integration pattern that helps creating
-robust communication systems. The idea is to be as tolerant as possible when
-reading data from another service. This way, when the communication schema
-changes, the readers must not break.
+Tolerant Reader is an integration pattern that helps creating robust communication systems. The idea is to be as
+tolerant as possible when reading data from another service. This way, when the communication schema changes, the
+readers must not break.
+
+## Explanation
+Real world example
+
+> We are persisting rainbowfish objects to file and later on they need to be restored. What makes it problematic is that rainbowfish data structure is versioned and evolves over time. New version of rainbowfish needs to be able to restore old versions as well.
+
+In plain words
+
+> Tolerant Reader pattern is used to create robust communication mechanisms between services.
+
+[Robustness Principle](https://java-design-patterns.com/principles/#robustness-principle) says
+
+> Be conservative in what you do, be liberal in what you accept from others
+
+**Programmatic Example**
+
+Here's the versioned rainbowfish. Notice how the second version introduces additional properties.
+
+```java
+public class RainbowFish implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private String name;
+ private int age;
+ private int lengthMeters;
+ private int weightTons;
+
+ /**
+ * Constructor.
+ */
+ public RainbowFish(String name, int age, int lengthMeters, int weightTons) {
+ this.name = name;
+ this.age = age;
+ this.lengthMeters = lengthMeters;
+ this.weightTons = weightTons;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public int getLengthMeters() {
+ return lengthMeters;
+ }
+
+ public int getWeightTons() {
+ return weightTons;
+ }
+}
+
+public class RainbowFishV2 extends RainbowFish {
+
+ private static final long serialVersionUID = 1L;
+
+ private boolean sleeping;
+ private boolean hungry;
+ private boolean angry;
+
+ public RainbowFishV2(String name, int age, int lengthMeters, int weightTons) {
+ super(name, age, lengthMeters, weightTons);
+ }
+
+ /**
+ * Constructor.
+ */
+ public RainbowFishV2(String name, int age, int lengthMeters, int weightTons, boolean sleeping,
+ boolean hungry, boolean angry) {
+ this(name, age, lengthMeters, weightTons);
+ this.sleeping = sleeping;
+ this.hungry = hungry;
+ this.angry = angry;
+ }
+
+ public boolean getSleeping() {
+ return sleeping;
+ }
+
+ public boolean getHungry() {
+ return hungry;
+ }
+
+ public boolean getAngry() {
+ return angry;
+ }
+}
+```
+
+Next we introduce the rainbowfish serializer. This is the class that implements the Tolerant Reader pattern.
+
+```java
+public final class RainbowFishSerializer {
+
+ private RainbowFishSerializer() {
+ }
+
+ public static void writeV1(RainbowFish rainbowFish, String filename) throws IOException {
+ var map = Map.of(
+ "name", rainbowFish.getName(),
+ "age", String.format("%d", rainbowFish.getAge()),
+ "lengthMeters", String.format("%d", rainbowFish.getLengthMeters()),
+ "weightTons", String.format("%d", rainbowFish.getWeightTons())
+ );
+
+ try (var fileOut = new FileOutputStream(filename);
+ var objOut = new ObjectOutputStream(fileOut)) {
+ objOut.writeObject(map);
+ }
+ }
+
+ public static void writeV2(RainbowFishV2 rainbowFish, String filename) throws IOException {
+ var map = Map.of(
+ "name", rainbowFish.getName(),
+ "age", String.format("%d", rainbowFish.getAge()),
+ "lengthMeters", String.format("%d", rainbowFish.getLengthMeters()),
+ "weightTons", String.format("%d", rainbowFish.getWeightTons()),
+ "angry", Boolean.toString(rainbowFish.getAngry()),
+ "hungry", Boolean.toString(rainbowFish.getHungry()),
+ "sleeping", Boolean.toString(rainbowFish.getSleeping())
+ );
+
+ try (var fileOut = new FileOutputStream(filename);
+ var objOut = new ObjectOutputStream(fileOut)) {
+ objOut.writeObject(map);
+ }
+ }
+
+ public static RainbowFish readV1(String filename) throws IOException, ClassNotFoundException {
+ Map map;
+
+ try (var fileIn = new FileInputStream(filename);
+ var objIn = new ObjectInputStream(fileIn)) {
+ map = (Map) objIn.readObject();
+ }
+
+ return new RainbowFish(
+ map.get("name"),
+ Integer.parseInt(map.get("age")),
+ Integer.parseInt(map.get("lengthMeters")),
+ Integer.parseInt(map.get("weightTons"))
+ );
+ }
+}
+```
+
+And finally here's the full example in action.
+
+```java
+ var fishV1 = new RainbowFish("Zed", 10, 11, 12);
+ LOGGER.info("fishV1 name={} age={} length={} weight={}", fishV1.getName(),
+ fishV1.getAge(), fishV1.getLengthMeters(), fishV1.getWeightTons());
+ RainbowFishSerializer.writeV1(fishV1, "fish1.out");
+
+ var deserializedRainbowFishV1 = RainbowFishSerializer.readV1("fish1.out");
+ LOGGER.info("deserializedFishV1 name={} age={} length={} weight={}",
+ deserializedRainbowFishV1.getName(), deserializedRainbowFishV1.getAge(),
+ deserializedRainbowFishV1.getLengthMeters(), deserializedRainbowFishV1.getWeightTons());
+
+ var fishV2 = new RainbowFishV2("Scar", 5, 12, 15, true, true, true);
+ LOGGER.info(
+ "fishV2 name={} age={} length={} weight={} sleeping={} hungry={} angry={}",
+ fishV2.getName(), fishV2.getAge(), fishV2.getLengthMeters(), fishV2.getWeightTons(),
+ fishV2.getHungry(), fishV2.getAngry(), fishV2.getSleeping());
+ RainbowFishSerializer.writeV2(fishV2, "fish2.out");
+
+ var deserializedFishV2 = RainbowFishSerializer.readV1("fish2.out");
+ LOGGER.info("deserializedFishV2 name={} age={} length={} weight={}",
+ deserializedFishV2.getName(), deserializedFishV2.getAge(),
+ deserializedFishV2.getLengthMeters(), deserializedFishV2.getWeightTons());
+
+ // fishV1 name=Zed age=10 length=11 weight=12
+ // deserializedFishV1 name=Zed age=10 length=11 weight=12
+ // fishV2 name=Scar age=5 length=12 weight=15 sleeping=true hungry=true angry=true
+ // deserializedFishV2 name=Scar age=5 length=12 weight=15
+```
+
## Class diagram

@@ -25,3 +204,4 @@ Use the Tolerant Reader pattern when
## Credits
* [Martin Fowler - Tolerant Reader](http://martinfowler.com/bliki/TolerantReader.html)
+* [Service Design Patterns: Fundamental Design Solutions for SOAP/WSDL and RESTful Web Services](https://www.amazon.com/gp/product/032154420X/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=032154420X&linkId=94f9516e747ac2b449a959d5b096c73c)
From 8982392feaf0e65777fe615936345600ab238294 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Wed, 22 Jul 2020 20:31:56 +0300
Subject: [PATCH 025/225] #590 add explanation for Throttling
---
throttling/README.md | 163 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 163 insertions(+)
diff --git a/throttling/README.md b/throttling/README.md
index 12090c5e3..f3ef43c17 100644
--- a/throttling/README.md
+++ b/throttling/README.md
@@ -11,6 +11,164 @@ tags:
## Intent
Ensure that a given client is not able to access service resources more than the assigned limit.
+## Explanation
+Real world example
+
+> A large multinational corporation offers API to its customers. The API is rate-limited and each customer can only make certain amount of calls per second.
+
+In plain words
+
+> Throttling pattern is used to rate-limit access to a resource.
+
+[Microsoft documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/throttling) says
+
+> Control the consumption of resources used by an instance of an application, an individual tenant, or an entire service. This can allow the system to continue to function and meet service level agreements, even when an increase in demand places an extreme load on resources.
+
+**Programmatic Example**
+
+Tenant class presents the clients of the API. CallsCount tracks the number of API calls per tenant.
+
+```java
+public class Tenant {
+
+ private String name;
+ private int allowedCallsPerSecond;
+
+ public Tenant(String name, int allowedCallsPerSecond, CallsCount callsCount) {
+ if (allowedCallsPerSecond < 0) {
+ throw new InvalidParameterException("Number of calls less than 0 not allowed");
+ }
+ this.name = name;
+ this.allowedCallsPerSecond = allowedCallsPerSecond;
+ callsCount.addTenant(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAllowedCallsPerSecond() {
+ return allowedCallsPerSecond;
+ }
+}
+
+public final class CallsCount {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CallsCount.class);
+ private Map tenantCallsCount = new ConcurrentHashMap<>();
+
+ public void addTenant(String tenantName) {
+ tenantCallsCount.putIfAbsent(tenantName, new AtomicLong(0));
+ }
+
+ public void incrementCount(String tenantName) {
+ tenantCallsCount.get(tenantName).incrementAndGet();
+ }
+
+ public long getCount(String tenantName) {
+ return tenantCallsCount.get(tenantName).get();
+ }
+
+ public void reset() {
+ LOGGER.debug("Resetting the map.");
+ tenantCallsCount.replaceAll((k, v) -> new AtomicLong(0));
+ }
+}
+```
+
+Next we introduce the service that the tenants are calling. To track the call count we use the throttler timer.
+
+```java
+public interface Throttler {
+
+ void start();
+}
+
+public class ThrottleTimerImpl implements Throttler {
+
+ private final int throttlePeriod;
+ private final CallsCount callsCount;
+
+ public ThrottleTimerImpl(int throttlePeriod, CallsCount callsCount) {
+ this.throttlePeriod = throttlePeriod;
+ this.callsCount = callsCount;
+ }
+
+ @Override
+ public void start() {
+ new Timer(true).schedule(new TimerTask() {
+ @Override
+ public void run() {
+ callsCount.reset();
+ }
+ }, 0, throttlePeriod);
+ }
+}
+
+class B2BService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(B2BService.class);
+ private final CallsCount callsCount;
+
+ public B2BService(Throttler timer, CallsCount callsCount) {
+ this.callsCount = callsCount;
+ timer.start();
+ }
+
+ public int dummyCustomerApi(Tenant tenant) {
+ var tenantName = tenant.getName();
+ var count = callsCount.getCount(tenantName);
+ LOGGER.debug("Counter for {} : {} ", tenant.getName(), count);
+ if (count >= tenant.getAllowedCallsPerSecond()) {
+ LOGGER.error("API access per second limit reached for: {}", tenantName);
+ return -1;
+ }
+ callsCount.incrementCount(tenantName);
+ return getRandomCustomerId();
+ }
+
+ private int getRandomCustomerId() {
+ return ThreadLocalRandom.current().nextInt(1, 10000);
+ }
+}
+```
+
+Now we are ready to see the full example in action. Tenant Adidas is rate-limited to 5 calls per second and Nike to 6.
+
+```java
+ public static void main(String[] args) {
+ var callsCount = new CallsCount();
+ var adidas = new Tenant("Adidas", 5, callsCount);
+ var nike = new Tenant("Nike", 6, callsCount);
+
+ var executorService = Executors.newFixedThreadPool(2);
+ executorService.execute(() -> makeServiceCalls(adidas, callsCount));
+ executorService.execute(() -> makeServiceCalls(nike, callsCount));
+ executorService.shutdown();
+
+ try {
+ executorService.awaitTermination(10, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ LOGGER.error("Executor Service terminated: {}", e.getMessage());
+ }
+ }
+
+ private static void makeServiceCalls(Tenant tenant, CallsCount callsCount) {
+ var timer = new ThrottleTimerImpl(10, callsCount);
+ var service = new B2BService(timer, callsCount);
+ // Sleep is introduced to keep the output in check and easy to view and analyze the results.
+ IntStream.range(0, 20).forEach(i -> {
+ service.dummyCustomerApi(tenant);
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ LOGGER.error("Thread interrupted: {}", e.getMessage());
+ }
+ });
+ }
+```
+
+
## Class diagram

@@ -19,3 +177,8 @@ The Throttling pattern should be used:
* When a service access needs to be restricted to not have high impacts on the performance of the service.
* When multiple clients are consuming the same service resources and restriction has to be made according to the usage per client.
+
+## Credits
+
+* [Throttling pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/throttling)
+* [Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications (Microsoft patterns & practices)](https://www.amazon.com/gp/product/B00ITGHBBS/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B00ITGHBBS&linkId=12aacdd0cec04f372e7152689525631a)
From 9db997d0aee466000b26c2cd56e2f19e0a6db8f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Wed, 22 Jul 2020 20:59:14 +0300
Subject: [PATCH 026/225] #590 add explanation for Thread Pool
---
thread-pool/README.md | 145 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 145 insertions(+)
diff --git a/thread-pool/README.md b/thread-pool/README.md
index 0e125176d..62a2a3339 100644
--- a/thread-pool/README.md
+++ b/thread-pool/README.md
@@ -15,6 +15,146 @@ the system spend more time creating and destroying the threads than executing
the actual tasks. Thread Pool solves this problem by reusing existing threads
and eliminating the latency of creating new threads.
+## Explanation
+Real world example
+
+> We have a large number of relatively short tasks at hand. We need to peel huge amounts of potatoes and serve mighty amount of coffee cups. Creating a new thread for each task would be a waste so we establish a thread pool.
+
+In plain words
+
+> Thread Pool is a concurrency pattern where threads are allocated once and reused between tasks.
+
+Wikipedia says
+
+> In computer programming, a thread pool is a software design pattern for achieving concurrency of execution in a computer program. Often also called a replicated workers or worker-crew model, a thread pool maintains multiple threads waiting for tasks to be allocated for concurrent execution by the supervising program. By maintaining a pool of threads, the model increases performance and avoids latency in execution due to frequent creation and destruction of threads for short-lived tasks. The number of available threads is tuned to the computing resources available to the program, such as a parallel task queue after completion of execution.
+
+**Programmatic Example**
+
+Let's first look at our task hierarchy. We have a base class and then concrete CoffeeMakingTask and PotatoPeelingTask.
+
+```java
+public abstract class Task {
+
+ private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
+
+ private final int id;
+ private final int timeMs;
+
+ public Task(final int timeMs) {
+ this.id = ID_GENERATOR.incrementAndGet();
+ this.timeMs = timeMs;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public int getTimeMs() {
+ return timeMs;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("id=%d timeMs=%d", id, timeMs);
+ }
+}
+
+public class CoffeeMakingTask extends Task {
+
+ private static final int TIME_PER_CUP = 100;
+
+ public CoffeeMakingTask(int numCups) {
+ super(numCups * TIME_PER_CUP);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s %s", this.getClass().getSimpleName(), super.toString());
+ }
+}
+
+public class PotatoPeelingTask extends Task {
+
+ private static final int TIME_PER_POTATO = 200;
+
+ public PotatoPeelingTask(int numPotatoes) {
+ super(numPotatoes * TIME_PER_POTATO);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s %s", this.getClass().getSimpleName(), super.toString());
+ }
+}
+```
+
+Next we present a runnable Worker class that the thread pool will utilize to handle all the potato peeling and coffee
+making.
+
+```java
+public class Worker implements Runnable {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Worker.class);
+
+ private final Task task;
+
+ public Worker(final Task task) {
+ this.task = task;
+ }
+
+ @Override
+ public void run() {
+ LOGGER.info("{} processing {}", Thread.currentThread().getName(), task.toString());
+ try {
+ Thread.sleep(task.getTimeMs());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+}
+```
+
+Now we are ready to show the full example in action.
+
+```java
+ LOGGER.info("Program started");
+
+ // Create a list of tasks to be executed
+ var tasks = List.of(
+ new PotatoPeelingTask(3),
+ new PotatoPeelingTask(6),
+ new CoffeeMakingTask(2),
+ new CoffeeMakingTask(6),
+ new PotatoPeelingTask(4),
+ new CoffeeMakingTask(2),
+ new PotatoPeelingTask(4),
+ new CoffeeMakingTask(9),
+ new PotatoPeelingTask(3),
+ new CoffeeMakingTask(2),
+ new PotatoPeelingTask(4),
+ new CoffeeMakingTask(2),
+ new CoffeeMakingTask(7),
+ new PotatoPeelingTask(4),
+ new PotatoPeelingTask(5));
+
+ // Creates a thread pool that reuses a fixed number of threads operating off a shared
+ // unbounded queue. At any point, at most nThreads threads will be active processing
+ // tasks. If additional tasks are submitted when all threads are active, they will wait
+ // in the queue until a thread is available.
+ var executor = Executors.newFixedThreadPool(3);
+
+ // Allocate new worker for each task
+ // The worker is executed when a thread becomes
+ // available in the thread pool
+ tasks.stream().map(Worker::new).forEach(executor::execute);
+ // All tasks were executed, now shutdown
+ executor.shutdown();
+ while (!executor.isTerminated()) {
+ Thread.yield();
+ }
+ LOGGER.info("Program finished");
+```
+
## Class diagram

@@ -22,3 +162,8 @@ and eliminating the latency of creating new threads.
Use the Thread Pool pattern when
* You have a large number of short-lived tasks to be executed in parallel
+
+## Credits
+
+* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0134685997&linkId=e1b9ddd5e669591642c4f30d40cd9f6b)
+* [Java Concurrency in Practice](https://www.amazon.com/gp/product/0321349601/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321349601&linkId=fbedb3bad3c6cbead5afa56eea39ed59)
From 1886a6f969b03dbc56c2bc9907b6e41a6c1cfdd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Wed, 22 Jul 2020 21:34:44 +0300
Subject: [PATCH 027/225] #590 add explanation for Game Loop
---
game-loop/README.md | 216 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 205 insertions(+), 11 deletions(-)
diff --git a/game-loop/README.md b/game-loop/README.md
index f0a7eeebb..5f2cd9653 100644
--- a/game-loop/README.md
+++ b/game-loop/README.md
@@ -9,33 +9,227 @@ tags:
---
## Intent
-A game loop runs continuously during gameplay. Each turn of the loop, it processes user input without blocking, updates the game state, and renders the game. It tracks the passage of time to control the rate of gameplay.
+A game loop runs continuously during gameplay. Each turn of the loop, it processes user input without blocking, updates
+the game state, and renders the game. It tracks the passage of time to control the rate of gameplay.
-This pattern decouple the progression of game time from user input and processor speed.
+This pattern decouples progression of game time from user input and processor speed.
## Applicability
This pattern is used in every game engine.
## Explanation
-Game loop is the main process of all the game rendering threads. It drives input process, internal status update, rendering, AI and all the other processes.
+Real world example
-There are a lot of implementations of game loop:
+> Game loop is the main process of all the game rendering threads. It's present in all modern games. It drives input process, internal status update, rendering, AI and all the other processes.
-- Frame-based game loop
+In plain words
-Frame-based game loop is the easiest implementation. The loop always keeps spinning for the following three processes: processInput, update and render. The problem with it is you have no control over how fast the game runs. On a fast machine, that loop will spin so fast users won’t be able to see what’s going on. On a slow machine, the game will crawl. If you have a part of the game that’s content-heavy or does more AI or physics, the game will actually play slower there.
+> Game Loop pattern ensures that game time progresses in equal speed in all different hardware setups.
-- Variable-step game loop
+Wikipedia says
-The variable-step game loop chooses a time step to advance based on how much real time passed since the last frame. The longer the frame takes, the bigger steps the game takes. It always keeps up with real time because it will take bigger and bigger steps to get there.
+> The central component of any game, from a programming standpoint, is the game loop. The game loop allows the game to run smoothly regardless of a user's input or lack thereof.
-- Fixed-step game loop
+**Programmatic Example**
-For fixed-step game loop, a certain amount of real time has elapsed since the last turn of the game loop. This is how much game time need to be simulated for the game’s “now” to catch up with the player’s.
+Let's start with something simple. Here's a bullet that will move in our game. For demonstration it's enough that it has 1-dimensional position.
+
+```java
+public class Bullet {
+
+ private float position;
+
+ public Bullet() {
+ position = 0.0f;
+ }
+
+ public float getPosition() {
+ return position;
+ }
+
+ public void setPosition(float position) {
+ this.position = position;
+ }
+}
+```
+
+GameController is responsible for moving objects in the game. Including the aforementioned bullet.
+
+```java
+public class GameController {
+
+ protected final Bullet bullet;
+
+ public GameController() {
+ bullet = new Bullet();
+ }
+
+ public void moveBullet(float offset) {
+ var currentPosition = bullet.getPosition();
+ bullet.setPosition(currentPosition + offset);
+ }
+
+ public float getBulletPosition() {
+ return bullet.getPosition();
+ }
+}
+```
+
+Now we introduce the game loop. Or actually in this demo we have 3 different game loops.
+
+```java
+public enum GameStatus {
+
+ RUNNING, STOPPED
+}
+
+public abstract class GameLoop {
+
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ protected volatile GameStatus status;
+
+ protected GameController controller;
+
+ private Thread gameThread;
+
+ public GameLoop() {
+ controller = new GameController();
+ status = GameStatus.STOPPED;
+ }
+
+ public void run() {
+ status = GameStatus.RUNNING;
+ gameThread = new Thread(() -> processGameLoop());
+ gameThread.start();
+ }
+
+ public void stop() {
+ status = GameStatus.STOPPED;
+ }
+
+ public boolean isGameRunning() {
+ return status == GameStatus.RUNNING;
+ }
+
+ protected void processInput() {
+ try {
+ var lag = new Random().nextInt(200) + 50;
+ Thread.sleep(lag);
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage());
+ }
+ }
+
+ protected void render() {
+ var position = controller.getBulletPosition();
+ logger.info("Current bullet position: " + position);
+ }
+
+ protected abstract void processGameLoop();
+}
+
+public class FrameBasedGameLoop extends GameLoop {
+
+ @Override
+ protected void processGameLoop() {
+ while (isGameRunning()) {
+ processInput();
+ update();
+ render();
+ }
+ }
+
+ protected void update() {
+ controller.moveBullet(0.5f);
+ }
+}
+
+public class VariableStepGameLoop extends GameLoop {
+
+ @Override
+ protected void processGameLoop() {
+ var lastFrameTime = System.currentTimeMillis();
+ while (isGameRunning()) {
+ processInput();
+ var currentFrameTime = System.currentTimeMillis();
+ var elapsedTime = currentFrameTime - lastFrameTime;
+ update(elapsedTime);
+ lastFrameTime = currentFrameTime;
+ render();
+ }
+ }
+
+ protected void update(Long elapsedTime) {
+ controller.moveBullet(0.5f * elapsedTime / 1000);
+ }
+}
+
+public class FixedStepGameLoop extends GameLoop {
+
+ private static final long MS_PER_FRAME = 20;
+
+ @Override
+ protected void processGameLoop() {
+ var previousTime = System.currentTimeMillis();
+ var lag = 0L;
+ while (isGameRunning()) {
+ var currentTime = System.currentTimeMillis();
+ var elapsedTime = currentTime - previousTime;
+ previousTime = currentTime;
+ lag += elapsedTime;
+
+ processInput();
+
+ while (lag >= MS_PER_FRAME) {
+ update();
+ lag -= MS_PER_FRAME;
+ }
+
+ render();
+ }
+ }
+
+ protected void update() {
+ controller.moveBullet(0.5f * MS_PER_FRAME / 1000);
+ }
+}
+```
+
+Finally we can show all these game loops in action.
+
+```java
+ try {
+ LOGGER.info("Start frame-based game loop:");
+ var frameBasedGameLoop = new FrameBasedGameLoop();
+ frameBasedGameLoop.run();
+ Thread.sleep(GAME_LOOP_DURATION_TIME);
+ frameBasedGameLoop.stop();
+ LOGGER.info("Stop frame-based game loop.");
+
+ LOGGER.info("Start variable-step game loop:");
+ var variableStepGameLoop = new VariableStepGameLoop();
+ variableStepGameLoop.run();
+ Thread.sleep(GAME_LOOP_DURATION_TIME);
+ variableStepGameLoop.stop();
+ LOGGER.info("Stop variable-step game loop.");
+
+ LOGGER.info("Start fixed-step game loop:");
+ var fixedStepGameLoop = new FixedStepGameLoop();
+ fixedStepGameLoop.run();
+ Thread.sleep(GAME_LOOP_DURATION_TIME);
+ fixedStepGameLoop.stop();
+ LOGGER.info("Stop variable-step game loop.");
+
+ } catch (InterruptedException e) {
+ LOGGER.error(e.getMessage());
+ }
+```
## Class diagram

## Credits
-
* [Game Programming Patterns - Game Loop](http://gameprogrammingpatterns.com/game-loop.html)
+* [Game Programming Patterns](https://www.amazon.com/gp/product/0990582906/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0990582906&linkId=1289749a703b3fe0e24cd8d604d7c40b)
+* [Game Engine Architecture, Third Edition](https://www.amazon.com/gp/product/1138035459/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1138035459&linkId=94502746617211bc40e0ef49d29333ac)
From 645fb20730bd7d9381813773abdb269ad95703a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Thu, 23 Jul 2020 17:50:20 +0300
Subject: [PATCH 028/225] #590 improve Retry explanation
---
retry/README.md | 61 ++++++++++++++++++++++++++-----------------------
1 file changed, 32 insertions(+), 29 deletions(-)
diff --git a/retry/README.md b/retry/README.md
index 0f8345412..fa56c1240 100644
--- a/retry/README.md
+++ b/retry/README.md
@@ -8,16 +8,12 @@ tags:
- Performance
---
-## Retry / resiliency
-Enables an application to handle transient failures from external resources.
-
## Intent
-Transparently retry certain operations that involve communication with external
-resources, particularly over the network, isolating calling code from the
-retry implementation details.
+Transparently retry certain operations that involve communication with external resources, particularly over the
+network, isolating calling code from the retry implementation details.
## Explanation
-The `Retry` pattern consists retrying operations on remote resources over the
+Retry pattern consists retrying operations on remote resources over the
network a set number of times. It closely depends on both business and technical
requirements: how much time will the business allow the end user to wait while
the operation finishes? What are the performance characteristics of the
@@ -30,11 +26,7 @@ Another concern is the impact on the calling code by implementing the retry
mechanism. The retry mechanics should ideally be completely transparent to the
calling code (service interface remains unaltered). There are two general
approaches to this problem: from an enterprise architecture standpoint
-(**strategic**), and a shared library standpoint (**tactical**).
-
-*(As an aside, one interesting property is that, since implementations tend to
-be configurable at runtime, daily monitoring and operation of this capability
-is shifted over to operations support instead of the developers themselves.)*
+(strategic), and a shared library standpoint (tactical).
From a strategic point of view, this would be solved by having requests
be redirected to a separate intermediary system, traditionally an
@@ -42,11 +34,26 @@ be redirected to a separate intermediary system, traditionally an
a [Service Mesh](https://medium.com/microservices-in-practice/service-mesh-for-microservices-2953109a3c9a).
From a tactical point of view, this would be solved by reusing shared libraries
-like [Hystrix](https://github.com/Netflix/Hystrix)[1]. This is the type of
-solution showcased in the simple example that accompanies this *README*.
+like [Hystrix](https://github.com/Netflix/Hystrix) (please note that *Hystrix* is a complete implementation of
+the [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/) pattern, of which the Retry pattern
+can be considered a subset of.). This is the type of solution showcased in the simple example that accompanies this
+*README*.
-In our hypothetical application, we have a generic interface for all
-operations on remote interfaces:
+Real world example
+
+> Our application uses a service providing customer information. Once in a while the service seems to be flaky and can return errors or sometimes it just times out. To circumvent these problems we apply the retry pattern.
+
+In plain words
+
+> Retry pattern transparently retries failed operations over network.
+
+[Microsoft documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/retry) says
+
+> Enable an application to handle transient failures when it tries to connect to a service or network resource, by transparently retrying a failed operation. This can improve the stability of the application.
+
+**Programmatic Example**
+
+In our hypothetical application, we have a generic interface for all operations on remote interfaces.
```java
public interface BusinessOperation {
@@ -54,8 +61,7 @@ public interface BusinessOperation {
}
```
-And we have an implementation of this interface that finds our customers
-by looking up a database:
+And we have an implementation of this interface that finds our customers by looking up a database.
```java
public final class FindCustomer implements BusinessOperation {
@@ -122,20 +128,12 @@ more importantly we did *not* instruct our `Retry` to ignore, then the operation
would have failed immediately upon receiving the error, not matter how many
attempts were left.
-
-
-[1] Please note that *Hystrix* is a complete implementation of the *Circuit
-Breaker* pattern, of which the *Retry* pattern can be considered a subset of.
-
## Class diagram

## Applicability
-Whenever an application needs to communicate with an external resource,
-particularly in a cloud environment, and if the business requirements allow it.
-
-## Presentations
-You can view Microsoft's article [here](https://docs.microsoft.com/en-us/azure/architecture/patterns/retry).
+Whenever an application needs to communicate with an external resource, particularly in a cloud environment, and if
+the business requirements allow it.
## Consequences
**Pros:**
@@ -150,4 +148,9 @@ You can view Microsoft's article [here](https://docs.microsoft.com/en-us/azure/a
## Related Patterns
-* [Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html)
+* [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/)
+
+## Credits
+
+* [Retry pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/retry)
+* [Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications](https://www.amazon.com/gp/product/1621140369/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1621140369&linkId=3e3f686af5e60a7a453b48adb286797b)
From 9deb587c52175b0e340a5213b3db08c983e0c798 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Thu, 23 Jul 2020 18:27:00 +0300
Subject: [PATCH 029/225] #590 add explanation for Fluent Interface
---
fluentinterface/README.md | 136 ++++++++++++++++++++++++++++++++++++--
1 file changed, 131 insertions(+), 5 deletions(-)
diff --git a/fluentinterface/README.md b/fluentinterface/README.md
index 3068468b9..61c5f2eb5 100644
--- a/fluentinterface/README.md
+++ b/fluentinterface/README.md
@@ -9,26 +9,151 @@ tags:
---
## Intent
-A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using this pattern results in code that can be read nearly as human language.
+A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using
+this pattern results in code that can be read nearly as human language.
-## Implementation
+## Explanation
+The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API. Those interfaces tend
+to mimic domain specific languages, so they can nearly be read as human languages.
+
A fluent interface can be implemented using any of
* Method Chaining - calling a method returns some object on which further methods can be called.
* Static Factory Methods and Imports
* Named parameters - can be simulated in Java using static factory methods.
+Real world example
+
+> We need to select numbers based on different criteria from the list. It's a great chance to utilize fluent interface pattern to provide readable easy-to-use developer experience.
+
+In plain words
+
+> Fluent Interface pattern provides easily readable flowing interface to code.
+
+Wikipedia says
+
+> In software engineering, a fluent interface is an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language (DSL).
+
+**Programmatic Example**
+
+In this example two implementations of a `FluentIterable` interface are given.
+
+```java
+public interface FluentIterable extends Iterable {
+
+ FluentIterable filter(Predicate super E> predicate);
+
+ Optional first();
+
+ FluentIterable first(int count);
+
+ Optional last();
+
+ FluentIterable last(int count);
+
+ FluentIterable map(Function super E, T> function);
+
+ List asList();
+
+ static List copyToList(Iterable iterable) {
+ var copy = new ArrayList();
+ iterable.forEach(copy::add);
+ return copy;
+ }
+}
+```
+
+The `SimpleFluentIterable` evaluates eagerly and would be too costly for real world applications.
+
+```java
+public class SimpleFluentIterable implements FluentIterable {
+ ...
+}
+```
+
+The `LazyFluentIterable` is evaluated on termination.
+
+```java
+public class LazyFluentIterable implements FluentIterable {
+ ...
+}
+```
+
+Their usage is demonstrated with a simple number list that is filtered, transformed and collected. The
+result is printed afterwards.
+
+```java
+ var integerList = List.of(1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68);
+
+ prettyPrint("The initial list contains: ", integerList);
+
+ var firstFiveNegatives = SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(negatives())
+ .first(3)
+ .asList();
+ prettyPrint("The first three negative values are: ", firstFiveNegatives);
+
+
+ var lastTwoPositives = SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(positives())
+ .last(2)
+ .asList();
+ prettyPrint("The last two positive values are: ", lastTwoPositives);
+
+ SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(number -> number % 2 == 0)
+ .first()
+ .ifPresent(evenNumber -> LOGGER.info("The first even number is: {}", evenNumber));
+
+
+ var transformedList = SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(negatives())
+ .map(transformToString())
+ .asList();
+ prettyPrint("A string-mapped list of negative numbers contains: ", transformedList);
+
+
+ var lastTwoOfFirstFourStringMapped = LazyFluentIterable
+ .from(integerList)
+ .filter(positives())
+ .first(4)
+ .last(2)
+ .map(number -> "String[" + valueOf(number) + "]")
+ .asList();
+ prettyPrint("The lazy list contains the last two of the first four positive numbers "
+ + "mapped to Strings: ", lastTwoOfFirstFourStringMapped);
+
+ LazyFluentIterable
+ .from(integerList)
+ .filter(negatives())
+ .first(2)
+ .last()
+ .ifPresent(number -> LOGGER.info("Last amongst first two negatives: {}", number));
+
+ // The initial list contains: 1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68.
+ // The first three negative values are: -61, -22, -87.
+ // The last two positive values are: 23, 2.
+ // The first even number is: 14
+ // A string-mapped list of negative numbers contains: String[-61], String[-22], String[-87], String[-82], String[-98], String[-68].
+ // The lazy list contains the last two of the first four positive numbers mapped to Strings: String[18], String[6].
+ // Last amongst first two negatives: -22
+```
+
## Class diagram

## Applicability
Use the Fluent Interface pattern when
-* you provide an API that would benefit from a DSL-like usage
-* you have objects that are difficult to configure or use
+* You provide an API that would benefit from a DSL-like usage
+* You have objects that are difficult to configure or use
-## Real world examples
+## Known uses
* [Java 8 Stream API](http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html)
* [Google Guava FluentInterable](https://github.com/google/guava/wiki/FunctionalExplained)
@@ -41,3 +166,4 @@ Use the Fluent Interface pattern when
* [Fluent Interface - Martin Fowler](http://www.martinfowler.com/bliki/FluentInterface.html)
* [Evolutionary architecture and emergent design: Fluent interfaces - Neal Ford](http://www.ibm.com/developerworks/library/j-eaed14/)
* [Internal DSL](http://www.infoq.com/articles/internal-dsls-java)
+* [Domain Specific Languages](https://www.amazon.com/gp/product/0321712943/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=0321712943&linkId=ad8351d6f5be7d8b7ecdb650731f85df)
From 689486267d975dd9d40932d1f431e85ee73c4dd8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Thu, 23 Jul 2020 18:53:47 +0300
Subject: [PATCH 030/225] #590 add explanation to Pipeline
---
pipeline/README.md | 88 +++++++++++++++++--
.../main/java/com/iluwatar/pipeline/App.java | 3 +-
2 files changed, 84 insertions(+), 7 deletions(-)
diff --git a/pipeline/README.md b/pipeline/README.md
index bc8f9399a..fd03cd7b9 100644
--- a/pipeline/README.md
+++ b/pipeline/README.md
@@ -9,7 +9,83 @@ tags:
---
## Intent
-Allows processing of data in a series of stages by giving in an initial input and passing the processed output to be used by the next stages.
+Allows processing of data in a series of stages by giving in an initial input and passing the processed output to be
+used by the next stages.
+
+## Explanation
+
+The Pipeline pattern uses ordered stages to process a sequence of input values. Each implemented task is represented by
+a stage of the pipeline. You can think of pipelines as similar to assembly lines in a factory, where each item in the
+assembly line is constructed in stages. The partially assembled item is passed from one assembly stage to another. The
+outputs of the assembly line occur in the same order as that of the inputs.
+
+Real world example
+
+> Suppose we wanted to pass through a string to a series of filtering stages and convert it as a char array on the last stage.
+
+In plain words
+
+> Pipeline pattern is an assembly line where partial results are passed from one stage to another.
+
+Wikipedia says
+
+> In software engineering, a pipeline consists of a chain of processing elements (processes, threads, coroutines, functions, etc.), arranged so that the output of each element is the input of the next; the name is by analogy to a physical pipeline.
+
+**Programmatic Example**
+
+The stages of our pipeline are called `Handler`s.
+
+```java
+interface Handler {
+ O process(I input);
+}
+```
+
+In our string processing example we have 3 different concrete `Handler`s.
+
+```java
+class RemoveAlphabetsHandler implements Handler {
+ ...
+}
+
+class RemoveDigitsHandler implements Handler {
+ ...
+}
+
+class ConvertToCharArrayHandler implements Handler {
+ ...
+}
+```
+
+Here is the `Pipeline` that will gather and execute the handlers one by one.
+
+```java
+class Pipeline {
+
+ private final Handler currentHandler;
+
+ Pipeline(Handler currentHandler) {
+ this.currentHandler = currentHandler;
+ }
+
+ Pipeline addHandler(Handler newHandler) {
+ return new Pipeline<>(input -> newHandler.process(currentHandler.process(input)));
+ }
+
+ O execute(I input) {
+ return currentHandler.process(input);
+ }
+}
+```
+
+And here's the `Pipeline` in action processing the string.
+
+```java
+ var filters = new Pipeline<>(new RemoveAlphabetsHandler())
+ .addHandler(new RemoveDigitsHandler())
+ .addHandler(new ConvertToCharArrayHandler());
+ filters.execute("GoYankees123!");
+```
## Class diagram

@@ -21,16 +97,16 @@ Use the Pipeline pattern when you want to
* Add readability to complex sequence of operations by providing a fluent builder as an interface
* Improve testability of code since stages will most likely be doing a single thing, complying to the [Single Responsibility Principle (SRP)](https://java-design-patterns.com/principles/#single-responsibility-principle)
-## Typical Use Case
-
-* Implement stages and execute them in an ordered manner
-
-## Real world examples
+## Known uses
* [java.util.Stream](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html)
* [Maven Build Lifecycle](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)
* [Functional Java](https://github.com/functionaljava/functionaljava)
+## Related patterns
+
+* [Chain of Responsibility](https://java-design-patterns.com/patterns/chain/)
+
## Credits
* [The Pipeline Pattern — for fun and profit](https://medium.com/@aaronweatherall/the-pipeline-pattern-for-fun-and-profit-9b5f43a98130)
diff --git a/pipeline/src/main/java/com/iluwatar/pipeline/App.java b/pipeline/src/main/java/com/iluwatar/pipeline/App.java
index 1b1e443e6..cfbcbafc2 100644
--- a/pipeline/src/main/java/com/iluwatar/pipeline/App.java
+++ b/pipeline/src/main/java/com/iluwatar/pipeline/App.java
@@ -59,8 +59,9 @@ public class App {
then is expected to receive an input of char[] array since that is the type being returned
by the previous handler, ConvertToCharArrayHandler.
*/
- new Pipeline<>(new RemoveAlphabetsHandler())
+ var filters = new Pipeline<>(new RemoveAlphabetsHandler())
.addHandler(new RemoveDigitsHandler())
.addHandler(new ConvertToCharArrayHandler());
+ filters.execute("GoYankees123!");
}
}
From 205b87cd9352f303c3ba9165f32286cfc9aef244 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Fri, 24 Jul 2020 16:45:28 +0300
Subject: [PATCH 031/225] Improve Prototype description
---
prototype/README.md | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/prototype/README.md b/prototype/README.md
index c51f5c9bc..472e8330c 100644
--- a/prototype/README.md
+++ b/prototype/README.md
@@ -10,10 +10,13 @@ tags:
---
## Intent
-Specify the kinds of objects to create using a prototypical
-instance, and create new objects by copying this prototype.
+Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
## Explanation
+
+First it should be noted that Prototype pattern is not used to gain performance benefits. It's only used for creating
+new objects from prototype instance.
+
Real world example
> Remember Dolly? The sheep that was cloned! Lets not get into the details but the key point here is that it is all about cloning.
From d9ed8a52b50feaa3be97ae991060171adb418650 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sat, 25 Jul 2020 14:28:43 +0300
Subject: [PATCH 032/225] Update readme
---
README.md | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 53c9cd7a5..2eabb5e82 100644
--- a/README.md
+++ b/README.md
@@ -31,19 +31,20 @@ programming tutorials how to implement a specific pattern. We use the most
popular battle-proven open source Java technologies.
Before you dive into the material, you should be familiar with various
-software design principles.
+[Software Design Principles](https://java-design-patterns.com/principles/).
All designs should be as simple as possible. You should start with KISS, YAGNI,
and Do The Simplest Thing That Could Possibly Work principles. Complexity and
patterns should only be introduced when they are needed for practical
extensibility.
-Once you are familiar with these concepts you can start drilling down into
-patterns by any of the following approaches
+Once you are familiar with these concepts you can start drilling down into the
+[available design patterns](https://java-design-patterns.com/patterns/) by any
+of the following approaches
- - Using difficulty tags, `Difficulty-Beginner`, `Difficulty-Intermediate` & `Difficulty-Expert`.
+ - Search for a specific pattern by name. Can't find one? Please report a new pattern [here](https://github.com/iluwatar/java-design-patterns/issues).
+ - Using tags such as `Performance`, `Gang of Four` or `Data access`.
- Using pattern categories, `Creational`, `Behavioral`, and others.
- - Search for a specific pattern. Can't find one? Please report a new pattern [here](https://github.com/iluwatar/java-design-patterns/issues).
Hopefully you find the object oriented solutions presented on this site useful
in your architectures and have as much fun learning them as we had developing them.
From 2ee5789c7739ecb676f57348320c0d845c1a99af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sat, 25 Jul 2020 15:48:21 +0300
Subject: [PATCH 033/225] #590 explanation for Trampoline
---
trampoline/README.md | 129 +++++++++++++++++++++++++++++++++++++------
1 file changed, 112 insertions(+), 17 deletions(-)
diff --git a/trampoline/README.md b/trampoline/README.md
index 2356e8715..8831f41e1 100644
--- a/trampoline/README.md
+++ b/trampoline/README.md
@@ -9,14 +9,111 @@ tags:
---
## Intent
-Trampoline pattern is used for implementing algorithms recursively in Java without blowing the stack
-and to interleave the execution of functions without hard coding them together
-It is possible by representing a computation in one of 2 states : done | more
-(completed with result, or a reference to the reminder of the computation,
-something like the way a java.util.Supplier does).
+
+Trampoline pattern is used for implementing algorithms recursively in Java without blowing the stack and to interleave
+the execution of functions without hard coding them together.
## Explanation
-Trampoline pattern allows to define recursive algorithms by iterative loop.
+
+Recursion is a frequently adopted technique for solving algorithmic problems in a divide and conquer
+style. For example calculating fibonacci accumulating sum and factorials. In these kinds of problems recursion is
+more straightforward than their loop counterpart. Furthermore recursion may need less code and looks more concise.
+There is a saying that every recursion problem can be solved using a loop with the cost of writing code that is more
+difficult to understand.
+
+However recursion type solutions have one big caveat. For each recursive call it typically needs an intermediate value
+stored and there is a limited amount of stack memory available. Running out of stack memory creates a stack overflow
+error and halts the program execution.
+
+Trampoline pattern is a trick that allows us define recursive algorithms in Java without blowing the stack.
+
+Real world example
+
+> A recursive Fibonacci calculation without the stack overflow problem using the Trampoline pattern.
+
+In plain words
+
+> Trampoline pattern allows recursion without running out of stack memory.
+
+Wikipedia says
+
+> In Java, trampoline refers to using reflection to avoid using inner classes, for example in event listeners. The time overhead of a reflection call is traded for the space overhead of an inner class. Trampolines in Java usually involve the creation of a GenericListener to pass events to an outer class.
+
+**Programmatic Example**
+
+Here's the `Trampoline` implementation in Java.
+
+When `get` is called on the returned Trampoline, internally it will iterate calling `jump` on the returned `Trampoline`
+as long as the concrete instance returned is `Trampoline`, stopping once the returned instance is `done`.
+
+```java
+public interface Trampoline {
+
+ T get();
+
+ default Trampoline jump() {
+ return this;
+ }
+
+ default T result() {
+ return get();
+ }
+
+ default boolean complete() {
+ return true;
+ }
+
+ static Trampoline done(final T result) {
+ return () -> result;
+ }
+
+ static Trampoline more(final Trampoline> trampoline) {
+ return new Trampoline() {
+ @Override
+ public boolean complete() {
+ return false;
+ }
+
+ @Override
+ public Trampoline jump() {
+ return trampoline.result();
+ }
+
+ @Override
+ public T get() {
+ return trampoline(this);
+ }
+
+ T trampoline(final Trampoline trampoline) {
+ return Stream.iterate(trampoline, Trampoline::jump)
+ .filter(Trampoline::complete)
+ .findFirst()
+ .map(Trampoline::result)
+ .orElseThrow();
+ }
+ };
+ }
+}
+```
+
+Using the `Trampoline` to get Fibonacci values.
+
+```java
+ public static Trampoline loop(int times, int prod) {
+ if (times == 0) {
+ return Trampoline.done(prod);
+ } else {
+ return Trampoline.more(() -> loop(times - 1, prod * times));
+ }
+ }
+
+ log.info("start pattern");
+ var result = loop(10, 1).result();
+ log.info("result {}", result);
+
+ // start pattern
+ // result 3628800
+```
## Class diagram

@@ -27,18 +124,16 @@ Use the Trampoline pattern when
* For implementing tail recursive function. This pattern allows to switch on a stackless operation.
* For interleaving the execution of two or more functions on the same thread.
-## Known uses(real world examples)
+## Known uses
-* Trampoline refers to using reflection to avoid using inner classes, for example in event listeners.
-The time overhead of a reflection call is traded for the space overhead of an inner class.
-Trampolines in Java usually involve the creation of a GenericListener to pass events to an outer class.
-
-
-## Tutorials
-
-* [Trampolining: a practical guide for awesome Java Developers](https://medium.com/@johnmcclean/trampolining-a-practical-guide-for-awesome-java-developers-4b657d9c3076)
-* [Trampoline in java ](http://mindprod.com/jgloss/trampoline.html)
+* [cyclops-react](https://github.com/aol/cyclops-react)
## Credits
-* [library 'cyclops-react' uses the pattern](https://github.com/aol/cyclops-react)
+* [Trampolining: a practical guide for awesome Java Developers](https://medium.com/@johnmcclean/trampolining-a-practical-guide-for-awesome-java-developers-4b657d9c3076)
+* [Trampoline in java ](http://mindprod.com/jgloss/trampoline.html)
+* [Laziness, trampolines, monoids and other functional amenities: this is not your father's Java](https://www.slideshare.net/mariofusco/lazine)
+* [Trampoline implementation](https://github.com/bodar/totallylazy/blob/master/src/com/googlecode/totallylazy/Trampoline.java)
+* [What is a trampoline function?](https://stackoverflow.com/questions/189725/what-is-a-trampoline-function)
+* [Modern Java in Action: Lambdas, streams, functional and reactive programming](https://www.amazon.com/gp/product/1617293563/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617293563&linkId=ad53ae6f9f7c0982e759c3527bd2595c)
+* [Java 8 in Action: Lambdas, Streams, and functional-style programming](https://www.amazon.com/gp/product/1617291994/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617291994&linkId=e3e5665b0732c59c9d884896ffe54f4f)
From 1eafb46b6160ec36a2f09d5ef2e866e3728b47f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 26 Jul 2020 11:30:42 +0300
Subject: [PATCH 034/225] Update links and tags
---
ambassador/README.md | 6 +++---
caching/README.md | 5 +++--
circuit-breaker/README.md | 7 ++++---
cqrs/README.md | 11 ++++++-----
event-sourcing/README.md | 4 +++-
leader-election/README.md | 2 +-
priority-queue/README.md | 8 ++++----
queue-load-leveling/README.md | 3 ++-
retry/README.md | 1 +
saga/README.md | 1 +
sharding/README.md | 2 +-
strangler/README.md | 5 ++---
throttling/README.md | 1 +
13 files changed, 32 insertions(+), 24 deletions(-)
diff --git a/ambassador/README.md b/ambassador/README.md
index 78b3a8856..11abfaf88 100644
--- a/ambassador/README.md
+++ b/ambassador/README.md
@@ -5,7 +5,8 @@ folder: ambassador
permalink: /patterns/ambassador/
categories: Structural
tags:
- - Decoupling
+ - Decoupling
+ - Cloud distributed
---
## Intent
@@ -22,8 +23,7 @@ In plain words
Microsoft documentation states
-> An ambassador service can be thought of as an out-of-process proxy that is co-located with the client.
- This pattern can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, or other applications that are difficult to modify, in order to extend their networking capabilities. It can also enable a specialized team to implement those features.
+> An ambassador service can be thought of as an out-of-process proxy that is co-located with the client. This pattern can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, or other applications that are difficult to modify, in order to extend their networking capabilities. It can also enable a specialized team to implement those features.
**Programmatic Example**
diff --git a/caching/README.md b/caching/README.md
index 4172cc72a..912f1d218 100644
--- a/caching/README.md
+++ b/caching/README.md
@@ -5,7 +5,8 @@ folder: caching
permalink: /patterns/caching/
categories: Behavioral
tags:
- - Performance
+ - Performance
+ - Cloud distributed
---
## Intent
@@ -25,4 +26,4 @@ Use the Caching pattern(s) when
* [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
* [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177)
-* [Cache-Aside](https://msdn.microsoft.com/en-us/library/dn589799.aspx)
+* [Cache-Aside pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside)
diff --git a/circuit-breaker/README.md b/circuit-breaker/README.md
index e0ef7d1fb..ce280a570 100644
--- a/circuit-breaker/README.md
+++ b/circuit-breaker/README.md
@@ -5,8 +5,9 @@ folder: circuit-breaker
permalink: /patterns/circuit-breaker/
categories: Behavioral
tags:
- - Performance
- - Decoupling
+ - Performance
+ - Decoupling
+ - Cloud distributed
---
## Intent
@@ -187,4 +188,4 @@ Use the Circuit Breaker pattern when
* [Understanding Circuit Breaker Pattern](https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42)
* [Martin Fowler on Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html)
* [Fault tolerance in a high volume, distributed system](https://medium.com/netflix-techblog/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a)
-* [Microsoft docs](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
+* [Circuit Breaker pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
diff --git a/cqrs/README.md b/cqrs/README.md
index 431ae6279..017e0a003 100644
--- a/cqrs/README.md
+++ b/cqrs/README.md
@@ -5,8 +5,8 @@ folder: cqrs
permalink: /patterns/cqrs/
categories: Architectural
tags:
- - Performance
- - Cloud distributed
+ - Performance
+ - Cloud distributed
---
## Intent
@@ -18,12 +18,13 @@ CQRS Command Query Responsibility Segregation - Separate the query side from the
## Applicability
Use the CQRS pattern when
-* you want to scale the queries and commands independently.
-* you want to use different data models for queries and commands. Useful when dealing with complex domains.
-* you want to use architectures like event sourcing or task based UI.
+* You want to scale the queries and commands independently.
+* You want to use different data models for queries and commands. Useful when dealing with complex domains.
+* You want to use architectures like event sourcing or task based UI.
## Credits
* [Greg Young - CQRS, Task Based UIs, Event Sourcing agh!](http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/)
* [Martin Fowler - CQRS](https://martinfowler.com/bliki/CQRS.html)
* [Oliver Wolf - CQRS for Great Good](https://www.youtube.com/watch?v=Ge53swja9Dw)
+* [Command and Query Responsibility Segregation (CQRS) pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)
diff --git a/event-sourcing/README.md b/event-sourcing/README.md
index 5efbbbd02..6d24a40e5 100644
--- a/event-sourcing/README.md
+++ b/event-sourcing/README.md
@@ -5,7 +5,8 @@ folder: event-sourcing
permalink: /patterns/event-sourcing/
categories: Architectural
tags:
- - Performance
+ - Performance
+ - Cloud distributed
---
## Intent
@@ -30,3 +31,4 @@ Use the Event Sourcing pattern when
* [Martin Fowler - Event Sourcing] (https://martinfowler.com/eaaDev/EventSourcing.html)
* [Event Sourcing | Microsoft Docs] (https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)
* [Reference 3: Introducing Event Sourcing] (https://msdn.microsoft.com/en-us/library/jj591559.aspx)
+* [Event Sourcing pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)
diff --git a/leader-election/README.md b/leader-election/README.md
index 3cfa7a662..85943d5b4 100644
--- a/leader-election/README.md
+++ b/leader-election/README.md
@@ -30,4 +30,4 @@ Do not use this pattern when
## Credits
-* [ Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn568104(v=pandp.10))
+* [Leader Election pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/leader-election)
diff --git a/priority-queue/README.md b/priority-queue/README.md
index c8d1f7773..924d7169f 100644
--- a/priority-queue/README.md
+++ b/priority-queue/README.md
@@ -6,6 +6,7 @@ permalink: /patterns/priority-queue/
categories: Behavioral
tags:
- Decoupling
+ - Cloud distributed
---
## Intent
@@ -18,12 +19,11 @@ Applications may delegate specific tasks to other services; for example, to perf

## Applicability
-Use the Property pattern when
+Use the Priority Queue pattern when
* The system must handle multiple tasks that might have different priorities.
* Different users or tenants should be served with different priority..
-## Real world examples
+## Credits
-* [ Priority Queue Pattern](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589794(v=pandp.10))
-Microsoft Azure does not provide a queuing mechanism that natively support automatic prioritization of messages through sorting. However, it does provide Azure Service Bus topics and subscriptions, which support a queuing mechanism that provides message filtering, together with a wide range of flexible capabilities that make it ideal for use in almost all priority queue implementations.
+* [Priority Queue pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/priority-queue)
diff --git a/queue-load-leveling/README.md b/queue-load-leveling/README.md
index 3674e7413..5cad88636 100644
--- a/queue-load-leveling/README.md
+++ b/queue-load-leveling/README.md
@@ -7,6 +7,7 @@ categories: Concurrency
tags:
- Decoupling
- Performance
+ - Cloud distributed
---
## Intent
@@ -32,4 +33,4 @@ for both the task and the service.
## Credits
-* [Microsoft Cloud Design Patterns: Queue-Based Load Leveling Pattern](https://msdn.microsoft.com/en-us/library/dn589783.aspx)
+* [Queue-Based Load Leveling pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/queue-based-load-leveling)
diff --git a/retry/README.md b/retry/README.md
index fa56c1240..056674a18 100644
--- a/retry/README.md
+++ b/retry/README.md
@@ -6,6 +6,7 @@ permalink: /patterns/retry/
categories: Behavioral
tags:
- Performance
+ - Cloud distributed
---
## Intent
diff --git a/saga/README.md b/saga/README.md
index 50aeb7d73..394398f99 100644
--- a/saga/README.md
+++ b/saga/README.md
@@ -46,3 +46,4 @@ Use the Saga pattern, if:
## Credits
- [Pattern: Saga](https://microservices.io/patterns/data/saga.html)
+- [Saga distributed transactions pattern](https://docs.microsoft.com/en-us/azure/architecture/reference-architectures/saga/saga)
diff --git a/sharding/README.md b/sharding/README.md
index 2ee465401..cc2121bb5 100644
--- a/sharding/README.md
+++ b/sharding/README.md
@@ -26,4 +26,4 @@ This pattern offers the following benefits:
## Credits
-* [Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications - Sharding Pattern](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589797(v=pandp.10)?redirectedfrom=MSDN)
+* [Sharding pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/sharding)
diff --git a/strangler/README.md b/strangler/README.md
index 2f157f1d2..667940798 100644
--- a/strangler/README.md
+++ b/strangler/README.md
@@ -6,6 +6,7 @@ permalink: /patterns/strangler/
categories: Structural
tags:
- Extensibility
+ - Cloud distributed
---
## Intent
@@ -25,7 +26,5 @@ so usually use it when the system is not so simple.
## Credits
-* [Strangler pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/strangler#context-and-problem)
+* [Strangler pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/strangler)
* [Legacy Application Strangulation : Case Studies](https://paulhammant.com/2013/07/14/legacy-application-strangulation-case-studies/)
-
-
diff --git a/throttling/README.md b/throttling/README.md
index f3ef43c17..48e1b1c78 100644
--- a/throttling/README.md
+++ b/throttling/README.md
@@ -6,6 +6,7 @@ permalink: /patterns/throttling/
categories: Behavioral
tags:
- Performance
+ - Cloud distributed
---
## Intent
From 0a35cdfbe4b9a3ac90a3b39b7da809c390de1207 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 26 Jul 2020 12:10:48 +0300
Subject: [PATCH 035/225] #590 explanation for Unit of Work
---
unit-of-work/README.md | 165 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 163 insertions(+), 2 deletions(-)
diff --git a/unit-of-work/README.md b/unit-of-work/README.md
index 94ef784f5..1f6c7c5b2 100644
--- a/unit-of-work/README.md
+++ b/unit-of-work/README.md
@@ -7,11 +7,167 @@ permalink: /patterns/unit-of-work/
categories: Architectural
tags:
- Data access
+ - Performance
---
## Intent
-When a business transaction is completed, all the these updates are sent as one
- big unit of work to be persisted in a database in one go so as to minimize database trips.
+When a business transaction is completed, all the the updates are sent as one big unit of work to be persisted
+in one go to minimize database round-trips.
+
+## Explanation
+Real world example
+
+> We have a database containing student information. Administrators all over the country are constantly updating this information and it causes high load on the database server. To make the load more manageable we apply to Unit of Work pattern to send many small updates in batches.
+
+In plain words
+
+> Unit of Work merges many small database updates in single batch to optimize the number of round-trips.
+
+[MartinFowler.com](https://martinfowler.com/eaaCatalog/unitOfWork.html) says
+
+> Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.
+
+**Programmatic Example**
+
+Here's the `Student` entity that is being persisted to the database.
+
+```java
+public class Student {
+ private final Integer id;
+ private final String name;
+ private final String address;
+
+ public Student(Integer id, String name, String address) {
+ this.id = id;
+ this.name = name;
+ this.address = address;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+}
+```
+
+The essence of the implementation is the `StudentRepository` implementing the Unit of Work pattern. It maintains a map
+of database operations (`context`) that need to be done and when `commit` is called it applies them in single batch.
+
+```java
+public interface IUnitOfWork {
+
+ String INSERT = "INSERT";
+ String DELETE = "DELETE";
+ String MODIFY = "MODIFY";
+
+ void registerNew(T entity);
+
+ void registerModified(T entity);
+
+ void registerDeleted(T entity);
+
+ void commit();
+}
+
+public class StudentRepository implements IUnitOfWork {
+ private static final Logger LOGGER = LoggerFactory.getLogger(StudentRepository.class);
+
+ private Map> context;
+ private StudentDatabase studentDatabase;
+
+ public StudentRepository(Map> context, StudentDatabase studentDatabase) {
+ this.context = context;
+ this.studentDatabase = studentDatabase;
+ }
+
+ @Override
+ public void registerNew(Student student) {
+ LOGGER.info("Registering {} for insert in context.", student.getName());
+ register(student, IUnitOfWork.INSERT);
+ }
+
+ @Override
+ public void registerModified(Student student) {
+ LOGGER.info("Registering {} for modify in context.", student.getName());
+ register(student, IUnitOfWork.MODIFY);
+
+ }
+
+ @Override
+ public void registerDeleted(Student student) {
+ LOGGER.info("Registering {} for delete in context.", student.getName());
+ register(student, IUnitOfWork.DELETE);
+ }
+
+ private void register(Student student, String operation) {
+ var studentsToOperate = context.get(operation);
+ if (studentsToOperate == null) {
+ studentsToOperate = new ArrayList<>();
+ }
+ studentsToOperate.add(student);
+ context.put(operation, studentsToOperate);
+ }
+
+ @Override
+ public void commit() {
+ if (context == null || context.size() == 0) {
+ return;
+ }
+ LOGGER.info("Commit started");
+ if (context.containsKey(IUnitOfWork.INSERT)) {
+ commitInsert();
+ }
+
+ if (context.containsKey(IUnitOfWork.MODIFY)) {
+ commitModify();
+ }
+ if (context.containsKey(IUnitOfWork.DELETE)) {
+ commitDelete();
+ }
+ LOGGER.info("Commit finished.");
+ }
+
+ private void commitInsert() {
+ var studentsToBeInserted = context.get(IUnitOfWork.INSERT);
+ for (var student : studentsToBeInserted) {
+ LOGGER.info("Saving {} to database.", student.getName());
+ studentDatabase.insert(student);
+ }
+ }
+
+ private void commitModify() {
+ var modifiedStudents = context.get(IUnitOfWork.MODIFY);
+ for (var student : modifiedStudents) {
+ LOGGER.info("Modifying {} to database.", student.getName());
+ studentDatabase.modify(student);
+ }
+ }
+
+ private void commitDelete() {
+ var deletedStudents = context.get(IUnitOfWork.DELETE);
+ for (var student : deletedStudents) {
+ LOGGER.info("Deleting {} to database.", student.getName());
+ studentDatabase.delete(student);
+ }
+ }
+}
+```
+
+Finally here's how we use the `StudentRepository` and `commit` the transaction.
+
+```java
+ studentRepository.registerNew(ram);
+ studentRepository.registerModified(shyam);
+ studentRepository.registerDeleted(gopi);
+ studentRepository.commit();
+```
## Class diagram

@@ -23,6 +179,11 @@ Use the Unit Of Work pattern when
* To send changes to database as a unit of work which ensures atomicity of the transaction.
* To reduce number of database calls.
+## Tutorials
+
+* [Repository and Unit of Work Pattern](https://www.programmingwithwolfgang.com/repository-and-unit-of-work-pattern/)
+* [Unit of Work - a Design Pattern](https://mono.software/2017/01/13/unit-of-work-a-design-pattern/)
+
## Credits
* [Design Pattern - Unit Of Work Pattern](https://www.codeproject.com/Articles/581487/Unit-of-Work-Design-Pattern)
From 3e1a83e29d6242e000c2ec73a2de2db26d749bdf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 26 Jul 2020 15:53:48 +0300
Subject: [PATCH 036/225] #590 explanation for API Gateway
---
api-gateway/README.md | 141 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 135 insertions(+), 6 deletions(-)
diff --git a/api-gateway/README.md b/api-gateway/README.md
index 3a4f13e35..0d67b8d9b 100644
--- a/api-gateway/README.md
+++ b/api-gateway/README.md
@@ -5,14 +5,142 @@ folder: api-gateway
permalink: /patterns/api-gateway/
categories: Architectural
tags:
-- Cloud distributed
-- Decoupling
+ - Cloud distributed
+ - Decoupling
+ - Microservices
---
## Intent
-Aggregate calls to microservices in a single location: the API Gateway. The user makes a single
-call to the API Gateway, and the API Gateway then calls each relevant microservice.
+Aggregate calls to microservices in a single location: the API Gateway. The user makes a single call to the API Gateway,
+and the API Gateway then calls each relevant microservice.
+
+## Explanation
+
+With the Microservices pattern, a client may need data from multiple different microservices. If the client called each
+microservice directly, that could contribute to longer load times, since the client would have to make a network request
+for each microservice called. Moreover, having the client call each microservice directly ties the client to that
+microservice - if the internal implementations of the microservices change (for example, if two microservices are
+combined sometime in the future) or if the location (host and port) of a microservice changes, then every client that
+makes use of those microservices must be updated.
+
+The intent of the API Gateway pattern is to alleviate some of these issues. In the API Gateway pattern, an additional
+entity (the API Gateway) is placed between the client and the microservices. The job of the API Gateway is to aggregate
+the calls to the microservices. Rather than the client calling each microservice individually, the client calls the
+API Gateway a single time. The API Gateway then calls each of the microservices that the client needs.
+
+Real world example
+
+> We are implementing microservices and API Gateway pattern for an e-commerce site. In this system the API Gateway makes
+calls to the Image and Price microservices.
+
+In plain words
+
+> For a system implemented using microservices architecture, API Gateway is the single entry point that aggregates the
+calls to the individual microservices.
+
+Wikipedia says
+
+> API Gateway is a server that acts as an API front-end, receives API requests, enforces throttling and security
+policies, passes requests to the back-end service and then passes the response back to the requester. A gateway often
+includes a transformation engine to orchestrate and modify the requests and responses on the fly. A gateway can also
+provide functionality such as collecting analytics data and providing caching. The gateway can provide functionality to
+support authentication, authorization, security, audit and regulatory compliance.
+
+**Programmatic Example**
+
+This implementation shows what the API Gateway pattern could look like for an e-commerce site. The `ApiGateway` makes
+calls to the Image and Price microservices using the `ImageClientImpl` and `PriceClientImpl` respectively. Customers
+viewing the site on a desktop device can see both price information and an image of a product, so the `ApiGateway` calls
+both of the microservices and aggregates the data in the `DesktopProduct` model. However, mobile users only see price
+information; they do not see a product image. For mobile users, the `ApiGateway` only retrieves price information, which
+it uses to populate the `MobileProduct`.
+
+Here's the Image microservice implementation.
+
+```java
+public interface ImageClient {
+ String getImagePath();
+}
+
+public class ImageClientImpl implements ImageClient {
+
+ @Override
+ public String getImagePath() {
+ var httpClient = HttpClient.newHttpClient();
+ var httpGet = HttpRequest.newBuilder()
+ .GET()
+ .uri(URI.create("http://localhost:50005/image-path"))
+ .build();
+
+ try {
+ var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
+ return httpResponse.body();
+ } catch (IOException | InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+}
+```
+
+Here's the Price microservice implementation.
+
+```java
+public interface PriceClient {
+ String getPrice();
+}
+
+public class PriceClientImpl implements PriceClient {
+
+ @Override
+ public String getPrice() {
+ var httpClient = HttpClient.newHttpClient();
+ var httpGet = HttpRequest.newBuilder()
+ .GET()
+ .uri(URI.create("http://localhost:50006/price"))
+ .build();
+
+ try {
+ var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
+ return httpResponse.body();
+ } catch (IOException | InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+}
+```
+
+And here we can see how API Gateway maps the requests to the microservices.
+
+```java
+public class ApiGateway {
+
+ @Resource
+ private ImageClient imageClient;
+
+ @Resource
+ private PriceClient priceClient;
+
+ @RequestMapping(path = "/desktop", method = RequestMethod.GET)
+ public DesktopProduct getProductDesktop() {
+ var desktopProduct = new DesktopProduct();
+ desktopProduct.setImagePath(imageClient.getImagePath());
+ desktopProduct.setPrice(priceClient.getPrice());
+ return desktopProduct;
+ }
+
+ @RequestMapping(path = "/mobile", method = RequestMethod.GET)
+ public MobileProduct getProductMobile() {
+ var mobileProduct = new MobileProduct();
+ mobileProduct.setPrice(priceClient.getPrice());
+ return mobileProduct;
+ }
+}
+```
## Class diagram

@@ -21,10 +149,11 @@ call to the API Gateway, and the API Gateway then calls each relevant microservi
Use the API Gateway pattern when
-* you're also using the Microservices pattern and need a single point of aggregation for your
-microservice calls
+* You're using microservices architecture and need a single point of aggregation for your microservice calls.
## Credits
* [microservices.io - API Gateway](http://microservices.io/patterns/apigateway.html)
* [NGINX - Building Microservices: Using an API Gateway](https://www.nginx.com/blog/building-microservices-using-an-api-gateway/)
+* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=ac7b6a57f866ac006a309d9086e8cfbd)
+* [Building Microservices: Designing Fine-Grained Systems](https://www.amazon.com/gp/product/1491950358/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1491950358&linkId=4c95ca9831e05e3f0dadb08841d77bf1)
From f37d697a606a4d37465cb4959459bffc3d019b0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 26 Jul 2020 19:25:25 +0300
Subject: [PATCH 037/225] #590 explanation for Service Layer
---
service-layer/README.md | 210 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 204 insertions(+), 6 deletions(-)
diff --git a/service-layer/README.md b/service-layer/README.md
index 3feaf8395..910eaeaea 100644
--- a/service-layer/README.md
+++ b/service-layer/README.md
@@ -9,12 +9,210 @@ tags:
---
## Intent
-Service Layer is an abstraction over domain logic. Typically
-applications require multiple kinds of interfaces to the data they store and
-logic they implement: data loaders, user interfaces, integration gateways, and
-others. Despite their different purposes, these interfaces often need common
-interactions with the application to access and manipulate its data and invoke
-its business logic. The Service Layer fulfills this role.
+
+Service Layer is an abstraction over domain logic. It defines application's boundary with a layer of services that
+establishes a set of available operations and coordinates the application's response in each operation.
+
+## Explanation
+
+Typically applications require different kinds of interfaces to the data they store and the logic they implement.
+Despite their different purposes, these interfaces often need common interactions with the application to access and
+manipulate its data and invoke its business logic. Encoding the logic of the interactions separately in each module
+causes a lot of duplication. It's better to centralize building the business logic inside single Service Layer to avoid
+these pitfalls.
+
+Real world example
+
+> We are writing an application that tracks wizards, spellbooks and spells. Wizards may have spellbooks and spellbooks
+may have spells.
+
+In plain words
+
+> Service Layer is an abstraction over application's business logic.
+
+Wikipedia says
+
+> Service layer is an architectural pattern, applied within the service-orientation design paradigm, which aims to
+organize the services, within a service inventory, into a set of logical layers. Services that are categorized into
+a particular layer share functionality. This helps to reduce the conceptual overhead related to managing the service
+inventory, as the services belonging to the same layer address a smaller set of activities.
+
+**Programmatic Example**
+
+The example application demonstrates interactions between a client `App` and a service `MagicService` that allows
+interaction between wizards, spellbooks and spells. The service is implemented with 3-layer architecture
+(entity, dao, service).
+
+For this explanation we are looking at one vertical slice of the system. Let's start from the entity layer and look at
+`Wizard` class. Other entities not shown here are `Spellbook` and `Spell`.
+
+```java
+@Entity
+@Table(name = "WIZARD")
+public class Wizard extends BaseEntity {
+
+ @Id
+ @GeneratedValue
+ @Column(name = "WIZARD_ID")
+ private Long id;
+
+ private String name;
+
+ @ManyToMany(cascade = CascadeType.ALL)
+ private Set spellbooks;
+
+ public Wizard() {
+ spellbooks = new HashSet<>();
+ }
+
+ public Wizard(String name) {
+ this();
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set getSpellbooks() {
+ return spellbooks;
+ }
+
+ public void setSpellbooks(Set spellbooks) {
+ this.spellbooks = spellbooks;
+ }
+
+ public void addSpellbook(Spellbook spellbook) {
+ spellbook.getWizards().add(this);
+ spellbooks.add(spellbook);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
+```
+
+Above the entity layer we have DAOs. For `Wizard` the DAO layer looks as follows.
+
+```java
+public interface WizardDao extends Dao {
+
+ Wizard findByName(String name);
+}
+
+public class WizardDaoImpl extends DaoBaseImpl implements WizardDao {
+
+ @Override
+ public Wizard findByName(String name) {
+ Transaction tx = null;
+ Wizard result;
+ try (var session = getSessionFactory().openSession()) {
+ tx = session.beginTransaction();
+ var criteria = session.createCriteria(persistentClass);
+ criteria.add(Restrictions.eq("name", name));
+ result = (Wizard) criteria.uniqueResult();
+ tx.commit();
+ } catch (Exception e) {
+ if (tx != null) {
+ tx.rollback();
+ }
+ throw e;
+ }
+ return result;
+ }
+}
+```
+
+Next we can look at the Service Layer, which in our case consists of a single `MagicService`.
+
+```java
+public interface MagicService {
+
+ List findAllWizards();
+
+ List findAllSpellbooks();
+
+ List findAllSpells();
+
+ List findWizardsWithSpellbook(String name);
+
+ List findWizardsWithSpell(String name);
+}
+
+public class MagicServiceImpl implements MagicService {
+
+ private WizardDao wizardDao;
+ private SpellbookDao spellbookDao;
+ private SpellDao spellDao;
+
+ public MagicServiceImpl(WizardDao wizardDao, SpellbookDao spellbookDao, SpellDao spellDao) {
+ this.wizardDao = wizardDao;
+ this.spellbookDao = spellbookDao;
+ this.spellDao = spellDao;
+ }
+
+ @Override
+ public List findAllWizards() {
+ return wizardDao.findAll();
+ }
+
+ @Override
+ public List findAllSpellbooks() {
+ return spellbookDao.findAll();
+ }
+
+ @Override
+ public List findAllSpells() {
+ return spellDao.findAll();
+ }
+
+ @Override
+ public List findWizardsWithSpellbook(String name) {
+ var spellbook = spellbookDao.findByName(name);
+ return new ArrayList<>(spellbook.getWizards());
+ }
+
+ @Override
+ public List findWizardsWithSpell(String name) {
+ var spell = spellDao.findByName(name);
+ var spellbook = spell.getSpellbook();
+ return new ArrayList<>(spellbook.getWizards());
+ }
+}
+```
+
+And finally we can show how the client `App` interacts with `MagicService` in the Service Layer.
+
+```java
+ var service = new MagicServiceImpl(wizardDao, spellbookDao, spellDao);
+ LOGGER.info("Enumerating all wizards");
+ service.findAllWizards().stream().map(Wizard::getName).forEach(LOGGER::info);
+ LOGGER.info("Enumerating all spellbooks");
+ service.findAllSpellbooks().stream().map(Spellbook::getName).forEach(LOGGER::info);
+ LOGGER.info("Enumerating all spells");
+ service.findAllSpells().stream().map(Spell::getName).forEach(LOGGER::info);
+ LOGGER.info("Find wizards with spellbook 'Book of Idores'");
+ var wizardsWithSpellbook = service.findWizardsWithSpellbook("Book of Idores");
+ wizardsWithSpellbook.forEach(w -> LOGGER.info("{} has 'Book of Idores'", w.getName()));
+ LOGGER.info("Find wizards with spell 'Fireball'");
+ var wizardsWithSpell = service.findWizardsWithSpell("Fireball");
+ wizardsWithSpell.forEach(w -> LOGGER.info("{} has 'Fireball'", w.getName()));
+```
+
## Class diagram

From 2fdd7a11e93c38d0a3496f09232fa10c51de3f21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 26 Jul 2020 22:40:42 +0300
Subject: [PATCH 038/225] SonarQube check runs only in master branch
(workaround for https://jira.sonarsource.com/browse/MMF-1371)
---
.github/workflows/maven.yml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 53460c97d..01caaab67 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -46,7 +46,13 @@ jobs:
# Some tests need screen access
- name: Install xvfb
run: sudo apt-get install xvfb
+ # SonarQube scan does not work for forked repositories
+ # See https://jira.sonarsource.com/browse/MMF-1371
- name: Build with Maven
+ if: github.ref != ‘refs/heads/master’
+ run: xvfb-run mvn clean verify
+ - name: Build with Maven and run SonarQube analysis
+ if: github.ref == ‘refs/heads/master’
run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
env:
# These two env variables are needed for sonar analysis
From eee409f2840d6276826f8577fd5408afa52e7a40 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 26 Jul 2020 22:44:54 +0300
Subject: [PATCH 039/225] Fix syntax
---
.github/workflows/maven.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 01caaab67..336c103d6 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -49,10 +49,10 @@ jobs:
# SonarQube scan does not work for forked repositories
# See https://jira.sonarsource.com/browse/MMF-1371
- name: Build with Maven
- if: github.ref != ‘refs/heads/master’
+ if: "github.ref != ‘refs/heads/master’"
run: xvfb-run mvn clean verify
- name: Build with Maven and run SonarQube analysis
- if: github.ref == ‘refs/heads/master’
+ if: "github.ref == ‘refs/heads/master’"
run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
env:
# These two env variables are needed for sonar analysis
From 4b88214baef78c362806311d88f96bebb0cd4d21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Sun, 26 Jul 2020 22:47:33 +0300
Subject: [PATCH 040/225] Fix syntax
---
.github/workflows/maven.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 336c103d6..d18cad280 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -49,10 +49,10 @@ jobs:
# SonarQube scan does not work for forked repositories
# See https://jira.sonarsource.com/browse/MMF-1371
- name: Build with Maven
- if: "github.ref != ‘refs/heads/master’"
+ if: github.ref != 'refs/heads/master'
run: xvfb-run mvn clean verify
- name: Build with Maven and run SonarQube analysis
- if: "github.ref == ‘refs/heads/master’"
+ if: github.ref == 'refs/heads/master'
run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
env:
# These two env variables are needed for sonar analysis
From 54c0b1725c522666e7dbdcb973719cefb7a9daed Mon Sep 17 00:00:00 2001
From: amit1307
Date: Mon, 27 Jul 2020 14:50:32 +0100
Subject: [PATCH 041/225] Fix broken logging in service layer (#1342)
---
service-layer/src/main/resources/logback.xml | 1 +
1 file changed, 1 insertion(+)
diff --git a/service-layer/src/main/resources/logback.xml b/service-layer/src/main/resources/logback.xml
index 47fe42236..e6678aff2 100644
--- a/service-layer/src/main/resources/logback.xml
+++ b/service-layer/src/main/resources/logback.xml
@@ -43,6 +43,7 @@
+
From b62bed7e433591af1585aa13ca8b7aecd1842e7b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Mon, 27 Jul 2020 18:28:12 +0300
Subject: [PATCH 042/225] #590 explanation for Promise
---
promise/README.md | 278 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 272 insertions(+), 6 deletions(-)
diff --git a/promise/README.md b/promise/README.md
index cf3d96c88..993d29a9f 100644
--- a/promise/README.md
+++ b/promise/README.md
@@ -9,18 +9,277 @@ tags:
---
## Also known as
+
CompletableFuture
## Intent
-A Promise represents a proxy for a value not necessarily known when the promise is created. It
-allows you to associate dependent promises to an asynchronous action's eventual success value or
-failure reason. Promises are a way to write async code that still appears as though it is executing
-in a synchronous way.
+
+A Promise represents a proxy for a value not necessarily known when the promise is created. It allows you to associate
+dependent promises to an asynchronous action's eventual success value or failure reason. Promises are a way to write
+async code that still appears as though it is executing in a synchronous way.
+
+## Explanation
+
+The Promise object is used for asynchronous computations. A Promise represents an operation that hasn't completed yet,
+but is expected in the future.
+
+Promises provide a few advantages over callback objects:
+ * Functional composition and error handling
+ * Prevents callback hell and provides callback aggregation
+
+Real world example
+
+> We are developing a software solution that downloads files and calculates the number of lines and character
+frequencies in those files. Promise is an ideal solution to make the code concise and easy to understand.
+
+In plain words
+
+> Promise is a placeholder for an asynchronous operation that is ongoing.
+
+Wikipedia says
+
+> In computer science, future, promise, delay, and deferred refer to constructs used for synchronizing program
+execution in some concurrent programming languages. They describe an object that acts as a proxy for a result that is
+initially unknown, usually because the computation of its value is not yet complete.
+
+**Programmatic Example**
+
+In the example a file is downloaded and its line count is calculated. The calculated line count is then consumed and
+printed on console.
+
+Let's first introduce a support class we need for implementation. Here's `PromiseSupport`.
+
+```java
+class PromiseSupport implements Future {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PromiseSupport.class);
+
+ private static final int RUNNING = 1;
+ private static final int FAILED = 2;
+ private static final int COMPLETED = 3;
+
+ private final Object lock;
+
+ private volatile int state = RUNNING;
+ private T value;
+ private Exception exception;
+
+ PromiseSupport() {
+ this.lock = new Object();
+ }
+
+ void fulfill(T value) {
+ this.value = value;
+ this.state = COMPLETED;
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+
+ void fulfillExceptionally(Exception exception) {
+ this.exception = exception;
+ this.state = FAILED;
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ return state > RUNNING;
+ }
+
+ @Override
+ public T get() throws InterruptedException, ExecutionException {
+ synchronized (lock) {
+ while (state == RUNNING) {
+ lock.wait();
+ }
+ }
+ if (state == COMPLETED) {
+ return value;
+ }
+ throw new ExecutionException(exception);
+ }
+
+ @Override
+ public T get(long timeout, TimeUnit unit) throws ExecutionException {
+ synchronized (lock) {
+ while (state == RUNNING) {
+ try {
+ lock.wait(unit.toMillis(timeout));
+ } catch (InterruptedException e) {
+ LOGGER.warn("Interrupted!", e);
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ if (state == COMPLETED) {
+ return value;
+ }
+ throw new ExecutionException(exception);
+ }
+}
+```
+
+With `PromiseSupport` in place we can implement the actual `Promise`.
+
+```java
+public class Promise extends PromiseSupport {
+
+ private Runnable fulfillmentAction;
+ private Consumer super Throwable> exceptionHandler;
+
+ public Promise() {
+ }
+
+ @Override
+ public void fulfill(T value) {
+ super.fulfill(value);
+ postFulfillment();
+ }
+
+ @Override
+ public void fulfillExceptionally(Exception exception) {
+ super.fulfillExceptionally(exception);
+ handleException(exception);
+ postFulfillment();
+ }
+
+ private void handleException(Exception exception) {
+ if (exceptionHandler == null) {
+ return;
+ }
+ exceptionHandler.accept(exception);
+ }
+
+ private void postFulfillment() {
+ if (fulfillmentAction == null) {
+ return;
+ }
+ fulfillmentAction.run();
+ }
+
+ public Promise fulfillInAsync(final Callable task, Executor executor) {
+ executor.execute(() -> {
+ try {
+ fulfill(task.call());
+ } catch (Exception ex) {
+ fulfillExceptionally(ex);
+ }
+ });
+ return this;
+ }
+
+ public Promise thenAccept(Consumer super T> action) {
+ var dest = new Promise();
+ fulfillmentAction = new ConsumeAction(this, dest, action);
+ return dest;
+ }
+
+ public Promise onError(Consumer super Throwable> exceptionHandler) {
+ this.exceptionHandler = exceptionHandler;
+ return this;
+ }
+
+ public Promise thenApply(Function super T, V> func) {
+ Promise dest = new Promise<>();
+ fulfillmentAction = new TransformAction(this, dest, func);
+ return dest;
+ }
+
+ private class ConsumeAction implements Runnable {
+
+ private final Promise src;
+ private final Promise dest;
+ private final Consumer super T> action;
+
+ private ConsumeAction(Promise src, Promise dest, Consumer super T> action) {
+ this.src = src;
+ this.dest = dest;
+ this.action = action;
+ }
+
+ @Override
+ public void run() {
+ try {
+ action.accept(src.get());
+ dest.fulfill(null);
+ } catch (Throwable throwable) {
+ dest.fulfillExceptionally((Exception) throwable.getCause());
+ }
+ }
+ }
+
+ private class TransformAction implements Runnable {
+
+ private final Promise src;
+ private final Promise dest;
+ private final Function super T, V> func;
+
+ private TransformAction(Promise src, Promise dest, Function super T, V> func) {
+ this.src = src;
+ this.dest = dest;
+ this.func = func;
+ }
+
+ @Override
+ public void run() {
+ try {
+ dest.fulfill(func.apply(src.get()));
+ } catch (Throwable throwable) {
+ dest.fulfillExceptionally((Exception) throwable.getCause());
+ }
+ }
+ }
+}
+```
+
+Now we can show the full example in action. Here's how to download and count the number of lines in a file using
+`Promise`.
+
+```java
+ countLines().thenAccept(
+ count -> {
+ LOGGER.info("Line count is: {}", count);
+ taskCompleted();
+ }
+ );
+
+ private Promise countLines() {
+ return download(DEFAULT_URL).thenApply(Utility::countLines);
+ }
+
+ private Promise download(String urlString) {
+ return new Promise()
+ .fulfillInAsync(
+ () -> Utility.downloadFile(urlString), executor)
+ .onError(
+ throwable -> {
+ throwable.printStackTrace();
+ taskCompleted();
+ }
+ );
+ }
+```
## Class diagram
+

## Applicability
+
Promise pattern is applicable in concurrent programming when some work needs to be done asynchronously
and:
@@ -35,10 +294,17 @@ and:
* [Guava ListenableFuture](https://github.com/google/guava/wiki/ListenableFutureExplained)
## Related Patterns
- * Async Method Invocation
- * Callback
+
+ * [Async Method Invocation](https://java-design-patterns.com/patterns/async-method-invocation/)
+ * [Callback](https://java-design-patterns.com/patterns/callback/)
+
+## Tutorials
+
+* [Guide To CompletableFuture](https://www.baeldung.com/java-completablefuture)
## Credits
* [You are missing the point to Promises](https://gist.github.com/domenic/3889970)
* [Functional style callbacks using CompletableFuture](https://www.infoq.com/articles/Functional-Style-Callbacks-Using-CompletableFuture)
+* [Java 8 in Action: Lambdas, Streams, and functional-style programming](https://www.amazon.com/gp/product/1617291994/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617291994&linkId=995af46887bb7b65e6c788a23eaf7146)
+* [Modern Java in Action: Lambdas, streams, functional and reactive programming](https://www.amazon.com/gp/product/1617293563/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617293563&linkId=f70fe0d3e1efaff89554a6479c53759c)
From ef4de30310fa46c95c562612c3863ddd1200db92 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 27 Jul 2020 20:59:08 +0300
Subject: [PATCH 043/225] docs: add iluwatar as a contributor (#1343)
* docs: update README.md [skip ci]
* docs: create .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 24 ++++++++++++++++++++++++
README.md | 22 ++++++++++++++++++++++
2 files changed, 46 insertions(+)
create mode 100644 .all-contributorsrc
diff --git a/.all-contributorsrc b/.all-contributorsrc
new file mode 100644
index 000000000..4e92d6568
--- /dev/null
+++ b/.all-contributorsrc
@@ -0,0 +1,24 @@
+{
+ "files": [
+ "README.md"
+ ],
+ "imageSize": 100,
+ "commit": false,
+ "contributors": [
+ {
+ "login": "iluwatar",
+ "name": "Ilkka Seppälä",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/582346?v=4",
+ "profile": "https://github.com/iluwatar",
+ "contributions": [
+ "code"
+ ]
+ }
+ ],
+ "contributorsPerLine": 7,
+ "projectName": "java-design-patterns",
+ "projectOwner": "iluwatar",
+ "repoType": "github",
+ "repoHost": "https://github.com",
+ "skipCi": true
+}
diff --git a/README.md b/README.md
index 2eabb5e82..533eec47e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,7 @@
+[](#contributors-)
+
that smart and dearly wants an empty line before a heading to be able to
display it as such, e.g. website) -->
@@ -58,3 +61,22 @@ you and answer your questions in the [Gitter chatroom](https://gitter.im/iluwata
# License
This project is licensed under the terms of the MIT license.
+
+## Contributors ✨
+
+Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
+
+
+
+
+
+
+
+
+
+
+This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
\ No newline at end of file
From 93c11fdf233e19f75b8a39afa7e7dbd8c2d87157 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Mon, 27 Jul 2020 21:01:48 +0300
Subject: [PATCH 044/225] Update README.md
---
README.md | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index 533eec47e..d7148dde7 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,4 @@
-[](#contributors-)
-
that smart and dearly wants an empty line before a heading to be able to
display it as such, e.g. website) -->
@@ -11,6 +8,9 @@
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
+
+[](#contributors-)
+
# Introduction
@@ -62,9 +62,7 @@ you and answer your questions in the [Gitter chatroom](https://gitter.im/iluwata
This project is licensed under the terms of the MIT license.
-## Contributors ✨
-
-Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
+# Contributors
@@ -79,4 +77,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
-This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
\ No newline at end of file
+This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
From b7d122f6146c3ae36750a9eaef0083649749800d Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 27 Jul 2020 21:13:13 +0300
Subject: [PATCH 045/225] docs: add iluwatar as a contributor (#1344)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: create .all-contributorsrc [skip ci]
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 3 ++-
README.md | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 4e92d6568..80d7f54b4 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -11,7 +11,8 @@
"avatar_url": "https://avatars1.githubusercontent.com/u/582346?v=4",
"profile": "https://github.com/iluwatar",
"contributions": [
- "code"
+ "code",
+ "projectManagement"
]
}
],
diff --git a/README.md b/README.md
index d7148dde7..55f11e702 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ This project is licensed under the terms of the MIT license.
From ae7a0b8a4a331ccf96d6dbd956c4fd1c541888ed Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 27 Jul 2020 21:17:52 +0300
Subject: [PATCH 046/225] docs: add amit1307 as a contributor (#1345)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 80d7f54b4..d919371f1 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -14,6 +14,15 @@
"code",
"projectManagement"
]
+ },
+ {
+ "login": "amit1307",
+ "name": "amit1307",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/23420222?v=4",
+ "profile": "https://github.com/amit1307",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 55f11e702..04ddf6372 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -70,6 +70,7 @@ This project is licensed under the terms of the MIT license.
From 76f634ff7a10f4a9f1840680938318bd02af2738 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 27 Jul 2020 21:50:31 +0300
Subject: [PATCH 047/225] docs: add iluwatar as a contributor (#1346)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: create .all-contributorsrc [skip ci]
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 8 ++++++++
README.md | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index d919371f1..dbf65aeb8 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -12,6 +12,14 @@
"profile": "https://github.com/iluwatar",
"contributions": [
"code",
+ "projectManagement",
+ "maintenance",
+ "blog",
+ "content",
+ "doc",
+ "ideas",
+ "infra",
+ "review"
"projectManagement"
]
},
diff --git a/README.md b/README.md
index 04ddf6372..279f02028 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ This project is licensed under the terms of the MIT license.
From 02b6aba6ae25aae1c23823c0b458782d859f1e04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Mon, 27 Jul 2020 22:38:07 +0300
Subject: [PATCH 048/225] fix config syntax
---
.all-contributorsrc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index dbf65aeb8..9c7f063a7 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -19,7 +19,7 @@
"doc",
"ideas",
"infra",
- "review"
+ "review",
"projectManagement"
]
},
From 211d7903ae480e05cef03795779a00115050b216 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 27 Jul 2020 22:40:20 +0300
Subject: [PATCH 049/225] docs: add npathai as a contributor (#1347)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 13 +++++++++++++
README.md | 5 +++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 9c7f063a7..90490c998 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -31,6 +31,19 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "npathai",
+ "name": "Narendra Pathai",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/1792515?v=4",
+ "profile": "https://github.com/npathai",
+ "contributions": [
+ "code",
+ "ideas",
+ "maintenance",
+ "question",
+ "review"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 279f02028..bce11a908 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -69,8 +69,9 @@ This project is licensed under the terms of the MIT license.
From aea90ab115039ac008194e2743b365f2e2da3df4 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 27 Jul 2020 22:48:15 +0300
Subject: [PATCH 050/225] docs: add fluxw42 as a contributor (#1348)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 90490c998..25335e77a 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -44,6 +44,15 @@
"question",
"review"
]
+ },
+ {
+ "login": "fluxw42",
+ "name": "Jeroen Meulemeester",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/1545460?v=4",
+ "profile": "https://github.com/fluxw42",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index bce11a908..7525ddb43 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -72,6 +72,7 @@ This project is licensed under the terms of the MIT license.
 Ilkka Seppälä 💻 📆 🚧 📝 🖋 📖 🤔 🚇 👀 📆 |
 amit1307 💻 |
 Narendra Pathai 💻 🤔 🚧 💬 👀 |
+  Jeroen Meulemeester 💻 |
From 2c8535e839223a445220bef981b5591da12e4c4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Mon, 27 Jul 2020 23:07:58 +0300
Subject: [PATCH 051/225] max 3 contribution types per person
---
.all-contributorsrc | 11 +----------
README.md | 4 ++--
2 files changed, 3 insertions(+), 12 deletions(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 25335e77a..8e44fd9e2 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -11,16 +11,9 @@
"avatar_url": "https://avatars1.githubusercontent.com/u/582346?v=4",
"profile": "https://github.com/iluwatar",
"contributions": [
- "code",
"projectManagement",
"maintenance",
- "blog",
- "content",
- "doc",
- "ideas",
- "infra",
- "review",
- "projectManagement"
+ "content"
]
},
{
@@ -40,8 +33,6 @@
"contributions": [
"code",
"ideas",
- "maintenance",
- "question",
"review"
]
},
diff --git a/README.md b/README.md
index 7525ddb43..ba9fd307e 100644
--- a/README.md
+++ b/README.md
@@ -69,9 +69,9 @@ This project is licensed under the terms of the MIT license.
From 05dfd31fb7e55e185499f7fa3a2944b2690853c9 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 27 Jul 2020 23:14:34 +0300
Subject: [PATCH 052/225] docs: add mikulucky as a contributor (#1349)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 5 +++--
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 8e44fd9e2..cecc9e2dc 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -44,6 +44,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "mikulucky",
+ "name": "Joseph McCarthy",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/4526195?v=4",
+ "profile": "http://www.joemccarthy.co.uk",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index ba9fd307e..743017959 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -69,10 +69,11 @@ This project is licensed under the terms of the MIT license.
From 64eff5eb93da95bf55ce48222d1f41200424e785 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 27 Jul 2020 23:18:02 +0300
Subject: [PATCH 053/225] docs: add thomasoss as a contributor (#1350)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index cecc9e2dc..68751f4a7 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -53,6 +53,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "thomasoss",
+ "name": "Thomas",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/22516154?v=4",
+ "profile": "https://github.com/thomasoss",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 743017959..08f10e096 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -74,6 +74,7 @@ This project is licensed under the terms of the MIT license.
 Narendra Pathai 💻 🤔 👀 |
 Jeroen Meulemeester 💻 |
 Joseph McCarthy 💻 |
+  Thomas 💻 |
From 09dd0bee30519c7b4e0539744b2cb7a2f222fe97 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 27 Jul 2020 23:20:44 +0300
Subject: [PATCH 054/225] docs: add anuragagarwal561994 as a contributor
(#1351)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 68751f4a7..a3ed0c8f2 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -62,6 +62,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "anuragagarwal561994",
+ "name": "Anurag Agarwal",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/6075379?v=4",
+ "profile": "https://github.com/anuragagarwal561994",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 08f10e096..d8231ef7e 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -75,6 +75,7 @@ This project is licensed under the terms of the MIT license.
 Jeroen Meulemeester 💻 |
 Joseph McCarthy 💻 |
 Thomas 💻 |
+  Anurag Agarwal 💻 |
From d609f3eec69488e021b3bd34c9c08114b11f9c95 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:26:03 +0300
Subject: [PATCH 055/225] docs: add markusmo3 as a contributor (#1352)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 11 +++++++++++
README.md | 5 ++++-
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index a3ed0c8f2..4fda28295 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -71,6 +71,17 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "markusmo3",
+ "name": "Markus Moser",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/3317416?v=4",
+ "profile": "https://markusmo3.github.io",
+ "contributions": [
+ "design",
+ "code",
+ "ideas"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index d8231ef7e..d8f9f5e7a 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -77,6 +77,9 @@ This project is licensed under the terms of the MIT license.
 Thomas 💻 |
 Anurag Agarwal 💻 |
+
+  Markus Moser 🎨 💻 🤔 |
+
From b3eb6ccea424c54bf7cfab8c2ac36b8c467dd53e Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:28:35 +0300
Subject: [PATCH 056/225] docs: add isabiq as a contributor (#1353)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 4fda28295..113d84373 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -82,6 +82,15 @@
"code",
"ideas"
]
+ },
+ {
+ "login": "isabiq",
+ "name": "Sabiq Ihab",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/19510920?v=4",
+ "profile": "https://twitter.com/i_sabiq",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index d8f9f5e7a..c3aa4249e 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -79,6 +79,7 @@ This project is licensed under the terms of the MIT license.
 Markus Moser 🎨 💻 🤔 |
+  Sabiq Ihab 💻 |
From 960adfc37a3fd30bdf33f2c75256c79e8ce1d7ca Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:30:42 +0300
Subject: [PATCH 057/225] docs: add inbravo as a contributor (#1354)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 113d84373..8bcf19fb5 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -91,6 +91,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "inbravo",
+ "name": "Amit Dixit",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/5253764?v=4",
+ "profile": "http://inbravo.github.io",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index c3aa4249e..4dee660b8 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -80,6 +80,7 @@ This project is licensed under the terms of the MIT license.
 Markus Moser 🎨 💻 🤔 |
 Sabiq Ihab 💻 |
+  Amit Dixit 💻 |
From 781a7c8b52af7ff3edde4bb89ceb4456ed3b897c Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:32:58 +0300
Subject: [PATCH 058/225] docs: add piyushchaudhari04 as a contributor (#1355)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 8bcf19fb5..1b3b280e2 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -100,6 +100,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "piyushchaudhari04",
+ "name": "Piyush Kailash Chaudhari",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/10268029?v=4",
+ "profile": "https://github.com/piyushchaudhari04",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 4dee660b8..4f5c8b5b7 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -81,6 +81,7 @@ This project is licensed under the terms of the MIT license.
 Markus Moser 🎨 💻 🤔 |
 Sabiq Ihab 💻 |
 Amit Dixit 💻 |
+  Piyush Kailash Chaudhari 💻 |
From d6edeee326d03e8d85a246889afb6ef41e3f5d50 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:35:49 +0300
Subject: [PATCH 059/225] docs: add joshzambales as a contributor (#1356)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 1b3b280e2..bd011b233 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -109,6 +109,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "joshzambales",
+ "name": "joshzambales",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/8704552?v=4",
+ "profile": "https://github.com/joshzambales",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 4f5c8b5b7..5c559363f 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -82,6 +82,7 @@ This project is licensed under the terms of the MIT license.
 Sabiq Ihab 💻 |
 Amit Dixit 💻 |
 Piyush Kailash Chaudhari 💻 |
+  joshzambales 💻 |
From 1cb9c2bcde9c8a1c32e453bf4ab273b25b878e97 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:37:56 +0300
Subject: [PATCH 060/225] docs: add Crossy147 as a contributor (#1357)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index bd011b233..fdd99c31c 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -118,6 +118,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "Crossy147",
+ "name": "Kamil Pietruszka",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/7272996?v=4",
+ "profile": "https://github.com/Crossy147",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 5c559363f..d21e9a476 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -83,6 +83,7 @@ This project is licensed under the terms of the MIT license.
 Amit Dixit 💻 |
 Piyush Kailash Chaudhari 💻 |
 joshzambales 💻 |
+  Kamil Pietruszka 💻 |
From 8ba111fe60ffe21d6155cc98c82a7907814ba752 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:40:28 +0300
Subject: [PATCH 061/225] docs: add zafarella as a contributor (#1358)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 10 ++++++++++
README.md | 3 ++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index fdd99c31c..eb77506ca 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -127,6 +127,16 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "zafarella",
+ "name": "Zafar Khaydarov",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/660742?v=4",
+ "profile": "http://cs.joensuu.fi/~zkhayda",
+ "contributions": [
+ "code",
+ "doc"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index d21e9a476..cee9e18bc 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -84,6 +84,7 @@ This project is licensed under the terms of the MIT license.
 Piyush Kailash Chaudhari 💻 |
 joshzambales 💻 |
 Kamil Pietruszka 💻 |
+  Zafar Khaydarov 💻 📖 |
From 80605283f55a0abe33b01f4d337304d0107b64e2 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:42:27 +0300
Subject: [PATCH 062/225] docs: add kemitix as a contributor (#1359)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 5 ++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index eb77506ca..387c34849 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -137,6 +137,15 @@
"code",
"doc"
]
+ },
+ {
+ "login": "kemitix",
+ "name": "Paul Campbell",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/1147749?v=4",
+ "profile": "https://kemitix.github.io/",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index cee9e18bc..95d2724e6 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -86,6 +86,9 @@ This project is licensed under the terms of the MIT license.
 Kamil Pietruszka 💻 |
 Zafar Khaydarov 💻 📖 |
+
+  Paul Campbell 💻 |
+
From cf8e366e2518af8354f1879d3caf690ff0b93194 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:44:46 +0300
Subject: [PATCH 063/225] docs: add Argyro-Sioziou as a contributor (#1360)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 387c34849..a07d447af 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -146,6 +146,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "Argyro-Sioziou",
+ "name": "Argyro Sioziou",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/22822639?v=4",
+ "profile": "https://github.com/Argyro-Sioziou",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 95d2724e6..d1ca6e8bc 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -88,6 +88,7 @@ This project is licensed under the terms of the MIT license.
 Paul Campbell 💻 |
+  Argyro Sioziou 💻 |
From a77e9620b5274321e1753de42c3945d14b2bc2fd Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:46:41 +0300
Subject: [PATCH 064/225] docs: add TylerMcConville as a contributor (#1361)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index a07d447af..eb1b24798 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -155,6 +155,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "TylerMcConville",
+ "name": "TylerMcConville",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/4946449?v=4",
+ "profile": "https://github.com/TylerMcConville",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index d1ca6e8bc..b73859360 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -89,6 +89,7 @@ This project is licensed under the terms of the MIT license.
 Paul Campbell 💻 |
 Argyro Sioziou 💻 |
+  TylerMcConville 💻 |
From f360b64877fb459666c597fc0985408c49481af7 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:48:50 +0300
Subject: [PATCH 065/225] docs: add saksham93 as a contributor (#1362)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index eb1b24798..81e67d559 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -164,6 +164,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "saksham93",
+ "name": "saksham93",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/37399540?v=4",
+ "profile": "https://github.com/saksham93",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index b73859360..833d65eae 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -90,6 +90,7 @@ This project is licensed under the terms of the MIT license.
 Paul Campbell 💻 |
 Argyro Sioziou 💻 |
 TylerMcConville 💻 |
+  saksham93 💻 |
From c85d764e397029aedd3148a8338fabebf2956f88 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:50:39 +0300
Subject: [PATCH 066/225] docs: add nikhilbarar as a contributor (#1363)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 81e67d559..61f88d89a 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -173,6 +173,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "nikhilbarar",
+ "name": "nikhilbarar",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/37332144?v=4",
+ "profile": "https://github.com/nikhilbarar",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 833d65eae..ccfa6e4ff 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -91,6 +91,7 @@ This project is licensed under the terms of the MIT license.
 Argyro Sioziou 💻 |
 TylerMcConville 💻 |
 saksham93 💻 |
+  nikhilbarar 💻 |
From 4c766b9e71fe927e2fd39003d7f44c2a70c7b024 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:52:39 +0300
Subject: [PATCH 067/225] docs: add colinbut as a contributor (#1364)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 61f88d89a..c90df750f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -182,6 +182,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "colinbut",
+ "name": "Colin But",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/10725674?v=4",
+ "profile": "http://colinbut.com",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index ccfa6e4ff..5fa2d303e 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -92,6 +92,7 @@ This project is licensed under the terms of the MIT license.
 TylerMcConville 💻 |
 saksham93 💻 |
 nikhilbarar 💻 |
+  Colin But 💻 |
From d8f12529f2703845cd58c253ba7886c379ec9630 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:55:47 +0300
Subject: [PATCH 068/225] docs: add ruslanpa as a contributor (#1365)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index c90df750f..28abe71da 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -191,6 +191,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "ruslanpa",
+ "name": "Ruslan",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/1503411?v=4",
+ "profile": "https://github.com/ruslanpa",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 5fa2d303e..559f2a69c 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -93,6 +93,7 @@ This project is licensed under the terms of the MIT license.
 saksham93 💻 |
 nikhilbarar 💻 |
 Colin But 💻 |
+  Ruslan 💻 |
From 97adc13a1bcf09bf45d4a1a37b1384caa1de9b7a Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 17:57:26 +0300
Subject: [PATCH 069/225] docs: add JuhoKang as a contributor (#1366)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 5 ++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 28abe71da..d532a2baf 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -200,6 +200,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "JuhoKang",
+ "name": "Juho Kang",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/4745294?v=4",
+ "profile": "https://github.com/JuhoKang",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 559f2a69c..eab98e6c0 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -95,6 +95,9 @@ This project is licensed under the terms of the MIT license.
 Colin But 💻 |
 Ruslan 💻 |
+
+  Juho Kang 💻 |
+
From a5ff32c13ea3d66794bda314bc542a93eafa08aa Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:02:49 +0300
Subject: [PATCH 070/225] docs: add dheeraj-mummareddy as a contributor (#1367)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index d532a2baf..5f5df0ed5 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -209,6 +209,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "dheeraj-mummareddy",
+ "name": "Dheeraj Mummareddy",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/7002230?v=4",
+ "profile": "https://github.com/dheeraj-mummareddy",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index eab98e6c0..912cc1b25 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -97,6 +97,7 @@ This project is licensed under the terms of the MIT license.
 Juho Kang 💻 |
+  Dheeraj Mummareddy 💻 |
From 0563ac7645484ea12382d1c7240873c7607dbbc9 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:08:01 +0300
Subject: [PATCH 071/225] docs: add bernardosulzbach as a contributor (#1368)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 5f5df0ed5..512859f34 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -218,6 +218,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "bernardosulzbach",
+ "name": "Bernardo Sulzbach",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/8271090?v=4",
+ "profile": "https://www.bernardosulzbach.com",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 912cc1b25..bb324ec26 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -98,6 +98,7 @@ This project is licensed under the terms of the MIT license.
 Juho Kang 💻 |
 Dheeraj Mummareddy 💻 |
+  Bernardo Sulzbach 💻 |
From 5b269d5af1e7dd3eaf7b0e9e5b4363faedbb5abd Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:09:43 +0300
Subject: [PATCH 072/225] docs: add 4lexis as a contributor (#1369)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 512859f34..3d129d1a1 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -227,6 +227,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "4lexis",
+ "name": "Aleksandar Dudukovic",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/19871727?v=4",
+ "profile": "https://github.com/4lexis",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index bb324ec26..8da13c04e 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -99,6 +99,7 @@ This project is licensed under the terms of the MIT license.
 Juho Kang 💻 |
 Dheeraj Mummareddy 💻 |
 Bernardo Sulzbach 💻 |
+  Aleksandar Dudukovic 💻 |
From 03ebd5f353edcb6becfc0e6c1ca1944e131c689d Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:11:29 +0300
Subject: [PATCH 073/225] docs: add yusufaytas as a contributor (#1370)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 3d129d1a1..2d1a8c2ab 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -236,6 +236,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "yusufaytas",
+ "name": "Yusuf Aytaş",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/1049483?v=4",
+ "profile": "https://www.yusufaytas.com",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 8da13c04e..d3485ec5c 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -100,6 +100,7 @@ This project is licensed under the terms of the MIT license.
 Dheeraj Mummareddy 💻 |
 Bernardo Sulzbach 💻 |
 Aleksandar Dudukovic 💻 |
+  Yusuf Aytaş 💻 |
From 2706c8fc37037d7a5fa7bca319038112d3addc3b Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:13:03 +0300
Subject: [PATCH 074/225] docs: add qpi as a contributor (#1371)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 2d1a8c2ab..d51e82608 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -245,6 +245,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "qpi",
+ "name": "Mihály Kuprivecz",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/1001491?v=4",
+ "profile": "http://futurehomes.hu",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index d3485ec5c..2646704d8 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -101,6 +101,7 @@ This project is licensed under the terms of the MIT license.
 Bernardo Sulzbach 💻 |
 Aleksandar Dudukovic 💻 |
 Yusuf Aytaş 💻 |
+  Mihály Kuprivecz 💻 |
From 452981669b5b95a0b3c78453a456eaf22f4cc2e7 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:14:37 +0300
Subject: [PATCH 075/225] docs: add kapinuss as a contributor (#1372)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index d51e82608..42d3fd6ce 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -254,6 +254,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "kapinuss",
+ "name": "Stanislav Kapinus",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/17639945?v=4",
+ "profile": "https://github.com/kapinuss",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 2646704d8..b8ea48ef0 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -102,6 +102,7 @@ This project is licensed under the terms of the MIT license.
 Aleksandar Dudukovic 💻 |
 Yusuf Aytaş 💻 |
 Mihály Kuprivecz 💻 |
+  Stanislav Kapinus 💻 |
From 0cff538c271ffdae6eb6adadc9ac4fde7f7fe2fc Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:16:14 +0300
Subject: [PATCH 076/225] docs: add gvsharma as a contributor (#1373)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 5 ++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 42d3fd6ce..ceefb272f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -263,6 +263,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "gvsharma",
+ "name": "GVSharma",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/6648152?v=4",
+ "profile": "https://github.com/gvsharma",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index b8ea48ef0..3ec2bcbab 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -104,6 +104,9 @@ This project is licensed under the terms of the MIT license.
 Mihály Kuprivecz 💻 |
 Stanislav Kapinus 💻 |
+
+  GVSharma 💻 |
+
From b805a7526eb7b741933a041992f0b610b50d0390 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:17:42 +0300
Subject: [PATCH 077/225] docs: add SrdjanPaunovic as a contributor (#1374)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index ceefb272f..7c71a2167 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -272,6 +272,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "SrdjanPaunovic",
+ "name": "Srđan Paunović",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/22815104?v=4",
+ "profile": "https://github.com/SrdjanPaunovic",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 3ec2bcbab..514df2349 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -106,6 +106,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
+  Srđan Paunović 💻 |
From d94199f5fff6cf83604d3aaa8b2b130315e2f5a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Tue, 28 Jul 2020 18:23:47 +0300
Subject: [PATCH 078/225] update readme
---
README.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/README.md b/README.md
index 514df2349..eafae6ef5 100644
--- a/README.md
+++ b/README.md
@@ -113,5 +113,3 @@ This project is licensed under the terms of the MIT license.
-
-This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
From 0bc3756250ef110a1c6adfd910cc1ecf0ededefd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Tue, 28 Jul 2020 18:49:46 +0300
Subject: [PATCH 079/225] update all-contributors config
---
.all-contributorsrc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 7c71a2167..bdd7dfdaa 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -283,7 +283,7 @@
]
}
],
- "contributorsPerLine": 7,
+ "contributorsPerLine": 4,
"projectName": "java-design-patterns",
"projectOwner": "iluwatar",
"repoType": "github",
From 96344142e9064e5afd08c3c8450b38419ca3528b Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:52:31 +0300
Subject: [PATCH 080/225] docs: add sideris as a contributor (#1375)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 17 ++++++++++++-----
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index bdd7dfdaa..1d6b1aabc 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -281,6 +281,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "sideris",
+ "name": "Petros G. Sideris",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/5484694?v=4",
+ "profile": "https://sideris.xyz/",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 4,
diff --git a/README.md b/README.md
index eafae6ef5..55e167ef8 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -73,32 +73,38 @@ This project is licensed under the terms of the MIT license.
 amit1307 💻 |
 Narendra Pathai 💻 🤔 👀 |
 Jeroen Meulemeester 💻 |
+
+
 Joseph McCarthy 💻 |
 Thomas 💻 |
 Anurag Agarwal 💻 |
+  Markus Moser 🎨 💻 🤔 |
-  Markus Moser 🎨 💻 🤔 |
 Sabiq Ihab 💻 |
 Amit Dixit 💻 |
 Piyush Kailash Chaudhari 💻 |
 joshzambales 💻 |
-  Kamil Pietruszka 💻 |
-  Zafar Khaydarov 💻 📖 |
+  Kamil Pietruszka 💻 |
+  Zafar Khaydarov 💻 📖 |
 Paul Campbell 💻 |
 Argyro Sioziou 💻 |
+
+
 TylerMcConville 💻 |
 saksham93 💻 |
 nikhilbarar 💻 |
 Colin But 💻 |
-  Ruslan 💻 |
+  Ruslan 💻 |
 Juho Kang 💻 |
 Dheeraj Mummareddy 💻 |
 Bernardo Sulzbach 💻 |
+
+
 Aleksandar Dudukovic 💻 |
 Yusuf Aytaş 💻 |
 Mihály Kuprivecz 💻 |
@@ -107,6 +113,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
+  Petros G. Sideris 💻 |
From c0d2c7fdb04a239488db9457197d095173fc1b79 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 20:23:30 +0300
Subject: [PATCH 081/225] docs: add robertt240 as a contributor (#1376)
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 1d6b1aabc..f5238558b 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -290,6 +290,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "robertt240",
+ "name": "Robert Kasperczyk",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/9137432?v=4",
+ "profile": "https://github.com/robertt240",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 4,
diff --git a/README.md b/README.md
index 55e167ef8..026ba94e3 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
-[](#contributors-)
+[](#contributors-)
# Introduction
@@ -114,6 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
+  Robert Kasperczyk 💻 |
From cfba28f9a4a0017d22506a7655e97c648413a79b Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 20:33:05 +0300
Subject: [PATCH 082/225] docs: add okinskas as a contributor (#1377)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index f5238558b..9780bbbf8 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "okinskas",
+ "name": "Ovidijus Okinskas",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/20372387?v=4",
+ "profile": "https://www.linkedin.com/in/ovidijus-okinskas/",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "robertt240",
"name": "Robert Kasperczyk",
diff --git a/README.md b/README.md
index 026ba94e3..4e931dca2 100644
--- a/README.md
+++ b/README.md
@@ -114,6 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
+  Ovidijus Okinskas 💻 |
 Robert Kasperczyk 💻 |
From 2b095bec283932368a7111463ae0082836c0afdf Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 20:37:11 +0300
Subject: [PATCH 083/225] docs: add ankurkaushal as a contributor (#1378)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 9780bbbf8..724d5e0d7 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "ankurkaushal",
+ "name": "Ankur Kaushal",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/2236616?v=4",
+ "profile": "https://github.com/ankurkaushal",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "okinskas",
"name": "Ovidijus Okinskas",
diff --git a/README.md b/README.md
index 4e931dca2..7e71b1e62 100644
--- a/README.md
+++ b/README.md
@@ -114,6 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
+  Ankur Kaushal 💻 |
 Ovidijus Okinskas 💻 |
 Robert Kasperczyk 💻 |
From f85e4db0bed8b96864375028d90ee31bf05f9ccc Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 20:40:11 +0300
Subject: [PATCH 084/225] docs: add Tschis as a contributor (#1379)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 724d5e0d7..cfc3cdfc5 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "Tschis",
+ "name": "Rodolfo Forte",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/20662669?v=4",
+ "profile": "http://tschis.github.io",
+ "contributions": [
+ "content"
+ ]
+ },
{
"login": "ankurkaushal",
"name": "Ankur Kaushal",
diff --git a/README.md b/README.md
index 7e71b1e62..506948ca9 100644
--- a/README.md
+++ b/README.md
@@ -114,6 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
+  Rodolfo Forte 🖋 |
 Ankur Kaushal 💻 |
 Ovidijus Okinskas 💻 |
 Robert Kasperczyk 💻 |
From 60ab9fa3ceb61e63acf8267507a502a8433ded70 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 20:43:09 +0300
Subject: [PATCH 085/225] docs: add qza as a contributor (#1380)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index cfc3cdfc5..9b817c42d 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "qza",
+ "name": "qza",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/233149?v=4",
+ "profile": "https://github.com/qza",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "Tschis",
"name": "Rodolfo Forte",
diff --git a/README.md b/README.md
index 506948ca9..ad0a2fa5d 100644
--- a/README.md
+++ b/README.md
@@ -114,6 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
+  qza 💻 |
 Rodolfo Forte 🖋 |
 Ankur Kaushal 💻 |
 Ovidijus Okinskas 💻 |
From 023865ad4c5b63f85bf1b6d001636543ff354f0e Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 20:45:59 +0300
Subject: [PATCH 086/225] docs: add pitsios-s as a contributor (#1381)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 9b817c42d..df2e3e857 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "pitsios-s",
+ "name": "Stamatis Pitsios",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/6773603?v=4",
+ "profile": "https://twitter.com/StPitsios",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "qza",
"name": "qza",
diff --git a/README.md b/README.md
index ad0a2fa5d..94615bf9c 100644
--- a/README.md
+++ b/README.md
@@ -114,6 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
+  Stamatis Pitsios 💻 |
 qza 💻 |
 Rodolfo Forte 🖋 |
 Ankur Kaushal 💻 |
From 0358fcec4c1f35c84d631e214c81bb6b96e2c74b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?=
Date: Tue, 28 Jul 2020 20:53:31 +0300
Subject: [PATCH 087/225] update readme
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 94615bf9c..97e3111cf 100644
--- a/README.md
+++ b/README.md
@@ -115,10 +115,14 @@ This project is licensed under the terms of the MIT license.
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
 Stamatis Pitsios 💻 |
+
+
 qza 💻 |
 Rodolfo Forte 🖋 |
 Ankur Kaushal 💻 |
 Ovidijus Okinskas 💻 |
+
+
 Robert Kasperczyk 💻 |
From eb8ddde98ffd9d63dce24ddd8f76a00649520889 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 17:36:32 +0300
Subject: [PATCH 088/225] docs: add llitfkitfk as a contributor (#1382)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index df2e3e857..3d7e4065e 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "llitfkitfk",
+ "name": "田浩",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/2404785?v=4",
+ "profile": "https://t.me/paul_docker",
+ "contributions": [
+ "content"
+ ]
+ },
{
"login": "pitsios-s",
"name": "Stamatis Pitsios",
diff --git a/README.md b/README.md
index 97e3111cf..79f9b34ff 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  Stamatis Pitsios 💻 |
+  田浩 🖋 |
 qza 💻 |
@@ -123,6 +123,7 @@ This project is licensed under the terms of the MIT license.
 Ovidijus Okinskas 💻 |
+  Stamatis Pitsios 💻 |
 Robert Kasperczyk 💻 |
From 8d6791490b63dbbfab8c093378c730eeee805bcd Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 17:39:11 +0300
Subject: [PATCH 089/225] docs: add gwildor28 as a contributor (#1383)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 3d7e4065e..f37d603e5 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "gwildor28",
+ "name": "gwildor28",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/16000365?v=4",
+ "profile": "https://github.com/gwildor28",
+ "contributions": [
+ "content"
+ ]
+ },
{
"login": "llitfkitfk",
"name": "田浩",
diff --git a/README.md b/README.md
index 79f9b34ff..104d7afa2 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  田浩 🖋 |
+  gwildor28 💻 |
 qza 💻 |
@@ -125,6 +125,7 @@ This project is licensed under the terms of the MIT license.
 Stamatis Pitsios 💻 |
 Robert Kasperczyk 💻 |
+  田浩 🖋 |
From 39e5436ed5ed13c1ff81487a08cd5b2d30eca0a5 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 17:41:35 +0300
Subject: [PATCH 090/225] docs: add amit2103 as a contributor (#1384)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index f37d603e5..c9c27ed6b 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "amit2103",
+ "name": "Amit Pandey",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/7566692?v=4",
+ "profile": "https://github.com/amit2103",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "gwildor28",
"name": "gwildor28",
diff --git a/README.md b/README.md
index 104d7afa2..1417b68d3 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  gwildor28 💻 |
+  Amit Pandey 💻 |
 qza 💻 |
@@ -126,6 +126,7 @@ This project is licensed under the terms of the MIT license.
 Stamatis Pitsios 💻 |
 Robert Kasperczyk 💻 |
 田浩 🖋 |
+  gwildor28 💻 |
From 81824057968557335d4812093ddc70ec7c12e73c Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 17:44:05 +0300
Subject: [PATCH 091/225] docs: add hoswey as a contributor (#1385)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 5 ++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index c9c27ed6b..ef533e802 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "hoswey",
+ "name": "Hoswey",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/3689445?v=4",
+ "profile": "https://github.com/hoswey",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "amit2103",
"name": "Amit Pandey",
diff --git a/README.md b/README.md
index 1417b68d3..e9cb72003 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  Amit Pandey 💻 |
+  Hoswey 💻 |
 qza 💻 |
@@ -128,6 +128,9 @@ This project is licensed under the terms of the MIT license.
 田浩 🖋 |
 gwildor28 💻 |
+
+  Amit Pandey 💻 |
+
From 37bffb4a99865f4ca34a4d4ac6816a52e8b79b9f Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 17:47:06 +0300
Subject: [PATCH 092/225] docs: add gopinath-langote as a contributor (#1386)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index ef533e802..21d993c64 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "gopinath-langote",
+ "name": "Gopinath Langote",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/10210778?v=4",
+ "profile": "https://www.linkedin.com/in/gopinathlangote/",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "hoswey",
"name": "Hoswey",
diff --git a/README.md b/README.md
index e9cb72003..d9fba1e99 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  Hoswey 💻 |
+  Gopinath Langote 💻 |
 qza 💻 |
@@ -130,6 +130,7 @@ This project is licensed under the terms of the MIT license.
 Amit Pandey 💻 |
+  Hoswey 💻 |
From 8c21809dad7caf2d42d19e32c1eead5c6fc6de8e Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 17:49:00 +0300
Subject: [PATCH 093/225] docs: add ThatGuyWithTheHat as a contributor (#1387)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 21d993c64..edef8c2c5 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "ThatGuyWithTheHat",
+ "name": "Matt",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/24470582?v=4",
+ "profile": "https://github.com/ThatGuyWithTheHat",
+ "contributions": [
+ "content"
+ ]
+ },
{
"login": "gopinath-langote",
"name": "Gopinath Langote",
diff --git a/README.md b/README.md
index d9fba1e99..5d9b81ca7 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  Gopinath Langote 💻 |
+  Matt 🖋 |
 qza 💻 |
@@ -131,6 +131,7 @@ This project is licensed under the terms of the MIT license.
 Amit Pandey 💻 |
 Hoswey 💻 |
+  Gopinath Langote 💻 |
From 5a23fab795d1588a2cada9e923eb8856ff2398a0 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 17:50:53 +0300
Subject: [PATCH 094/225] docs: add vehpsr as a contributor (#1389)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index edef8c2c5..e1b8032cb 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "vehpsr",
+ "name": "gans",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/3133265?v=4",
+ "profile": "https://github.com/vehpsr",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "ThatGuyWithTheHat",
"name": "Matt",
diff --git a/README.md b/README.md
index 5d9b81ca7..62c70ae2f 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  Matt 🖋 |
+  gans 💻 |
 qza 💻 |
@@ -132,6 +132,7 @@ This project is licensed under the terms of the MIT license.
 Amit Pandey 💻 |
 Hoswey 💻 |
 Gopinath Langote 💻 |
+  Matt 🖋 |
From c0d7c8922e82eb02cbeff2b331dc8b1ed30924b8 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 17:53:30 +0300
Subject: [PATCH 095/225] docs: add Azureyjt as a contributor (#1388)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 5 ++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index e1b8032cb..7a1681230 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "Azureyjt",
+ "name": "Azureyjt",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/18476317?v=4",
+ "profile": "https://github.com/Azureyjt",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "vehpsr",
"name": "gans",
diff --git a/README.md b/README.md
index 62c70ae2f..6b90e2df8 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  gans 💻 |
+  Azureyjt 💻 |
 qza 💻 |
@@ -134,6 +134,9 @@ This project is licensed under the terms of the MIT license.
 Gopinath Langote 💻 |
 Matt 🖋 |
+
+  gans 💻 |
+
From 7968615ad466c86b9d68cd25eee5d9a53a27f682 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 17:55:53 +0300
Subject: [PATCH 096/225] docs: add mookkiah as a contributor (#1390)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 7a1681230..ec24b3888 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "mookkiah",
+ "name": "Mahendran Mookkiah",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/8975264?v=4",
+ "profile": "https://github.com/mookkiah",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "Azureyjt",
"name": "Azureyjt",
diff --git a/README.md b/README.md
index 6b90e2df8..ac8ab189a 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  Azureyjt 💻 |
+  Mahendran Mookkiah 💻 |
 qza 💻 |
@@ -136,6 +136,7 @@ This project is licensed under the terms of the MIT license.
 gans 💻 |
+  Azureyjt 💻 |
From c5479cc882d3a1ff8c52fedd8ec8d6371bb64368 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 17:58:00 +0300
Subject: [PATCH 097/225] docs: add llorllale as a contributor (#1391)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index ec24b3888..02b8d2f37 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "llorllale",
+ "name": "George Aristy",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/2019896?v=4",
+ "profile": "https://llorllale.github.io/",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "mookkiah",
"name": "Mahendran Mookkiah",
diff --git a/README.md b/README.md
index ac8ab189a..8869d6e26 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  Mahendran Mookkiah 💻 |
+  George Aristy 💻 |
 qza 💻 |
@@ -137,6 +137,7 @@ This project is licensed under the terms of the MIT license.
 gans 💻 |
 Azureyjt 💻 |
+  Mahendran Mookkiah 💻 |
From c2fb5917496f001fc4293e2a4f7beb3a2af5542c Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:00:07 +0300
Subject: [PATCH 098/225] docs: add igeligel as a contributor (#1392)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 02b8d2f37..71677e31f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "igeligel",
+ "name": "Kevin Peters",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/12736734?v=4",
+ "profile": "https://www.kevinpeters.net/about/",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "llorllale",
"name": "George Aristy",
diff --git a/README.md b/README.md
index 8869d6e26..f8d66532b 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  George Aristy 💻 |
+  Kevin Peters 💻 |
 qza 💻 |
@@ -138,6 +138,7 @@ This project is licensed under the terms of the MIT license.
 gans 💻 |
 Azureyjt 💻 |
 Mahendran Mookkiah 💻 |
+  George Aristy 💻 |
From d1de4657801a2f4715673f79102cbf181e89e819 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:02:13 +0300
Subject: [PATCH 099/225] docs: add hbothra15 as a contributor (#1393)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 5 ++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 71677e31f..c7cef5bea 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "hbothra15",
+ "name": "Hemant Bothra",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/7418012?v=4",
+ "profile": "https://github.com/hbothra15",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "igeligel",
"name": "Kevin Peters",
diff --git a/README.md b/README.md
index f8d66532b..1b57fa8ab 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  Kevin Peters 💻 |
+  Hemant Bothra 💻 |
 qza 💻 |
@@ -140,6 +140,9 @@ This project is licensed under the terms of the MIT license.
 Mahendran Mookkiah 💻 |
 George Aristy 💻 |
+
+  Kevin Peters 💻 |
+
From ec80402fe50b81cc651946a48c7aa0b0f5b9e224 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:05:22 +0300
Subject: [PATCH 100/225] docs: add giorgosmav21 as a contributor (#1394)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index c7cef5bea..9518ede79 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "giorgosmav21",
+ "name": "George Mavroeidis",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/22855493?v=4",
+ "profile": "https://github.com/giorgosmav21",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "hbothra15",
"name": "Hemant Bothra",
diff --git a/README.md b/README.md
index 1b57fa8ab..12ba1a7e4 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  Hemant Bothra 💻 |
+  George Mavroeidis 💻 |
 qza 💻 |
@@ -142,6 +142,7 @@ This project is licensed under the terms of the MIT license.
 Kevin Peters 💻 |
+  Hemant Bothra 💻 |
From be54dc1c7e24e71d6fdae7069811e6eddf4f06c5 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:07:15 +0300
Subject: [PATCH 101/225] docs: add oconnelc as a contributor (#1395)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 9518ede79..25192ed78 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "oconnelc",
+ "name": "Christopher O'Connell",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/1112973?v=4",
+ "profile": "https://github.com/oconnelc",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "giorgosmav21",
"name": "George Mavroeidis",
diff --git a/README.md b/README.md
index 12ba1a7e4..d1cbd2f1c 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  George Mavroeidis 💻 |
+  Christopher O'Connell 💻 |
 qza 💻 |
@@ -143,6 +143,7 @@ This project is licensed under the terms of the MIT license.
 Kevin Peters 💻 |
 Hemant Bothra 💻 |
+  George Mavroeidis 💻 |
From ba485e2c3efb6669cece11164f93fb9bd4186316 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:09:00 +0300
Subject: [PATCH 102/225] docs: add npczwh as a contributor (#1396)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 25192ed78..17c9bc3d6 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "npczwh",
+ "name": "Zhang WH",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/14066422?v=4",
+ "profile": "https://github.com/npczwh",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "oconnelc",
"name": "Christopher O'Connell",
diff --git a/README.md b/README.md
index d1cbd2f1c..227c62c60 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ This project is licensed under the terms of the MIT license.
 GVSharma 💻 |
 Srđan Paunović 💻 |
 Petros G. Sideris 💻 |
-  Christopher O'Connell 💻 |
+  Zhang WH 💻 |
 qza 💻 |
@@ -144,6 +144,7 @@ This project is licensed under the terms of the MIT license.
 Kevin Peters 💻 |
 Hemant Bothra 💻 |
 George Mavroeidis 💻 |
+  Christopher O'Connell 💻 |
From d791c785014b200b38c95d07859cabf9f8a16b8b Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:11:09 +0300
Subject: [PATCH 103/225] docs: add leogtzr as a contributor (#1397)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 +++
2 files changed, 12 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 17c9bc3d6..985bd474f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "leogtzr",
+ "name": "Leo Gutiérrez Ramírez",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/1211969?v=4",
+ "profile": "https://github.com/leogtzr",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "npczwh",
"name": "Zhang WH",
diff --git a/README.md b/README.md
index 227c62c60..7e2ffc3d3 100644
--- a/README.md
+++ b/README.md
@@ -146,6 +146,9 @@ This project is licensed under the terms of the MIT license.
 George Mavroeidis 💻 |
 Christopher O'Connell 💻 |
+
+  Leo Gutiérrez Ramírez 💻 |
+
From e924c9399ad236da1db94edd049147a3975fa007 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:12:47 +0300
Subject: [PATCH 104/225] docs: add hannespernpeintner as a contributor (#1398)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 985bd474f..69a4de8f3 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "hannespernpeintner",
+ "name": "Hannes",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/1679437?v=4",
+ "profile": "https://bitbucket.org/hannespernpeintner/",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "leogtzr",
"name": "Leo Gutiérrez Ramírez",
diff --git a/README.md b/README.md
index 7e2ffc3d3..9ceb86f80 100644
--- a/README.md
+++ b/README.md
@@ -148,6 +148,7 @@ This project is licensed under the terms of the MIT license.
 Leo Gutiérrez Ramírez 💻 |
+  Hannes 💻 |
From 8137609e2f4a3ff7a9d43615c2707f634d699f70 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:14:30 +0300
Subject: [PATCH 105/225] docs: add dgruntz as a contributor (#1399)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 69a4de8f3..c36df4855 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "dgruntz",
+ "name": "Dominik Gruntz",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/1516800?v=4",
+ "profile": "https://github.com/dgruntz",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "hannespernpeintner",
"name": "Hannes",
diff --git a/README.md b/README.md
index 9ceb86f80..fef0bf614 100644
--- a/README.md
+++ b/README.md
@@ -149,6 +149,7 @@ This project is licensed under the terms of the MIT license.
 Leo Gutiérrez Ramírez 💻 |
 Hannes 💻 |
+  Dominik Gruntz 💻 |
From 46fdc5a54f0b4ec741f4dae395acf5d9ffe35eaf Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:16:12 +0300
Subject: [PATCH 106/225] docs: add christofferh as a contributor (#1400)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index c36df4855..8e0e6d13a 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "christofferh",
+ "name": "Christoffer Hamberg",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/767643?v=4",
+ "profile": "https://christofferh.com",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "dgruntz",
"name": "Dominik Gruntz",
diff --git a/README.md b/README.md
index fef0bf614..9720fbad5 100644
--- a/README.md
+++ b/README.md
@@ -150,6 +150,7 @@ This project is licensed under the terms of the MIT license.
 Leo Gutiérrez Ramírez 💻 |
 Hannes 💻 |
 Dominik Gruntz 💻 |
+  Christoffer Hamberg 💻 |
From a727a1d05b79b17ca2dd1a926d67cf8e651dcc52 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:18:07 +0300
Subject: [PATCH 107/225] docs: add AnaghaSasikumar as a contributor (#1401)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 +++
2 files changed, 12 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 8e0e6d13a..ca442aa6e 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "AnaghaSasikumar",
+ "name": "AnaghaSasikumar",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/42939261?v=4",
+ "profile": "https://github.com/AnaghaSasikumar",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "christofferh",
"name": "Christoffer Hamberg",
diff --git a/README.md b/README.md
index 9720fbad5..508a1dbef 100644
--- a/README.md
+++ b/README.md
@@ -152,6 +152,9 @@ This project is licensed under the terms of the MIT license.
 Dominik Gruntz 💻 |
 Christoffer Hamberg 💻 |
+
+  AnaghaSasikumar 💻 |
+
From 96bfb8bd9f1c293634828c0fd8e5ef074a4821f8 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:19:53 +0300
Subject: [PATCH 108/225] docs: add waisuan as a contributor (#1402)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index ca442aa6e..94158246d 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "waisuan",
+ "name": "Evan Sia Wai Suan",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/10975700?v=4",
+ "profile": "https://github.com/waisuan",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "AnaghaSasikumar",
"name": "AnaghaSasikumar",
diff --git a/README.md b/README.md
index 508a1dbef..6a091ea20 100644
--- a/README.md
+++ b/README.md
@@ -154,6 +154,7 @@ This project is licensed under the terms of the MIT license.
 AnaghaSasikumar 💻 |
+  Evan Sia Wai Suan 💻 |
From 09880e3850277b372975089725a7d3cdf8754a37 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:21:41 +0300
Subject: [PATCH 109/225] docs: add perwramdemark as a contributor (#1403)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 94158246d..a2cfd2a03 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "perwramdemark",
+ "name": "Per Wramdemark",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/7052193?v=4",
+ "profile": "http://www.wramdemark.se",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "waisuan",
"name": "Evan Sia Wai Suan",
diff --git a/README.md b/README.md
index 6a091ea20..51c774275 100644
--- a/README.md
+++ b/README.md
@@ -155,6 +155,7 @@ This project is licensed under the terms of the MIT license.
 AnaghaSasikumar 💻 |
 Evan Sia Wai Suan 💻 |
+  Per Wramdemark 💻 |
From 19929d9e7215223eddc03b5f1e950b7ec164297d Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:23:23 +0300
Subject: [PATCH 110/225] docs: add leonmak as a contributor (#1404)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 +++
2 files changed, 12 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index a2cfd2a03..fa19cf391 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "leonmak",
+ "name": "Leon Mak",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/13071508?v=4",
+ "profile": "http://leonmak.me",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "perwramdemark",
"name": "Per Wramdemark",
diff --git a/README.md b/README.md
index 51c774275..abea00951 100644
--- a/README.md
+++ b/README.md
@@ -156,6 +156,9 @@ This project is licensed under the terms of the MIT license.
 AnaghaSasikumar 💻 |
 Evan Sia Wai Suan 💻 |
 Per Wramdemark 💻 |
+  Leon Mak 💻 |
+
+
From a70213f8521cadab757ed874183e7d4c43e6ac50 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:25:03 +0300
Subject: [PATCH 111/225] docs: add kanwarpreet25 as a contributor (#1405)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index fa19cf391..7b91a7aa5 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "kanwarpreet25",
+ "name": "kanwarpreet25",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/39183641?v=4",
+ "profile": "https://github.com/kanwarpreet25",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "leonmak",
"name": "Leon Mak",
diff --git a/README.md b/README.md
index abea00951..53f0fedbb 100644
--- a/README.md
+++ b/README.md
@@ -159,6 +159,7 @@ This project is licensed under the terms of the MIT license.
 Leon Mak 💻 |
+  kanwarpreet25 💻 |
From 54bb02f69131cccd0b6655e19de3df3e314e6ea8 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:26:34 +0300
Subject: [PATCH 112/225] docs: add MSaifAsif as a contributor (#1406)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 7b91a7aa5..1fadb0530 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "MSaifAsif",
+ "name": "M Saif Asif",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/6280554?v=4",
+ "profile": "https://github.com/MSaifAsif",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "kanwarpreet25",
"name": "kanwarpreet25",
diff --git a/README.md b/README.md
index 53f0fedbb..708a62ca6 100644
--- a/README.md
+++ b/README.md
@@ -160,6 +160,7 @@ This project is licensed under the terms of the MIT license.
 kanwarpreet25 💻 |
+  M Saif Asif 💻 |
From e2a42b0051f4818908936aee5627329e1309cbfe Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:28:10 +0300
Subject: [PATCH 113/225] docs: add Alwayswithme as a contributor (#1407)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 1fadb0530..782955f0c 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "Alwayswithme",
+ "name": "PhoenixYip",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/3234786?v=4",
+ "profile": "https://alwayswithme.github.io",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "MSaifAsif",
"name": "M Saif Asif",
diff --git a/README.md b/README.md
index 708a62ca6..173485073 100644
--- a/README.md
+++ b/README.md
@@ -161,6 +161,7 @@ This project is licensed under the terms of the MIT license.
 kanwarpreet25 💻 |
 M Saif Asif 💻 |
+  PhoenixYip 💻 |
From fe2f8f74a1d1126d5de4e3fa5c598038ec9b7a8d Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:29:41 +0300
Subject: [PATCH 114/225] docs: add ranjeet-floyd as a contributor (#1408)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 782955f0c..27e8872d7 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "ranjeet-floyd",
+ "name": "Ranjeet",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/1992972?v=4",
+ "profile": "https://ranjeet-floyd.github.io",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "Alwayswithme",
"name": "PhoenixYip",
diff --git a/README.md b/README.md
index 173485073..46a1443e7 100644
--- a/README.md
+++ b/README.md
@@ -162,6 +162,7 @@ This project is licensed under the terms of the MIT license.
 kanwarpreet25 💻 |
 M Saif Asif 💻 |
 PhoenixYip 💻 |
+  Ranjeet 💻 |
From 8e268cf261cd23f5de815f32da2d9c2b417d5c1a Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:32:59 +0300
Subject: [PATCH 115/225] docs: add mitchellirvin as a contributor (#1409)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 11 +++++++++++
2 files changed, 20 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 27e8872d7..4b9a0dd1a 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "mitchellirvin",
+ "name": "Mitchell Irvin",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/16233245?v=4",
+ "profile": "http://mitchell-irvin.com",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "ranjeet-floyd",
"name": "Ranjeet",
diff --git a/README.md b/README.md
index 46a1443e7..d587771d1 100644
--- a/README.md
+++ b/README.md
@@ -164,6 +164,17 @@ This project is licensed under the terms of the MIT license.
 PhoenixYip 💻 |
 Ranjeet 💻 |
+  Mitchell Irvin 💻 |
+
+
+
+
+
+
+
+
+
+
From 9b5ae765fccfaac7be5fec221a48b0f0dde9ad54 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:34:45 +0300
Subject: [PATCH 116/225] docs: add kirill-vlasov as a contributor (#1410)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 4b9a0dd1a..6d3a4741f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "kirill-vlasov",
+ "name": "Kirill Vlasov",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/16112495?v=4",
+ "profile": "https://github.com/kirill-vlasov",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "mitchellirvin",
"name": "Mitchell Irvin",
diff --git a/README.md b/README.md
index d587771d1..f12fcb9ab 100644
--- a/README.md
+++ b/README.md
@@ -166,6 +166,7 @@ This project is licensed under the terms of the MIT license.
 Mitchell Irvin 💻 |
+  Kirill Vlasov 💻 |
From 1bc77a80f2b8fcafc52e611af600f9a77d77c744 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:36:27 +0300
Subject: [PATCH 117/225] docs: add joningiwork as a contributor (#1411)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 6d3a4741f..7352e906e 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "joningiwork",
+ "name": "Jón Ingi Sveinbjörnsson",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/6115148?v=4",
+ "profile": "http://joningi.net",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "kirill-vlasov",
"name": "Kirill Vlasov",
diff --git a/README.md b/README.md
index f12fcb9ab..655c71e26 100644
--- a/README.md
+++ b/README.md
@@ -167,6 +167,7 @@ This project is licensed under the terms of the MIT license.
 Mitchell Irvin 💻 |
 Kirill Vlasov 💻 |
+  Jón Ingi Sveinbjörnsson 💻 |
From a475df845bf44163ce49c9289371d08436d27bb5 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:38:07 +0300
Subject: [PATCH 118/225] docs: add jarpit96 as a contributor (#1412)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 7352e906e..ffe698d84 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "jarpit96",
+ "name": "Arpit Jain",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/10098713?v=4",
+ "profile": "https://github.com/jarpit96",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "joningiwork",
"name": "Jón Ingi Sveinbjörnsson",
diff --git a/README.md b/README.md
index 655c71e26..c59bfac02 100644
--- a/README.md
+++ b/README.md
@@ -165,6 +165,7 @@ This project is licensed under the terms of the MIT license.
 Ranjeet 💻 |
 Mitchell Irvin 💻 |
+  Arpit Jain 💻 |
 Kirill Vlasov 💻 |
 Jón Ingi Sveinbjörnsson 💻 |
From 2a66fec6fe509a2b3a96d086d3e7265aebf823b1 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:41:17 +0300
Subject: [PATCH 119/225] docs: add hoangnam2261 as a contributor (#1413)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index ffe698d84..ca9e4c8e0 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "hoangnam2261",
+ "name": "hoangnam2261",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/31692990?v=4",
+ "profile": "https://github.com/hoangnam2261",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "jarpit96",
"name": "Arpit Jain",
diff --git a/README.md b/README.md
index c59bfac02..b10ea2a59 100644
--- a/README.md
+++ b/README.md
@@ -166,6 +166,7 @@ This project is licensed under the terms of the MIT license.
 Mitchell Irvin 💻 |
 Arpit Jain 💻 |
+  hoangnam2261 💻 |
 Kirill Vlasov 💻 |
 Jón Ingi Sveinbjörnsson 💻 |
From d11b2f06ea91219a2952ca0ea578faef13384ab8 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:42:55 +0300
Subject: [PATCH 120/225] docs: add fanofxiaofeng as a contributor (#1414)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index ca9e4c8e0..76018eb5a 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "fanofxiaofeng",
+ "name": "靳阳",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/3983683?v=4",
+ "profile": "https://github.com/fanofxiaofeng",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "hoangnam2261",
"name": "hoangnam2261",
diff --git a/README.md b/README.md
index b10ea2a59..9d2c2fb91 100644
--- a/README.md
+++ b/README.md
@@ -167,6 +167,7 @@ This project is licensed under the terms of the MIT license.
 Mitchell Irvin 💻 |
 Arpit Jain 💻 |
 hoangnam2261 💻 |
+  靳阳 💻 |
 Kirill Vlasov 💻 |
 Jón Ingi Sveinbjörnsson 💻 |
From 1bbae5fd5a63a6c56e4b576ce4b6cd0abbc59855 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:44:29 +0300
Subject: [PATCH 121/225] docs: add dmitraver as a contributor (#1415)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 76018eb5a..c04339058 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "dmitraver",
+ "name": "Dmitry Avershin",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/1798156?v=4",
+ "profile": "https://github.com/dmitraver",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "fanofxiaofeng",
"name": "靳阳",
diff --git a/README.md b/README.md
index 9d2c2fb91..04721d214 100644
--- a/README.md
+++ b/README.md
@@ -171,6 +171,7 @@ This project is licensed under the terms of the MIT license.
 Kirill Vlasov 💻 |
 Jón Ingi Sveinbjörnsson 💻 |
+  Dmitry Avershin 💻 |
From b67a019c48c185e824acf3936b917a0b06764715 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:45:53 +0300
Subject: [PATCH 122/225] docs: add besok as a contributor (#1416)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index c04339058..f30ec4f26 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "besok",
+ "name": "Boris",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/29834592?v=4",
+ "profile": "https://github.com/besok",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "dmitraver",
"name": "Dmitry Avershin",
diff --git a/README.md b/README.md
index 04721d214..4407d4f36 100644
--- a/README.md
+++ b/README.md
@@ -172,6 +172,7 @@ This project is licensed under the terms of the MIT license.
 Kirill Vlasov 💻 |
 Jón Ingi Sveinbjörnsson 💻 |
 Dmitry Avershin 💻 |
+  Boris 💻 |
From b4e4cf9cfe4633ebc35e0f91836ce20bd671e11c Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:48:09 +0300
Subject: [PATCH 123/225] docs: add baislsl as a contributor (#1417)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 3 +++
2 files changed, 12 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index f30ec4f26..39babdca5 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "baislsl",
+ "name": "Shengli Bai",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/17060584?v=4",
+ "profile": "https://github.com/baislsl",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "besok",
"name": "Boris",
diff --git a/README.md b/README.md
index 4407d4f36..cc5d3a99e 100644
--- a/README.md
+++ b/README.md
@@ -164,10 +164,12 @@ This project is licensed under the terms of the MIT license.
 PhoenixYip 💻 |
 Ranjeet 💻 |
+
 Mitchell Irvin 💻 |
 Arpit Jain 💻 |
 hoangnam2261 💻 |
 靳阳 💻 |
+
 Kirill Vlasov 💻 |
 Jón Ingi Sveinbjörnsson 💻 |
@@ -175,6 +177,7 @@ This project is licensed under the terms of the MIT license.
 Boris 💻 |
+  Shengli Bai 💻 |
From 65d627b2ed11a5d8fdbeae32266bf2cf3dbfcdd8 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 18:49:46 +0300
Subject: [PATCH 124/225] docs: add akrystian as a contributor (#1418)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 39babdca5..92b26c57e 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "akrystian",
+ "name": "adamski.pro",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/6537430?v=4",
+ "profile": "http://adamski.pro",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "baislsl",
"name": "Shengli Bai",
diff --git a/README.md b/README.md
index cc5d3a99e..0d91ed28f 100644
--- a/README.md
+++ b/README.md
@@ -178,6 +178,7 @@ This project is licensed under the terms of the MIT license.
 Shengli Bai 💻 |
+  adamski.pro 💻 |
From 47acedaaf7e733d131df78126c3968df40ad4072 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 19:10:44 +0300
Subject: [PATCH 125/225] docs: add Rzeposlaw as a contributor (#1419)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 92b26c57e..8ff68a0b8 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "Rzeposlaw",
+ "name": "Katarzyna Rzepecka",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/18425745?v=4",
+ "profile": "https://github.com/Rzeposlaw",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "akrystian",
"name": "adamski.pro",
diff --git a/README.md b/README.md
index 0d91ed28f..8e02e8749 100644
--- a/README.md
+++ b/README.md
@@ -179,6 +179,7 @@ This project is licensed under the terms of the MIT license.
 Shengli Bai 💻 |
 adamski.pro 💻 |
+  Katarzyna Rzepecka 💻 |
From ae57ec75f3dbe269113e40691d7fbab038735035 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 19:12:46 +0300
Subject: [PATCH 126/225] docs: add LuigiCortese as a contributor (#1420)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 8ff68a0b8..98f1a8eba 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "LuigiCortese",
+ "name": "Luigi Cortese",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/9956006?v=4",
+ "profile": "http://www.devsedge.net/",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "Rzeposlaw",
"name": "Katarzyna Rzepecka",
diff --git a/README.md b/README.md
index 8e02e8749..182219262 100644
--- a/README.md
+++ b/README.md
@@ -180,6 +180,7 @@ This project is licensed under the terms of the MIT license.
 Shengli Bai 💻 |
 adamski.pro 💻 |
 Katarzyna Rzepecka 💻 |
+  Luigi Cortese 💻 |
From efd8c8156e9f6ce3ab5714e971973ec35360d683 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 19:14:26 +0300
Subject: [PATCH 127/225] docs: add Juaanma as a contributor (#1421)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 98f1a8eba..df021acbe 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "Juaanma",
+ "name": "Juan Manuel Suárez",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/7390500?v=4",
+ "profile": "https://github.com/Juaanma",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "LuigiCortese",
"name": "Luigi Cortese",
diff --git a/README.md b/README.md
index 182219262..33df95b87 100644
--- a/README.md
+++ b/README.md
@@ -183,6 +183,7 @@ This project is licensed under the terms of the MIT license.
 Luigi Cortese 💻 |
+  Juan Manuel Suárez 💻 |
From 325f0d93b24d9779109391cb7a5c876eaf048aa1 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 19:16:02 +0300
Subject: [PATCH 128/225] docs: add 7agustibm as a contributor (#1422)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index df021acbe..c7d6637a9 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "7agustibm",
+ "name": "Agustí Becerra Milà",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/8149332?v=4",
+ "profile": "https://github.com/7agustibm",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "Juaanma",
"name": "Juan Manuel Suárez",
diff --git a/README.md b/README.md
index 33df95b87..c9429805b 100644
--- a/README.md
+++ b/README.md
@@ -184,6 +184,7 @@ This project is licensed under the terms of the MIT license.
 Juan Manuel Suárez 💻 |
+  Agustí Becerra Milà 💻 |
From 1841fba8319af0e7a12a0ea04320311702b4b950 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2020 19:17:45 +0300
Subject: [PATCH 129/225] docs: add yosfik as a contributor (#1423)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: update README.md [skip ci]
* docs: update .all-contributorsrc [skip ci]
Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Ilkka Seppälä
---
.all-contributorsrc | 9 +++++++++
README.md | 1 +
2 files changed, 10 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index c7d6637a9..1e49b8d91 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -291,6 +291,15 @@
"code"
]
},
+ {
+ "login": "yosfik",
+ "name": "Yosfik Alqadri",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/4850270?v=4",
+ "profile": "https://github.com/yosfik",
+ "contributions": [
+ "code"
+ ]
+ },
{
"login": "7agustibm",
"name": "Agustí Becerra Milà",
diff --git a/README.md b/README.md
index c9429805b..74c9220bc 100644
--- a/README.md
+++ b/README.md
@@ -185,6 +185,7 @@ This project is licensed under the terms of the MIT license.

|