diff --git a/README.md b/README.md index 52948b49..1cb05517 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ [![codebeat badge](https://codebeat.co/badges/8e8c5e70-cb07-4f58-941c-3ddb64f3c059)](https://codebeat.co/projects/github-com-tamada-pochi-main) [![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://github.com/tamada/pochi/blob/master/LICENSE) -[![Version](https://img.shields.io/badge/Version-2.5.2-green.svg)](https://github.com/tamada/pochi/releases/tag/v2.5.2) +[![Version](https://img.shields.io/badge/Version-2.6.0-green.svg)](https://github.com/tamada/pochi/releases/tag/v2.6.0) [![DOI](https://img.shields.io/badge/DOI-10.5281/zenodo.4271132-green.svg)](https://zenodo.org/badge/latestdoi/82773287) -[![Javadoc](https://img.shields.io/badge/Javadoc-v2.5.2-blue?logo=java)](https://tamada.github.io/pochi/apidocs) -[![Docker](https://img.shields.io/badge/Docker-ghcr.io%2Ftamada%2Fpochi%3A2.5.2-blue?logo=docker)](https://github.com/users/tamada/packages/container/package/pochi) +[![Javadoc](https://img.shields.io/badge/Javadoc-v2.6.0-blue?logo=java)](https://tamada.github.io/pochi/apidocs) +[![Docker](https://img.shields.io/badge/Docker-ghcr.io%2Ftamada%2Fpochi%3A2.6.0-blue?logo=docker)](https://github.com/users/tamada/packages/container/package/pochi) [![GitHub Discussion](https://img.shields.io/badge/GitHub-Discussions-blue?logo=github)](https://github.com/tamada/pochi/discussions) Detecting the software theft, the birthmark toolkit for the JVM platform. @@ -83,7 +83,8 @@ For more detail, see [:ant: Examples](https://tamada.github.io/pochi/examples). Container images of **pochi** for Docker are: * [`ghcr.io/tamada/pochi`](https://github.com/users/tamada/packages/container/package/pochi) - * `2.5.2`, `latest` + * `2.6.0`, `latest` + * `2.5.2` * `2.5.1` * `2.5.0` * `2.4.6` @@ -106,7 +107,7 @@ Container images of **pochi** for Docker are: * `1.0.0` * accept only `.js` script files. -[![Docker](https://img.shields.io/badge/Docker-ghcir.io%2Ftamada%2Fpochi%3A2.5.2-blue?logo=docker)](https://github.com/users/tamada/packages/container/package/pochi) +[![Docker](https://img.shields.io/badge/Docker-ghcir.io%2Ftamada%2Fpochi%3A2.6.0-blue?logo=docker)](https://github.com/users/tamada/packages/container/package/pochi) To run **pochi** on Docker container OS, type the following commands. @@ -158,10 +159,10 @@ Then, add the dependencies of your `pom.xml`. | groupId | artifactId | version | |--------------------|--------------|---------| -|`jp.cafebabe.pochi` | `kunai2` | `2.5.2` | -|`jp.cafebabe.pochi` | `pochi-core` | `2.5.2` | -|`jp.cafebabe.pochi` | `pochi-api` | `2.5.2` | -|`jp.cafebabe.pochi` | `pochi-cmd` | `2.5.2` | +|`jp.cafebabe.pochi` | `kunai2` | `2.6.0` | +|`jp.cafebabe.pochi` | `pochi-core` | `2.6.0` | +|`jp.cafebabe.pochi` | `pochi-api` | `2.6.0` | +|`jp.cafebabe.pochi` | `pochi-cmd` | `2.6.0` | ## Modules diff --git a/bin/build_site.sh b/bin/build_site.sh index da1f9aa4..88e0949c 100755 --- a/bin/build_site.sh +++ b/bin/build_site.sh @@ -1,6 +1,6 @@ #! /bin/sh -VERSION="2.5.2" +VERSION="2.6.0" function build_apidocs() { mkdir -p site/msp diff --git a/bin/make_dist.sh b/bin/make_dist.sh index 26a72da6..cbcedc3a 100755 --- a/bin/make_dist.sh +++ b/bin/make_dist.sh @@ -1,6 +1,6 @@ #! /bin/sh -VERSION="2.5.2" +VERSION="2.6.0" function mkdirIfNeeded () { if [ ! -d $1 ] ; then diff --git a/dockers/pochi-groovysh/Dockerfile b/dockers/pochi-groovysh/Dockerfile index 6417627d..0e3aa891 100644 --- a/dockers/pochi-groovysh/Dockerfile +++ b/dockers/pochi-groovysh/Dockerfile @@ -15,7 +15,7 @@ RUN apk --no-cache add openjdk11=11.0.4_p4-r1 \ # building pochi FROM alpine:3.10.1 -ARG PochiVersion="2.5.2" +ARG PochiVersion="2.6.0" ARG GroovyVersion="3.0.9" LABEL maintainer="Haruaki Tamada" \ diff --git a/dockers/pochi/Dockerfile b/dockers/pochi/Dockerfile index 1c83c791..0b8d0374 100644 --- a/dockers/pochi/Dockerfile +++ b/dockers/pochi/Dockerfile @@ -15,7 +15,7 @@ RUN apk --no-cache add openjdk11=11.0.4_p4-r1 \ # building pochi FROM alpine:3.10.1 -ARG PochiVersion="2.5.2" +ARG PochiVersion="2.6.0" LABEL maintainer="Haruaki Tamada" \ pochi-version="${PochiVersion}" \ diff --git a/kunai2/README.md b/kunai2/README.md index d1c660e1..7c4a94e2 100644 --- a/kunai2/README.md +++ b/kunai2/README.md @@ -9,11 +9,11 @@ Kunai2 implemented for Java 8 and used streaming API. ```java // Reading Path sourcePath = Paths.get("path/of/source/file/or/directory"); -DataSourceFactory sourceFactory = new DefaultDataSourceFactory(); +DataSourceFactory sourceFactory = DataSourceFactory.instance(); try(DataSource source = sourceFactory.build(sourcePath)){ // Storing Path outputPath = Paths.get("path/of/output/file.jar"); - DataSinkFactory sinkFactory = new DefaultDataSinkFactory(); + DataSinkFactory sinkFactory = DataSinkFactory.instance(); try(DataSink sink = sinkFactory.build(outputPath)){ sink.consume(source); // above lines means following code. diff --git a/kunai2/pom.xml b/kunai2/pom.xml index f52e00d4..b50f72e6 100644 --- a/kunai2/pom.xml +++ b/kunai2/pom.xml @@ -4,7 +4,7 @@ jp.cafebabe pochi - 2.5.2 + 2.6.0 4.0.0 @@ -19,7 +19,7 @@ org.ow2.asm asm - 8.0.1 + 9.2 diff --git a/kunai2/src/main/java/jp/cafebabe/kunai/Demo.java b/kunai2/src/main/java/jp/cafebabe/kunai/Demo.java index 9727b49b..a8db7a5c 100644 --- a/kunai2/src/main/java/jp/cafebabe/kunai/Demo.java +++ b/kunai2/src/main/java/jp/cafebabe/kunai/Demo.java @@ -3,9 +3,9 @@ import java.nio.file.Paths; import jp.cafebabe.kunai.sink.DataSink; -import jp.cafebabe.kunai.sink.factories.DefaultDataSinkFactory; +import jp.cafebabe.kunai.sink.factories.DataSinkFactory; import jp.cafebabe.kunai.source.DataSource; -import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory; +import jp.cafebabe.kunai.source.factories.DataSourceFactory; public class Demo { public Demo(String[] args) throws Exception{ @@ -13,8 +13,8 @@ public Demo(String[] args) throws Exception{ } private void copy(String from, String to) throws Exception{ - try(DataSource source = new DefaultDataSourceFactory().build(Paths.get(from)); - DataSink sink = new DefaultDataSinkFactory().create(Paths.get(to))){ + try(DataSource source = DataSourceFactory.instance().build(Paths.get(from)); + DataSink sink = DataSinkFactory.instance().create(Paths.get(to))) { copy(source, sink); } } diff --git a/kunai2/src/main/java/jp/cafebabe/kunai/entries/KunaiException.java b/kunai2/src/main/java/jp/cafebabe/kunai/entries/KunaiException.java index c65eb9d7..c91a0000 100644 --- a/kunai2/src/main/java/jp/cafebabe/kunai/entries/KunaiException.java +++ b/kunai2/src/main/java/jp/cafebabe/kunai/entries/KunaiException.java @@ -7,4 +7,7 @@ public KunaiException(String message) { super(message); } + public KunaiException(Exception e) { + super(e); + } } diff --git a/kunai2/src/main/java/jp/cafebabe/kunai/sink/factories/DataSinkFactory.java b/kunai2/src/main/java/jp/cafebabe/kunai/sink/factories/DataSinkFactory.java index 122d3f45..3a106665 100644 --- a/kunai2/src/main/java/jp/cafebabe/kunai/sink/factories/DataSinkFactory.java +++ b/kunai2/src/main/java/jp/cafebabe/kunai/sink/factories/DataSinkFactory.java @@ -8,4 +8,8 @@ public interface DataSinkFactory { DataSink create(Path path); boolean isTarget(Path path); + + static DataSinkFactory instance() { + return new DefaultDataSinkFactory(); + } } diff --git a/kunai2/src/main/java/jp/cafebabe/kunai/sink/factories/DefaultDataSinkFactory.java b/kunai2/src/main/java/jp/cafebabe/kunai/sink/factories/DefaultDataSinkFactory.java index 1607f111..c08da6ef 100644 --- a/kunai2/src/main/java/jp/cafebabe/kunai/sink/factories/DefaultDataSinkFactory.java +++ b/kunai2/src/main/java/jp/cafebabe/kunai/sink/factories/DefaultDataSinkFactory.java @@ -11,7 +11,7 @@ import jp.cafebabe.kunai.sink.JarFileDataSink; import jp.cafebabe.kunai.sink.WarFileDataSink; -public class DefaultDataSinkFactory implements DataSinkFactory{ +class DefaultDataSinkFactory implements DataSinkFactory{ private List factories = new ArrayList<>(); public DefaultDataSinkFactory(){ diff --git a/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/DataSourceFactory.java b/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/DataSourceFactory.java index cc12f007..eaec0074 100644 --- a/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/DataSourceFactory.java +++ b/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/DataSourceFactory.java @@ -35,4 +35,8 @@ default DataSource build(Path path) throws KunaiException{ default DataSource build(File file) throws KunaiException{ return build(file.toPath()); } + + static DataSourceFactory instance() { + return new DefaultDataSourceFactory(); + } } diff --git a/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/DefaultDataSourceFactory.java b/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/DefaultDataSourceFactory.java index 12866eb8..93896dee 100644 --- a/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/DefaultDataSourceFactory.java +++ b/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/DefaultDataSourceFactory.java @@ -9,7 +9,7 @@ import jp.cafebabe.kunai.entries.KunaiException; import jp.cafebabe.kunai.source.DataSource; -public class DefaultDataSourceFactory implements DataSourceFactory{ +class DefaultDataSourceFactory implements DataSourceFactory{ private DataSourceFactories factories = new DataSourceFactories(); @Override diff --git a/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/package-info.java b/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/package-info.java index 44c6646b..e468025c 100644 --- a/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/package-info.java +++ b/kunai2/src/main/java/jp/cafebabe/kunai/source/factories/package-info.java @@ -4,7 +4,7 @@ * Typical usage is: *
  * Path path = Paths.get("some/data/source/path");
- * DataSourceFactory factory = DefaultDataSourceFactory();
+ * DataSourceFactory factory = DataSourceFactory.instance();
  * try(DataSource source = factory.build(path)){
  *     source.stream()
  *         .forEach(entry ->
diff --git a/kunai2/src/main/java/module-info.java b/kunai2/src/main/java/module-info.java
index 0d2d226b..e350ca19 100644
--- a/kunai2/src/main/java/module-info.java
+++ b/kunai2/src/main/java/module-info.java
@@ -1,7 +1,7 @@
 import jp.cafebabe.kunai.sink.DataSink;
-import jp.cafebabe.kunai.sink.factories.DefaultDataSinkFactory;
+import jp.cafebabe.kunai.sink.factories.DataSinkFactory;
 import jp.cafebabe.kunai.source.DataSource;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
 
 /**
  * 

@@ -15,8 +15,8 @@ * *

  * public void copy(String from, String to) throws Exception {
- *     try({@link DataSource} source = new {@link DefaultDataSourceFactory}().build(Paths.get(from));
- *             {@link DataSink} sink = new {@link DefaultDataSinkFactory}().create(Paths.get(to))){
+ *     try({@link DataSource} source = {@link DataSourceFactory}.instance().build(Paths.get(from));
+ *             {@link DataSink} sink = {@link DataSinkFactory}.instance().create(Paths.get(to))){
  *         copy(source, sink);
  *     }
  * }
@@ -33,6 +33,7 @@
 
     exports jp.cafebabe.kunai.entries;
     exports jp.cafebabe.kunai.sink;
+    exports jp.cafebabe.kunai.sink.factories;
     exports jp.cafebabe.kunai.source;
     exports jp.cafebabe.kunai.source.factories;
 }
diff --git a/kunai2/src/test/java/jp/cafebabe/kunai/entries/NameTest.java b/kunai2/src/test/java/jp/cafebabe/kunai/entries/NameTest.java
index ab68f0d8..6be1cc26 100644
--- a/kunai2/src/test/java/jp/cafebabe/kunai/entries/NameTest.java
+++ b/kunai2/src/test/java/jp/cafebabe/kunai/entries/NameTest.java
@@ -26,4 +26,21 @@ public void testBasic(){
         assertThat(name.toString(), is("Haruaki Tamada"));
         assertThat(name.name(), is("Haruaki Tamada"));
     }
+
+    @Test
+    public void testMatch() {
+        assertThat(name.matches("H.*Tamada"), is(true));
+        assertThat(name.matches("tamada"), is(false));
+        assertThat(name.contains("ki Ta"), is(true));
+        assertThat(name.endsWith("a"), is(true));
+        assertThat(name.startsWith("H"), is(true));
+    }
+
+    @Test
+    public void testEquals() {
+        assertThat(name.equals(new Name("Haruaki Tamada")), is(true));
+        assertThat(name.equals(new Name("Different Name")), is(false));
+        assertThat(name.equals(new Object()), is(false));
+        assertThat(name.equals(null), is(false));
+    }
 }
diff --git a/kunai2/src/test/java/jp/cafebabe/kunai/sink/DirectoryDataSinkTest.java b/kunai2/src/test/java/jp/cafebabe/kunai/sink/DirectoryDataSinkTest.java
index 720f5b1b..fdfccbaf 100644
--- a/kunai2/src/test/java/jp/cafebabe/kunai/sink/DirectoryDataSinkTest.java
+++ b/kunai2/src/test/java/jp/cafebabe/kunai/sink/DirectoryDataSinkTest.java
@@ -1,27 +1,26 @@
 package jp.cafebabe.kunai.sink;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import jp.cafebabe.kunai.entries.Entry;
+import jp.cafebabe.kunai.source.DataSource;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
+import jp.cafebabe.kunai.util.PathHelper;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import jp.cafebabe.kunai.entries.Entry;
-import jp.cafebabe.kunai.source.DataSource;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
-import jp.cafebabe.kunai.util.PathHelper;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 public class DirectoryDataSinkTest {
     @Before
     public void setUp() throws Exception{
         Path path = Paths.get("target/test-classes/hello/target/hello-1.0-SNAPSHOT.jar");
-        try(DataSource source = new DefaultDataSourceFactory().build(path)){
+        try(DataSource source = DataSourceFactory.instance().build(path)){
             try(DataSink sink = new DirectoryDataSink(Paths.get("dir"))){
                 sink.consume(source);
             }
@@ -30,7 +29,7 @@ public void setUp() throws Exception{
 
     @Test
     public void testCreatedDirectory() throws Exception{
-        DataSource source = new DefaultDataSourceFactory().build(Paths.get("dir"));
+        DataSource source = DataSourceFactory.instance().build(Paths.get("dir"));
 
         List list = new ArrayList<>();
         source.forEach(entry -> list.add(entry));
diff --git a/kunai2/src/test/java/jp/cafebabe/kunai/sink/JarFileDataSinkTest.java b/kunai2/src/test/java/jp/cafebabe/kunai/sink/JarFileDataSinkTest.java
index 52e5a9eb..41d3704d 100644
--- a/kunai2/src/test/java/jp/cafebabe/kunai/sink/JarFileDataSinkTest.java
+++ b/kunai2/src/test/java/jp/cafebabe/kunai/sink/JarFileDataSinkTest.java
@@ -1,7 +1,10 @@
 package jp.cafebabe.kunai.sink;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import jp.cafebabe.kunai.entries.Entry;
+import jp.cafebabe.kunai.source.DataSource;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
+import org.junit.After;
+import org.junit.Test;
 
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -9,24 +12,20 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.junit.After;
-import org.junit.Test;
-
-import jp.cafebabe.kunai.entries.Entry;
-import jp.cafebabe.kunai.source.DataSource;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 public class JarFileDataSinkTest {
     @Test
     public void testCreatedJarFile() throws Exception{
         Path path = Paths.get("target/test-classes/hello/target/classes/");
-        try(DataSource source = new DefaultDataSourceFactory().build(path)){
+        try(DataSource source = DataSourceFactory.instance().build(path)){
             try(DataSink sink = new JarFileDataSink(Paths.get("hoge.jar"))){
                 sink.consume(source);
             }
         }
 
-        DataSource source = new DefaultDataSourceFactory().build(Paths.get("hoge.jar"));
+        DataSource source = DataSourceFactory.instance().build(Paths.get("hoge.jar"));
 
         List list = new ArrayList<>();
         source.forEach(entry -> list.add(entry));
@@ -37,13 +36,13 @@ public void testCreatedJarFile() throws Exception{
     @Test
     public void testJarFromJar() throws Exception{
         Path path = Paths.get("target/test-classes/hello/target/hello-1.0-SNAPSHOT.jar");
-        try(DataSource source = new DefaultDataSourceFactory().build(path)){
+        try(DataSource source = DataSourceFactory.instance().build(path)){
             try(DataSink sink = new JarFileDataSink(Paths.get("hoge.jar"))){
                 sink.consume(source);
             }
         }
 
-        DataSource source = new DefaultDataSourceFactory().build(Paths.get("hoge.jar"));
+        DataSource source = DataSourceFactory.instance().build(Paths.get("hoge.jar"));
 
         List list = new ArrayList<>();
         source.forEach(entry -> list.add(entry));
diff --git a/kunai2/src/test/java/jp/cafebabe/kunai/source/AbstractDataSourceTest.java b/kunai2/src/test/java/jp/cafebabe/kunai/source/AbstractDataSourceTest.java
index 9e5084ce..8492e390 100644
--- a/kunai2/src/test/java/jp/cafebabe/kunai/source/AbstractDataSourceTest.java
+++ b/kunai2/src/test/java/jp/cafebabe/kunai/source/AbstractDataSourceTest.java
@@ -1,11 +1,11 @@
 package jp.cafebabe.kunai.source;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import org.junit.Test;
 
 import java.nio.file.Paths;
 
-import org.junit.Test;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 public class AbstractDataSourceTest{
     @Test
diff --git a/kunai2/src/test/java/jp/cafebabe/kunai/source/ClassFileDataSourceTest.java b/kunai2/src/test/java/jp/cafebabe/kunai/source/ClassFileDataSourceTest.java
index 9ae02403..f5f2c246 100644
--- a/kunai2/src/test/java/jp/cafebabe/kunai/source/ClassFileDataSourceTest.java
+++ b/kunai2/src/test/java/jp/cafebabe/kunai/source/ClassFileDataSourceTest.java
@@ -1,18 +1,16 @@
 package jp.cafebabe.kunai.source;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import jp.cafebabe.kunai.entries.ClassName;
+import jp.cafebabe.kunai.entries.Entry;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
-import org.junit.Before;
-import org.junit.Test;
-
-import jp.cafebabe.kunai.entries.ClassName;
-import jp.cafebabe.kunai.entries.Entry;
-import jp.cafebabe.kunai.source.factories.DataSourceFactory;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 
 public class ClassFileDataSourceTest {
     private Path path;
@@ -24,7 +22,7 @@ public void setUp(){
 
     @Test
     public void testDataSource() throws Exception{
-        DataSourceFactory factory = new DefaultDataSourceFactory();
+        DataSourceFactory factory = DataSourceFactory.instance();
 
         assertThat(factory.isTarget(path), is(true));
 
diff --git a/kunai2/src/test/java/jp/cafebabe/kunai/source/DirectoryDataSourceTest.java b/kunai2/src/test/java/jp/cafebabe/kunai/source/DirectoryDataSourceTest.java
index 5395a803..0c9a4aa4 100644
--- a/kunai2/src/test/java/jp/cafebabe/kunai/source/DirectoryDataSourceTest.java
+++ b/kunai2/src/test/java/jp/cafebabe/kunai/source/DirectoryDataSourceTest.java
@@ -1,18 +1,16 @@
 package jp.cafebabe.kunai.source;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import jp.cafebabe.kunai.entries.ClassName;
+import jp.cafebabe.kunai.entries.Entry;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
-import org.junit.Before;
-import org.junit.Test;
-
-import jp.cafebabe.kunai.entries.ClassName;
-import jp.cafebabe.kunai.entries.Entry;
-import jp.cafebabe.kunai.source.factories.DataSourceFactory;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 
 public class DirectoryDataSourceTest {
     private Path path;
@@ -24,7 +22,7 @@ public void setUp(){
 
     @Test
     public void testDataSource() throws Exception{
-        DataSourceFactory factory = new DefaultDataSourceFactory();
+        DataSourceFactory factory = DataSourceFactory.instance();
 
         assertThat(factory.isTarget(path), is(true));
 
diff --git a/kunai2/src/test/java/jp/cafebabe/kunai/source/FilteredDataSourceTest.java b/kunai2/src/test/java/jp/cafebabe/kunai/source/FilteredDataSourceTest.java
index 99af23c6..90eb87b3 100644
--- a/kunai2/src/test/java/jp/cafebabe/kunai/source/FilteredDataSourceTest.java
+++ b/kunai2/src/test/java/jp/cafebabe/kunai/source/FilteredDataSourceTest.java
@@ -1,18 +1,16 @@
 package jp.cafebabe.kunai.source;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import jp.cafebabe.kunai.entries.ClassName;
+import jp.cafebabe.kunai.entries.Entry;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
-import org.junit.Before;
-import org.junit.Test;
-
-import jp.cafebabe.kunai.entries.ClassName;
-import jp.cafebabe.kunai.entries.Entry;
-import jp.cafebabe.kunai.source.factories.DataSourceFactory;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 
 public class FilteredDataSourceTest {
     private Path path;
@@ -24,7 +22,7 @@ public void setUp(){
 
     @Test
     public void testDataSource() throws Exception{
-        DataSourceFactory factory = new DefaultDataSourceFactory();
+        DataSourceFactory factory = DataSourceFactory.instance();
 
         try(DataSource source = factory.build(path).filter(entry -> entry.endsWith("World.class"))){
             Entry[] entries = source.stream()
diff --git a/kunai2/src/test/java/jp/cafebabe/kunai/source/JarFileDataSourceTest.java b/kunai2/src/test/java/jp/cafebabe/kunai/source/JarFileDataSourceTest.java
index bdf6e1dc..cbc4791c 100644
--- a/kunai2/src/test/java/jp/cafebabe/kunai/source/JarFileDataSourceTest.java
+++ b/kunai2/src/test/java/jp/cafebabe/kunai/source/JarFileDataSourceTest.java
@@ -1,18 +1,16 @@
 package jp.cafebabe.kunai.source;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import jp.cafebabe.kunai.entries.ClassName;
+import jp.cafebabe.kunai.entries.Entry;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
-import org.junit.Before;
-import org.junit.Test;
-
-import jp.cafebabe.kunai.entries.ClassName;
-import jp.cafebabe.kunai.entries.Entry;
-import jp.cafebabe.kunai.source.factories.DataSourceFactory;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 
 public class JarFileDataSourceTest {
     private Path path;
@@ -24,7 +22,7 @@ public void setUp(){
 
     @Test
     public void testDataSource() throws Exception{
-        DataSourceFactory factory = new DefaultDataSourceFactory();
+        DataSourceFactory factory = DataSourceFactory.instance();
 
         assertThat(factory.isTarget(path), is(true));
 
diff --git a/kunai2/src/test/java/jp/cafebabe/kunai/source/WarFileDataSourceTest.java b/kunai2/src/test/java/jp/cafebabe/kunai/source/WarFileDataSourceTest.java
index 00b2c57e..e7d40a13 100644
--- a/kunai2/src/test/java/jp/cafebabe/kunai/source/WarFileDataSourceTest.java
+++ b/kunai2/src/test/java/jp/cafebabe/kunai/source/WarFileDataSourceTest.java
@@ -1,18 +1,16 @@
 package jp.cafebabe.kunai.source;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import jp.cafebabe.kunai.entries.ClassName;
+import jp.cafebabe.kunai.entries.Entry;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
-import org.junit.Before;
-import org.junit.Test;
-
-import jp.cafebabe.kunai.entries.ClassName;
-import jp.cafebabe.kunai.entries.Entry;
-import jp.cafebabe.kunai.source.factories.DataSourceFactory;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 
 public class WarFileDataSourceTest {
     private Path path;
@@ -24,7 +22,7 @@ public void setUp(){
 
     @Test
     public void testDataSource() throws Exception{
-        DataSourceFactory factory = new DefaultDataSourceFactory();
+        DataSourceFactory factory = DataSourceFactory.instance();
 
         assertThat(factory.isTarget(path), is(true));
 
diff --git a/pochi-api/pom.xml b/pochi-api/pom.xml
index 241aec80..8f1c3caf 100644
--- a/pochi-api/pom.xml
+++ b/pochi-api/pom.xml
@@ -6,7 +6,7 @@
   
     jp.cafebabe
     pochi
-    2.5.2
+    2.6.0
   
 
   jp.cafebabe.pochi
@@ -33,7 +33,7 @@
     
       jp.cafebabe.pochi
       kunai2
-      2.5.2
+      2.6.0
       compile
     
   
diff --git a/pochi-api/src/main/java/jp/cafebabe/birthmarks/BirthmarkParser.java b/pochi-api/src/main/java/jp/cafebabe/birthmarks/BirthmarkParser.java
index 49ba36e5..69ac4986 100644
--- a/pochi-api/src/main/java/jp/cafebabe/birthmarks/BirthmarkParser.java
+++ b/pochi-api/src/main/java/jp/cafebabe/birthmarks/BirthmarkParser.java
@@ -25,7 +25,7 @@ default List> parseForStream(DataSource source) {
     default Birthmarks parse(DataSource source){
         List> stream = parseForStream(source);
         // do termination operation before calling ```type()``` 
-        return new Birthmarks<>(stream.stream());
+        return Birthmarks.of(stream.stream());
     }
 
     List> parseEntry(Entry entry);
diff --git a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Birthmarks.java b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Birthmarks.java
index 84408a89..57abbd2c 100644
--- a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Birthmarks.java
+++ b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Birthmarks.java
@@ -1,23 +1,33 @@
 package jp.cafebabe.birthmarks.entities;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import io.vavr.control.Either;
 import jp.cafebabe.birthmarks.pairs.Streamable;
 import jp.cafebabe.kunai.entries.ClassName;
 
 public class Birthmarks implements Acceptor, Iterable>, Streamable>, Serializable {
     private List> list;
+    private List exceptions;
 
     public Birthmarks(){
         this(Stream.empty());
     }
 
-    public Birthmarks(Stream> stream) {
-        this.list = stream.collect(Collectors.toList());
+    public Birthmarks(Stream>> stream) {
+        list = new ArrayList<>();
+        exceptions = new ArrayList<>();
+        stream.forEach(either -> either.bimap(t -> exceptions.add(t), r -> list.add(r)));
+    }
+
+    public Optional> unify() {
+        return BirthmarksMerger.unifyTo(this);
     }
 
     public Stream> find(ClassName name) {
@@ -29,6 +39,10 @@ public Stream> stream() {
         return list.stream();
     }
 
+    public Stream exceptionStream() {
+        return exceptions.stream();
+    }
+
     public long count() {
         return list.size();
     }
@@ -39,13 +53,22 @@ public Iterator> iterator() {
     }
 
     public Birthmarks merge(Stream> stream) {
-        return new Birthmarks<>(Stream.concat(stream(), stream));
+        return new Birthmarks<>(Stream.concat(stream(), stream)
+                .map(item -> Either.right(item)));
     }
 
     public Birthmarks merge(Birthmarks other) {
         return merge(other.stream());
     }
 
+    public static  Birthmarks of(Stream> stream) {
+        return ofEither(stream.map(item -> Either.right(item)));
+    }
+
+    public static  Birthmarks ofEither(Stream>> stream) {
+        return new Birthmarks<>(stream);
+    }
+
     @Override
     public void accept(Visitor visitor) {
         list.stream()
diff --git a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/BirthmarksMerger.java b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/BirthmarksMerger.java
new file mode 100644
index 00000000..6b9fa989
--- /dev/null
+++ b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/BirthmarksMerger.java
@@ -0,0 +1,60 @@
+package jp.cafebabe.birthmarks.entities;
+
+import io.vavr.control.Try;
+import jp.cafebabe.birthmarks.utils.LongestCommonSubstring;
+import jp.cafebabe.kunai.entries.ClassName;
+
+import java.net.URI;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+class BirthmarksMerger {
+    public  Optional> unify(Birthmarks birthmarks) {
+        Optional> elements = mergeElements(birthmarks);
+        Metadata metadata = mergeMetadata(birthmarks);
+        return elements.map(e -> new Birthmark<>(metadata, e));
+    }
+
+    private  Metadata mergeMetadata(Birthmarks birthmarks) {
+        String location = findCommonLocation(birthmarks.stream());
+        return constructMetadata(location, findType(birthmarks));
+    }
+
+    private  Optional findType(Birthmarks birthmarks) {
+        return birthmarks.stream().map(b -> b.type())
+                .collect(Collectors.reducing((a, b) -> a));
+    }
+
+    private Metadata constructMetadata(String location, Optional type) {
+        Try tryUri = Try.of(() -> new URI(location));
+        Optional uri = tryUri.toJavaOptional();
+        Optional name = uri.map(u -> new ClassName(findBaseName(u)));
+        return new Metadata(name.orElseGet(() -> new ClassName("")), uri.get(), type.get());
+    }
+
+    private String findBaseName(URI uri) {
+        String path = uri.toString();
+        int index = path.lastIndexOf('/');
+        if(index >= 0)
+            return path.substring(index + 1);
+        return path;
+    }
+
+    private  String findCommonLocation(Stream> stream) {
+        Optional location = stream.map(birthmark -> birthmark.metadata())
+                .map(m -> m.location().toString())
+                .collect(Collectors.reducing((s1, s2) -> LongestCommonSubstring.of(s1, s2)));
+        return location.orElseGet(() -> "");
+    }
+
+    private  Optional> mergeElements(Birthmarks birthmarks) {
+        return birthmarks.stream()
+                .map(birthmark -> birthmark.elements())
+                .collect(Collectors.reducing((a, b) -> a.merge(b)));
+    }
+
+    public static  Optional> unifyTo(Birthmarks birthmarks) {
+        return new BirthmarksMerger().unify(birthmarks);
+    }
+}
diff --git a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Couple.java b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Couple.java
index 278cd52a..45042590 100644
--- a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Couple.java
+++ b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Couple.java
@@ -16,6 +16,11 @@ protected Couple(L left, R right) {
         this.right = Objects.requireNonNull(right);
     }
 
+    public void applyIf(BiPredicate predicate, BiConsumer consumer) {
+        if(predicate.test(left, right))
+            consumer.accept(left, right);
+    }
+
     public L left() {
         return left;
     }
diff --git a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Frequency.java b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Frequency.java
index c40ef48a..d04c71c3 100644
--- a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Frequency.java
+++ b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/Frequency.java
@@ -11,7 +11,7 @@ public static Frequency of(String item, Integer frequency) {
 
     @Override
     public String toString() {
-        return String.format("%s=%d", left(), right());
+        return String.format("<%s,%d>", left(), right());
     }
 
     @Override
diff --git a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/elements/FrequencyElements.java b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/elements/FrequencyElements.java
index 192787de..96d86915 100644
--- a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/elements/FrequencyElements.java
+++ b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/elements/FrequencyElements.java
@@ -106,4 +106,11 @@ public static FrequencyElements of(String... elements) {
     public static FrequencyElements of(Stream stream) {
         return new FrequencyElements(stream);
     }
+
+    @Override
+    public String toString() {
+        return frequencies.entrySet()
+                .stream().map(entry -> String.format("<%s,%d>", entry.getKey(), entry.getValue()))
+                .collect(Collectors.joining(","));
+    }
 }
diff --git a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/elements/ListElements.java b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/elements/ListElements.java
index ed48e1f9..c9e6d15a 100644
--- a/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/elements/ListElements.java
+++ b/pochi-api/src/main/java/jp/cafebabe/birthmarks/entities/elements/ListElements.java
@@ -78,4 +78,9 @@ public static ListElements asSetOf(String... elements) {
         return new ListElements(Arrays.stream(elements)
                 .distinct());
     }
+
+    @Override
+    public String toString() {
+        return list.stream().collect(Collectors.joining(","));
+    }
 }
diff --git a/pochi-api/src/main/java/jp/cafebabe/birthmarks/extractors/Extractor.java b/pochi-api/src/main/java/jp/cafebabe/birthmarks/extractors/Extractor.java
index 20f959eb..532f85ad 100644
--- a/pochi-api/src/main/java/jp/cafebabe/birthmarks/extractors/Extractor.java
+++ b/pochi-api/src/main/java/jp/cafebabe/birthmarks/extractors/Extractor.java
@@ -42,7 +42,7 @@ default  Stream>> extractStream(DataSource sou
      * @return extracted birthmarks
      */
     default  Birthmarks extract(DataSource source){
-        return new Birthmarks(stripEither(extractStream(source)));
+        return new Birthmarks(extractStream(source));
     }
 
     /**
diff --git a/pochi-api/src/main/java/jp/cafebabe/birthmarks/utils/LongestCommonSubstring.java b/pochi-api/src/main/java/jp/cafebabe/birthmarks/utils/LongestCommonSubstring.java
new file mode 100644
index 00000000..2df7b427
--- /dev/null
+++ b/pochi-api/src/main/java/jp/cafebabe/birthmarks/utils/LongestCommonSubstring.java
@@ -0,0 +1,44 @@
+package jp.cafebabe.birthmarks.utils;
+
+public class LongestCommonSubstring {
+    public static final String of(String s1, String s2) {
+        return new LongestCommonSubstring()
+                .calculate(s1, s2);
+    }
+
+    private String calculate(String s1, String s2) {
+        int[][] table = new int[s1.length() + 1][s2.length() + 1];
+        Result r = Result.of(0, 0, 0);
+        for(int i = 0; i < table.length; i++) {
+            for(int j = 0; j < table[i].length; j++) {
+                if(i == 0 || j == 0) table[i][j] = 0;
+                else if(s1.charAt(i - 1) == s2.charAt(j - 1)) {
+                    table[i][j] = 1 + table[i - 1][j - 1];
+                    r = updateResultIfNeeded(r, i, j, table[i][j]);
+                }
+                // printTable(table);
+            }
+        }
+        return s1.substring(r.i - r.max, r.i);
+    }
+
+    private Result updateResultIfNeeded(Result r, int i, int j, int v) {
+        if(r.max > v)
+            return r;
+        return Result.of(i, j, v);
+    }
+
+    private static final class Result {
+        private int i;
+        private int j;
+        private int max;
+        private Result(int i, int j, int max) {
+            this.i = i;
+            this.j = j;
+            this.max = max;
+        }
+        public static Result of(int i, int j, int max) {
+            return new Result(i, j, max);
+        }
+    }
+}
diff --git a/pochi-api/src/main/java/module-info.java b/pochi-api/src/main/java/module-info.java
index 30cf358c..8e046bf6 100644
--- a/pochi-api/src/main/java/module-info.java
+++ b/pochi-api/src/main/java/module-info.java
@@ -60,8 +60,9 @@
    exports jp.cafebabe.birthmarks.entities.elements;
    exports jp.cafebabe.birthmarks.extractors;
    exports jp.cafebabe.birthmarks.pairs;
+    exports jp.cafebabe.birthmarks.utils;
 
-   uses jp.cafebabe.birthmarks.comparators.ComparatorBuilder;
+    uses jp.cafebabe.birthmarks.comparators.ComparatorBuilder;
    uses jp.cafebabe.birthmarks.extractors.ExtractorBuilder;
    uses jp.cafebabe.birthmarks.pairs.PairMatcherBuilder;
 }
diff --git a/pochi-api/src/test/java/jp/cafebabe/birthmarks/entities/BirthmarksTest.java b/pochi-api/src/test/java/jp/cafebabe/birthmarks/entities/BirthmarksTest.java
index 12a704bf..cda35b8e 100644
--- a/pochi-api/src/test/java/jp/cafebabe/birthmarks/entities/BirthmarksTest.java
+++ b/pochi-api/src/test/java/jp/cafebabe/birthmarks/entities/BirthmarksTest.java
@@ -7,6 +7,7 @@
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
@@ -26,7 +27,7 @@ public void setUp() throws Exception{
                 Elements.listElements(IntStream.range(1, 4).mapToObj(label -> "e" + label))));
         list.add(new Birthmark(new Metadata(new ClassName("c3"), new URI("source3"), BirthmarkType.of("hoge1")),
                 Elements.listElements(IntStream.range(1, 6).mapToObj(label -> "e" + label))));
-        this.birthmarks = new Birthmarks<>(list.stream());
+        this.birthmarks = Birthmarks.of(list.stream());
     }
 
     @Test
@@ -59,7 +60,7 @@ public void testAppend() throws Exception{
         Birthmark b1 = new Birthmark<>(new Metadata(new ClassName("o1"), new URI("otherSource"), BirthmarkType.of("hoge1")),
                 Elements.listElements(IntStream.range(1, 7).mapToObj(label -> "e" + label)));
 
-        Birthmarks other = birthmarks.merge(new Birthmarks<>(Stream.of(b1)));
+        Birthmarks other = birthmarks.merge(Birthmarks.of(Stream.of(b1)));
 
         List> list = other.stream().collect(Collectors.toList());
         assertThat(list.size(), is(4));
@@ -68,4 +69,16 @@ public void testAppend() throws Exception{
         assertThat(list.get(2).metadata().toString(), is("c3,source3,hoge1"));
         assertThat(list.get(3).metadata().toString(), is("o1,otherSource,hoge1"));
     }
+
+    @Test
+    public void testUnify() throws Exception {
+        Optional> optionalResult = birthmarks.unify();
+        if(optionalResult.isEmpty())
+            throw new InternalError();
+        Birthmark result = optionalResult.get();
+        Elements elements = result.elements();
+
+        assertThat(result.className(), is(new ClassName("source")));
+        assertThat(elements.size(), is(9));
+    }
 }
diff --git a/pochi-api/src/test/java/jp/cafebabe/birthmarks/utils/LongestCommonSubstringTest.java b/pochi-api/src/test/java/jp/cafebabe/birthmarks/utils/LongestCommonSubstringTest.java
new file mode 100644
index 00000000..ad68372e
--- /dev/null
+++ b/pochi-api/src/test/java/jp/cafebabe/birthmarks/utils/LongestCommonSubstringTest.java
@@ -0,0 +1,15 @@
+package jp.cafebabe.birthmarks.utils;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import org.junit.Test;
+
+public class LongestCommonSubstringTest {
+    @Test
+    public void basicTest() {
+        assertThat(LongestCommonSubstring.of("abcdxyz", "xyzabcd"), is("abcd"));
+        assertThat(LongestCommonSubstring.of("abracadabra", "open sesame"), is("a"));
+        assertThat(LongestCommonSubstring.of("aaaa", "bbb"), is(""));
+    }
+}
diff --git a/pochi-cmd/pom.xml b/pochi-cmd/pom.xml
index 4222f702..61898fb8 100644
--- a/pochi-cmd/pom.xml
+++ b/pochi-cmd/pom.xml
@@ -6,7 +6,7 @@
   
     jp.cafebabe
     pochi
-    2.5.2
+    2.6.0
   
 
   jp.cafebabe.pochi
@@ -38,7 +38,7 @@
     
       jp.cafebabe.pochi
       pochi-core
-      2.5.2
+      2.6.0
       compile
     
   
diff --git a/pochi-core/pom.xml b/pochi-core/pom.xml
index 59cca0bf..e234fdfb 100644
--- a/pochi-core/pom.xml
+++ b/pochi-core/pom.xml
@@ -4,7 +4,7 @@
   
     jp.cafebabe
     pochi
-    2.5.2
+    2.6.0
   
 
   4.0.0
@@ -20,13 +20,13 @@
     
       jp.cafebabe.pochi
       kunai2
-      2.5.2
+      2.6.0
       compile
     
     
       jp.cafebabe.pochi
       pochi-api
-      2.5.2
+      2.6.0
       compile
     
     
diff --git a/pochi-core/src/main/java/jp/cafebabe/pochi/BirthmarkSystemHelper.java b/pochi-core/src/main/java/jp/cafebabe/pochi/BirthmarkSystemHelper.java
index acca41e2..777f2590 100644
--- a/pochi-core/src/main/java/jp/cafebabe/pochi/BirthmarkSystemHelper.java
+++ b/pochi-core/src/main/java/jp/cafebabe/pochi/BirthmarkSystemHelper.java
@@ -13,11 +13,11 @@
 import jp.cafebabe.birthmarks.pairs.PairMatcher;
 import jp.cafebabe.birthmarks.pairs.PairMatcherBuilder;
 import jp.cafebabe.birthmarks.pairs.PairMatcherType;
-import jp.cafebabe.pochi.pairs.PairMatcherBuilders;
-import jp.cafebabe.pochi.parsers.DefaultParser;
 import jp.cafebabe.kunai.entries.KunaiException;
 import jp.cafebabe.kunai.source.DataSource;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
+import jp.cafebabe.pochi.pairs.PairMatcherBuilders;
+import jp.cafebabe.pochi.parsers.DefaultParser;
 
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -50,7 +50,7 @@ public Configuration config() {
     }
 
     public DataSource source(String path) throws KunaiException {
-        return new DefaultDataSourceFactory()
+        return DataSourceFactory.instance()
                 .build(Paths.get(path));
     }
 
diff --git a/pochi-core/src/main/java/jp/cafebabe/pochi/Pochi.java b/pochi-core/src/main/java/jp/cafebabe/pochi/Pochi.java
index 15d3fa90..fbd327b7 100644
--- a/pochi-core/src/main/java/jp/cafebabe/pochi/Pochi.java
+++ b/pochi-core/src/main/java/jp/cafebabe/pochi/Pochi.java
@@ -8,7 +8,7 @@
 import java.util.Optional;
 
 public class Pochi {
-    public static final String VERSION = "2.5.2";
+    public static final String VERSION = "2.6.0";
     private static final Pochi INSTANCE = new Pochi();
 
     private final Path home;
@@ -22,7 +22,7 @@ public static final Path home() {
     }
 
     private static List targetPaths() {
-        return Arrays.asList(System.getenv("POCHI_HOME"), "/opt/pochi", "/usr/local/opt/pochi", String.format("pochi-%s", Pochi.VERSION), ".");
+        return Arrays.asList(System.getenv("POCHI_HOME"), "/opt/pochi", "/usr/local/opt/pochi", "/opt/homebrew/opt/pochi", String.format("pochi-%s", Pochi.VERSION), ".");
     }
 
     private Path findPochiHome() {
diff --git a/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/kgram/KGramBasedBirthmarkExtractorTest.java b/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/kgram/KGramBasedBirthmarkExtractorTest.java
index 92a54ed7..d0a352fd 100644
--- a/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/kgram/KGramBasedBirthmarkExtractorTest.java
+++ b/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/kgram/KGramBasedBirthmarkExtractorTest.java
@@ -8,7 +8,7 @@
 import jp.cafebabe.birthmarks.extractors.ExtractorBuilder;
 import jp.cafebabe.kunai.entries.ClassName;
 import jp.cafebabe.kunai.source.DataSource;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
 import jp.cafebabe.pochi.extractors.ExtractorBuilders;
 import org.junit.Test;
 import org.objectweb.asm.Opcodes;
@@ -26,7 +26,7 @@ public class KGramBasedBirthmarkExtractorTest {
     public Birthmarks extract(String path, String type) throws Exception{
         URL location = getClass().getResource(path);
         ExtractorBuilder builder = new ExtractorBuilders().builder(BirthmarkType.of(type));
-        DataSource source = new DefaultDataSourceFactory().build(Paths.get(location.toURI()));
+        DataSource source = DataSourceFactory.instance().build(Paths.get(location.toURI()));
         Extractor extractor = builder.build(new ConfigurationBuilder().configuration());
         return extractor.extract(source);
     }
diff --git a/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/uc/FUCBirthmarkExtractorTest.java b/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/uc/FUCBirthmarkExtractorTest.java
index 70a65647..7914682a 100644
--- a/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/uc/FUCBirthmarkExtractorTest.java
+++ b/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/uc/FUCBirthmarkExtractorTest.java
@@ -8,7 +8,7 @@
 import jp.cafebabe.birthmarks.extractors.Extractor;
 import jp.cafebabe.kunai.entries.ClassName;
 import jp.cafebabe.kunai.source.DataSource;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
 import org.junit.Test;
 
 import java.net.URL;
@@ -17,16 +17,16 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
 
 public class FUCBirthmarkExtractorTest {
     public Birthmarks extract(String path) throws Exception{
         URL location = getClass().getResource(path);
         Configuration config = new ConfigurationBuilder().configuration();
         Extractor extractor = new FUCBirthmarkExtractorBuilder().build(config);
-        DataSource source = new DefaultDataSourceFactory().build(Paths.get(location.toURI()));
+        DataSource source = DataSourceFactory.instance().build(Paths.get(location.toURI()));
         return extractor.extract(source);
     }
 
@@ -43,8 +43,8 @@ public void testBasic() throws Exception{
         list.get(0).forEach(item -> elements.add(item.toString()));
 
         assertThat(elements.size(), is(4));
-        assertThat(elements, is(containsInAnyOrder("java.io.PrintStream=2",
-                "java.lang.Object=2", "java.lang.String=2", "java.lang.System=1")));
+        assertThat(elements, is(containsInAnyOrder("",
+                "", "", "")));
     }
 
     @Test
@@ -60,12 +60,12 @@ public void testBasic2() throws Exception{
         list.get(0).forEach(item -> elements.add(item.toString()));
 
         assertThat(elements.size(), is(13));
-        assertThat(elements, is(containsInAnyOrder("java.io.PrintStream=2",
-                "java.lang.Integer=5", "java.lang.Object=5", "java.lang.String=1",
-                "java.lang.System=1", "java.util.Iterator=3", "java.util.List=5",
-                "java.util.function.IntFunction=1", "java.util.function.IntUnaryOperator=1",
-                "java.util.stream.Collector=2", "java.util.stream.Collectors=1",
-                "java.util.stream.IntStream=7", "java.util.stream.Stream=2")));
+        assertThat(elements, is(containsInAnyOrder("",
+                "", "", "",
+                "", "", "",
+                "", "",
+                "", "",
+                "", "")));
     }
 
     @Test
@@ -81,9 +81,9 @@ public void testBasic3() throws Exception{
         list.get(0).forEach(item -> elements.add(item.toString()));
 
         assertThat(elements.size(), is(6));
-        assertThat(elements, is(containsInAnyOrder("java.io.PrintStream=4",
-                "java.lang.Integer=70", "java.lang.Object=2", "java.lang.String=10",
-                "java.lang.System=2", "java.util.Random=4")));
+        assertThat(elements, is(containsInAnyOrder("",
+                "", "", "",
+                "", "")));
     }
 
     @Test
@@ -99,7 +99,7 @@ public void testBasic4() throws Exception{
         list.get(0).forEach(item -> elements.add(item.toString()));
 
         assertThat(elements.size(), is(3));
-        assertThat(elements, is(containsInAnyOrder("java.io.IOException=1",
-                "java.lang.Object=2", "java.net.ServerSocket=7")));
+        assertThat(elements, is(containsInAnyOrder("",
+                "", "")));
     }
 }
diff --git a/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/uc/UCBirthmarkExtractorTest.java b/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/uc/UCBirthmarkExtractorTest.java
index c1c2ea78..4da8080a 100644
--- a/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/uc/UCBirthmarkExtractorTest.java
+++ b/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/uc/UCBirthmarkExtractorTest.java
@@ -7,7 +7,7 @@
 import jp.cafebabe.birthmarks.extractors.Extractor;
 import jp.cafebabe.kunai.entries.ClassName;
 import jp.cafebabe.kunai.source.DataSource;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
 import org.junit.Test;
 
 import java.net.URL;
@@ -24,7 +24,7 @@ public Birthmarks extract(String path) throws Exception{
         URL location = getClass().getResource(path);
         Configuration config = new ConfigurationBuilder().configuration();
         Extractor extractor = new UCBirthmarkExtractorBuilder().build(config);
-        DataSource source = new DefaultDataSourceFactory().build(Paths.get(location.toURI()));
+        DataSource source = DataSourceFactory.instance().build(Paths.get(location.toURI()));
         return extractor.extract(source);
     }
 
diff --git a/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/verbs/VerbsOfMethodsBirthmarkExtractorTest.java b/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/verbs/VerbsOfMethodsBirthmarkExtractorTest.java
index e808eec6..273cdd10 100644
--- a/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/verbs/VerbsOfMethodsBirthmarkExtractorTest.java
+++ b/pochi-core/src/test/java/jp/cafebabe/pochi/birthmarks/verbs/VerbsOfMethodsBirthmarkExtractorTest.java
@@ -7,7 +7,7 @@
 import jp.cafebabe.birthmarks.extractors.Extractor;
 import jp.cafebabe.kunai.entries.ClassName;
 import jp.cafebabe.kunai.source.DataSource;
-import jp.cafebabe.kunai.source.factories.DefaultDataSourceFactory;
+import jp.cafebabe.kunai.source.factories.DataSourceFactory;
 import org.junit.Test;
 
 import java.net.URL;
@@ -24,7 +24,7 @@ public Birthmarks extract(String path) throws Exception{
         URL location = getClass().getResource(path);
         Configuration config = new ConfigurationBuilder().configuration();
         Extractor extractor = new VerbsOfMethodsExtractorBuilder().build(config);
-        DataSource source = new DefaultDataSourceFactory().build(Paths.get(location.toURI()));
+        DataSource source = DataSourceFactory.instance().build(Paths.get(location.toURI()));
         return extractor.extract(source);
     }
 
diff --git a/pom.xml b/pom.xml
index 86f35a5f..d991d0b4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
 
   jp.cafebabe
   pochi
-  2.5.2
+  2.6.0
   pom
 
   
@@ -228,7 +228,7 @@
       
         org.jacoco
         jacoco-maven-plugin
-        0.8.6
+        0.8.7
         
           
             prepare-agent
diff --git a/site/content/_index.md b/site/content/_index.md
index b7738796..3f9c8ea8 100644
--- a/site/content/_index.md
+++ b/site/content/_index.md
@@ -9,11 +9,11 @@ draft: false
 [![codebeat badge](https://codebeat.co/badges/8e8c5e70-cb07-4f58-941c-3ddb64f3c059)](https://codebeat.co/projects/github-com-tamada-pochi-main)
 
 [![License](https://img.shields.io/badge/License-Apache%202.0-green.svg?style=flat)](https://github.com/tamada/pochi/blob/master/LICENSE)
-[![Version](https://img.shields.io/badge/Version-2.5.2-green.svg)](https://github.com/tamada/pochi/releases/tag/v2.5.2)
+[![Version](https://img.shields.io/badge/Version-2.6.0-green.svg)](https://github.com/tamada/pochi/releases/tag/v2.6.0)
 [![DOI](https://img.shields.io/badge/DOI-10.5281/zenodo.4271132-green.svg)](https://zenodo.org/badge/latestdoi/82773287)
 
-[![Javadoc](https://img.shields.io/badge/Javadoc-v2.5.2-blue?logo=java)](https://tamada.github.io/pochi/apidocs)
-[![Docker](https://img.shields.io/badge/Docker-ghcr.io%2Ftamada%2Fpochi%3A2.5.2-blue?logo=docker)](https://github.com/users/tamada/packages/container/package/pochi)
+[![Javadoc](https://img.shields.io/badge/Javadoc-v2.6.0-blue?logo=java)](https://tamada.github.io/pochi/apidocs)
+[![Docker](https://img.shields.io/badge/Docker-ghcr.io%2Ftamada%2Fpochi%3A2.6.0-blue?logo=docker)](https://github.com/users/tamada/packages/container/package/pochi)
 [![GitHub Discussion](https://img.shields.io/badge/GitHub-Discussions-blue?logo=github)](https://github.com/tamada/pochi/discussions)
 
 Detecting the software theft, the birthmark toolkit for the JVM platform.
diff --git a/site/content/description.md b/site/content/description.md
index f4333397..8aa81965 100644
--- a/site/content/description.md
+++ b/site/content/description.md
@@ -49,7 +49,8 @@ For more detail, see [:ant: Examples](../examples).
 Container images of **pochi** for Docker are:
 
 * [`ghcr.io/tamada/pochi`](https://github.com/users/tamada/packages/container/package/pochi)
-    * `2.5.2`, `latest`
+    * `2.6.0`, `latest`
+    * `2.5.2`
     * `2.5.1`
   * `2.5.0`
   * `2.4.6`
@@ -72,7 +73,7 @@ Container images of **pochi** for Docker are:
     * `1.0.0`
         * accept only `.js` script files.
 
-[![Docker](https://img.shields.io/badge/Docker-ghcir.io%2Ftamada%2Fpochi%3A2.5.2-blue?logo=docker)](https://github.com/users/tamada/packages/container/package/pochi)
+[![Docker](https://img.shields.io/badge/Docker-ghcir.io%2Ftamada%2Fpochi%3A2.6.0-blue?logo=docker)](https://github.com/users/tamada/packages/container/package/pochi)
 
 To run **pochi** on Docker container OS, type the following commands.
 
diff --git a/site/content/install.md b/site/content/install.md
index 993567a8..2b2cd0ad 100644
--- a/site/content/install.md
+++ b/site/content/install.md
@@ -47,10 +47,10 @@ Then, add the dependencies of your `pom.xml`.
 
 | groupId            | artifactId   | version |
 |--------------------|--------------|---------|
-|`jp.cafebabe.pochi` | `kunai2`     | `2.5.2` |
-|`jp.cafebabe.pochi` | `pochi-core` | `2.5.2` |
-|`jp.cafebabe.pochi` | `pochi-api`  | `2.5.2` |
-|`jp.cafebabe.pochi` | `pochi-cmd`  | `2.5.2` |
+|`jp.cafebabe.pochi` | `kunai2`     | `2.6.0` |
+|`jp.cafebabe.pochi` | `pochi-core` | `2.6.0` |
+|`jp.cafebabe.pochi` | `pochi-api`  | `2.6.0` |
+|`jp.cafebabe.pochi` | `pochi-cmd`  | `2.6.0` |
 
 
 ## :briefcase: Requirements
diff --git a/site/pom.xml b/site/pom.xml
index 2a78d53a..d25df25f 100644
--- a/site/pom.xml
+++ b/site/pom.xml
@@ -4,7 +4,7 @@
   
     jp.cafebabe
     pochi
-    2.5.2
+    2.6.0
   
 
   4.0.0
@@ -20,19 +20,19 @@
     
       jp.cafebabe.pochi
       kunai2
-      2.5.2
+      2.6.0
       provided
     
     
       jp.cafebabe.pochi
       pochi-api
-      2.5.2
+      2.6.0
       provided
     
     
       jp.cafebabe.pochi
       pochi-core
-      2.5.2
+      2.6.0
       provided