Gradle プロジェクトで静的解析ツールを使う

# 概要
Gradle では静的解析ツールを使うためのプラグインが標準で提供されています。それらを Gradle プロジェクトに導入する方法を説明します。

間違っている部分があったらご指摘か編集リクエストをくださいますと幸いです。 :bow:

## 記事の背景
[『知識ゼロから学ぶソフトウェアテスト【改訂版】』](http://www.shoeisha.co.jp/book/detail/9784798130606)という本を読んでいたら、ふと自分のプロジェクトの Cyclomatic Complexity (循環的複雑度)を計測したくなりました。

### :question: なぜ Gradle なのか
Java だと Eclipse にプラグインがあるのですが、Eclipse はコードを書くことだけに使いたいと個人的に思っておりまして、ついでに、Gradle プラグインであれば環境の再現が容易だと考え、Gradle から利用できないかと思って調べてみたら、PMD プラグインが標準で用意されていることを知りました。このプラグインは日本語の解説記事も結構多く、それを参考に進めたら特に問題なく計測ができました。

### :do_not_litter: 別に既存の記事があるなら、そのリンクを記載すればよくて、わざわざ記事を書かなくてもよいのではないか
今回はほかの静的解析ツールを使うプラグインも併せて、簡単な使い方を紹介します。

## 静的解析とは
プログラムを実行せずに解析する手法をそう呼ぶそうです。Java の場合、ソースコードやバイトコードをツールで解析させます。機械が自動的に実行することで、人の目では見つけにくい不具合や不整合を見つけ出し、将来埋め込まれうるバグを未然に防いだり、可読性の高いコードに書き換えたりする手助けとできます。

## 実行環境

| Product | Version
|:---|:---
| Java SE | 1.8.0_111
| OS | Windows 10
| Gradle | 3.2.1

## 対象プロジェクト
以前作成した [RatPack のサンプルコード](https://github.com/toastkidjp/ratpack_word_cloud/tree/qiita2) を使います。

```:フォルダ階層(tree&nbsp;/f)
src
├─main
│  ├─java
│  │  └─jp
│  │      └─toastkid
│  │          ├─libs
│  │          │  └─tinysegmenter
│  │          │          CharacterClassifier.java
│  │          │          ScoreMap.java
│  │          │          TinySegmenter.java
│  │          │
│  │          └─ratpack
│  │              │  Main.java
│  │              │
│  │              └─models
│  │                      WordCloud.java
│  │
│  └─resources
│      │  .ratpack
│      │  wordcloud.html
│      │
│      └─public
│          ├─images
│          │      favicon.png
│          │      icon.png
│          │
│          ├─javascripts
│          │  │  jquery-1.6.4.min.js
│          │  │
│          │  ├─d3
│          │  │      d3.js
│          │  │      LICENSE(d3)
│          │  │
│          │  └─d3-cloud
│          │          d3.layout.cloud.js
│          │          index.js
│          │          LICENSE
│          │          package.json
│          │          README.md
│          │
│          └─stylesheets
│                  main.css
│
└─test
    └─java
        └─jp
            └─toastkid
                └─ratpack
                    └─models
                            WordCloudTest.java
```

----
# [PMD](https://pmd.github.io/)
プログラミングの基本的な指標から、問題のあるコードを指摘してくれる静的解析ツールです。

## 導入
プラグイン追加を指定するだけで使えます。

```groovy:build.gradle
apply plugin: 'pmd'
```

## 実行
```$ gradle pmdMain``` を実行してください。

```:実行
$ gradle pmdMain

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:pmdMain

BUILD SUCCESSFUL

Total time: 2.938 secs
```

レポートファイルは ```build/reports/pmd``` に HTML と XML 形式で出力されます。

![pmd1.png](https://qiita-image-store.s3.amazonaws.com/0/102004/6ddc4195-8d63-02b9-d6b3-0b52159f8a11.png)


### rule 追加
デフォルトで使われる basic ではチェック項目が少ないので、少し追加してみましょう。PMDでは下記リンク先に掲載されている rule を使うことができます。

http://pmd.sourceforge.net/pmd-4.3.0/rules/index.html

Cyclomatic Complexity は CodeSize で計測できます。今回は Braces と CodeSize を追加してみましょう。
なお、rule を指定する際は ```java-```という prefix が必要でした。

```groovy:build.gradle
pmd {
  ruleSets = [
    'java-braces',
    'java-codesize',
  ]
}
```

### 実行
```$ gradle pmdMain``` を実行してください。

```:実行
$ gradle pmdMain

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:pmdMain FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':pmdMain'.
> 10 PMD rule violations were found. See the report at: file:///C:/Users/Toast%20kid/Documents/workspace/ratpack_word_cloud-master/build/reports/pmd/main.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 2.266 secs
```

指摘数が一定以上あるため、ビルドが強制的に失敗しました。

### 指摘事項
![pmd2.png](https://qiita-image-store.s3.amazonaws.com/0/102004/f9820580-6e39-de10-9875-cd2da8523f97.png)

```
project\src\main\java\jp\toastkid\libs\tinysegmenter\ScoreMap.java 	1492 	The constructor 'ScoreMap' has a Cyclomatic Complexity of 43.
```

「ScoreMap.java のコンストラクタは Cyclomatic Complexity が43もある」と指摘されました。
この値は低ければ低いほどコードが簡潔であることを表しており、20を超えると要注意、50を超える場合は相当複雑とのことです。CodeSize のデフォルトでは10以上で Warning が出ます。

### Cyclomatic Complexity の計算式
> C = プログラムのルート数 - プログラムの分岐点数 + 2

## :warning: 指摘が多すぎる場合でもビルドを失敗扱いにしない
それが良いことだとは必ずしも言えませんが、そういう場合は ```ignoreFailures = true``` を追加すればビルドが成功します。

### build.gradle に追記

```groovy:build.gradle
pmd {
  ignoreFailures = true
  ruleSets = [
……
}
```

### 実行
```$ gradle pmdMain``` を実行してください。

```:実行
$ gradle pmdMain

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:pmdMain
10 PMD rule violations were found. See the report at: file:///C:/Users/Toast%20kid/Documents/workspace/ratpack_word_cloud-master/build/reports/pmd/main.html

BUILD SUCCESSFUL

Total time: 2.25 secs
```

## 参考
- [Gradle で PMD による静的解析を実行する](http://maku77.github.io/gradle/pmd/pmd.html)
- [第33章 PMDプラグイン](http://gradle.monochromeroad.com/docs/userguide/pmd_plugin.html)
- [PmdExtension](http://gradle.monochromeroad.com/docs/dsl/org.gradle.api.plugins.quality.PmdExtension.html)
- [PMD Rules](http://pmd.sourceforge.net/pmd-4.3.0/rules/index.html)

----
# [FindBugs](http://findbugs.sourceforge.net/)
Java のコードからバグの温床になりそうな部分を指摘してくれる静的解析ツールです。

## 導入
build.gradle に追記します。

```groovy:build.gradle
apply plugin: 'findbugs'
```

## 実行
```$ gradle findbugsMain``` コマンドで解析を実行します。

```:実行
$ gradle findbugsMain

:compileJava
:processResources
:classes
:findbugsMain
Download https://repo1.maven.org/maven2/com/google/code/findbugs/findbugs/3.0.1/findbugs-3.0.1.pom

...(中略)...

Download https://repo1.maven.org/maven2/org/ow2/asm/asm/5.0.2/asm-5.0.2.jar

:findbugsMain
FindBugs rule violations were found. See the report at: projet/build/reports/findbugs/main.xml
```

## レポート
解析結果はXMLで出力されます。HTML で見たいのですがオプションが見当たりませんでした。

```xml:Sample
  <BugInstance type="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE" priority="2" rank="13" abbrev="NP" category="STYLE">
    <Class classname="jp.toastkid.jfx.common.Style">
      <SourceLine classname="jp.toastkid.jfx.common.Style" start="36" end="137" sourcefile="Style.java" sourcepath="jp/toastkid/jfx/common/Style.java"/>
    </Class>
    <Method classname="jp.toastkid.jfx.common.Style" name="findJarResourceDir" signature="()Ljava/util/List;" isStatic="true">
      <SourceLine classname="jp.toastkid.jfx.common.Style" start="117" end="137" startBytecode="0" endBytecode="633" sourcefile="Style.java" sourcepath="jp/toastkid/jfx/common/Style.java"/>
    </Method>
    <LocalVariable name="?" register="-1" pc="219" role="LOCAL_VARIABLE_UNKNOWN"/>
    <SourceLine classname="jp.toastkid.jfx.common.Style" start="133" end="133" startBytecode="219" endBytecode="219" sourcefile="Style.java" sourcepath="jp/toastkid/jfx/common/Style.java" role="SOURCE_LINE_INVOKED"/>
    <SourceLine classname="jp.toastkid.jfx.common.Style" start="133" end="133" startBytecode="216" endBytecode="216" sourcefile="Style.java" sourcepath="jp/toastkid/jfx/common/Style.java" role="SOURCE_LINE_KNOWN_NULL"/>
    <Property name="edu.umd.cs.findbugs.detect.NullDerefProperty.DEREFS_ARE_CLONED" value="true"/>
  </BugInstance>
```

## :warning: 指摘が多すぎる場合でもビルドを失敗扱いにしない
このプラグインも ```ignoreFailures = true``` を追加すれば、どれだけ warning が出ていてもビルドが失敗扱いになりません。

```groovy:build.gradle
findbugs {
  ignoreFailures = true
```

## 参考
- [第31章 FindBugsプラグイン](http://gradle.monochromeroad.com/docs/userguide/findbugs_plugin.html)
- [FindBugsExtension](http://gradle.monochromeroad.com/docs/dsl/org.gradle.api.plugins.quality.FindBugsExtension.html)

----
# [Checkstyle](http://checkstyle.sourceforge.net/)
Checkstyle は Java のソースコードがコーディング規約に則っていることを確認するためのツールです。

## 導入
build.gradle に下記を1行追加します。

```groovy:build.gradle
apply plugin: 'checkstyle'
```

## :no_entry: 実行(失敗)
```$ gradle check``` でチェックを実行します。このプラグイン単独でのチェックをする場合は ```$ gradle checkstyleMain``` で可能です。

```:実行(失敗)
$ gradle check

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:checkstyleMain
Download https://repo1.maven.org/maven2/com/puppycrawl/tools/checkstyle/5.9/checkstyle-5.9.pom

……(中略)……

Download https://repo1.maven.org/maven2/com/google/guava/guava-jdk5/14.0.1/guava-jdk5-14.0.1.jar
:checkstyleMain FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':checkstyleMain'.
> Unable to create a Checker: unable to find project\config\checkstyle\checkstyle.xml

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 7.326 secs
```

## 設定ファイルの追加
何もない状態でチェックを実行すると上記のように失敗します。checkstyleの設定ファイルを用意する必要があります。
というわけで、下記から [Sun の規約を再現した設定ファイル](https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/sun_checks.xml)を取得します。

https://github.com/checkstyle/checkstyle

プロジェクトのルートに ```config/checkstyle``` フォルダを追加して、そこに ```checkstyle.xml``` を置いてください。

## :no_entry: 再度実行(失敗)
先ほどとコマンドは同じです。

```:実行
$ gradle check

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:checkstyleMain FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':checkstyleMain'.
> Unable to create a Checker: Property 'fileExtensions' in module Checker does not exist, please check the documentation

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 1.782 secs
```

fileExtensions が存在しないと言われています。

## コメントアウトして実行
当該箇所をコメントアウトして実行してみます。

```:実行
$ gradle check

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:checkstyleMain
[ant:checkstyle] project\src\main\java\jp\toastkid\libs\tinysegmenter\CharacterClassifier.java:0: Missing package-info.java file.
[ant:checkstyle] project\src\main\java\jp\toastkid\libs\tinysegmenter\CharacterClassifier.java:0: ファイルが新しい行で終了していません。

……(あまりに指摘が多すぎるので省略)……

[ant:checkstyle] project\src\main\java\jp\toastkid\ratpack\models\WordCloud.java:79:58: 'str' には @param タグが必要です。
:checkstyleMain FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':checkstyleMain'.
> Checkstyle rule violations were found. See the report at: project/build/reports/checkstyle/main.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 3.639 secs
```

いやあ、今回用意したのが実にひどいコードでしたね……このプラグインでも ```ignoreFailures``` が false の場合は、warning が出ているとビルドを失敗させます。レポートは生成されていますので見てみましょう。

## レポート
レポートファイルは ```build/reports/checkstyle/``` 以下に、html と xml で生成されます。

![cs.png](https://qiita-image-store.s3.amazonaws.com/0/102004/5f85cf64-879f-1892-c524-a3554ccc60f3.png)

## :warning: 指摘が多すぎる場合でもビルドを失敗扱いにしない
このプラグインも ```ignoreFailures = true``` を追加すれば、どれだけ warning が出ていてもビルドが失敗扱いになりません。

```groovy:build.gradle
checkstyle {
  ignoreFailures = true
```

## 参考
- [第29章 Checkstyleプラグイン](http://gradle.monochromeroad.com/docs/userguide/checkstyle_plugin.html)
- [CheckstyleExtension](http://gradle.monochromeroad.com/docs/dsl/org.gradle.api.plugins.quality.CheckstyleExtension.html)

----
# [JaCoCo](http://www.eclemma.org/jacoco/)
テストレポートを出力するプラグインです。テストカバレッジを計測して視覚的に参照できます。名前は "**Ja**va **Co**de **Co**verage" のアクロニムのようです。

## 導入
build.gradle に JaCoCo プラグインを追加します。

```groovy:build.gradle
apply plugin: "jacoco"
```

## 実行
テストのビルドが実行されている必要があります。今回は ```$ gradle test jacocoTestReport``` で実行します。

```:実行
$ gradle test jacocoTestReport

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
:jacocoTestReport

BUILD SUCCESSFUL

Total time: 3.448 secs
```

## レポート
デフォルトでは ```build/reports/jacoco/test/html/index.html``` に HTML 形式でテストレポートが生成されています。

### packages
![jacoco.png](https://qiita-image-store.s3.amazonaws.com/0/102004/e21af75e-7d74-2a51-bb33-d4ac11b80f73.png)

### classes
![jacoco2.png](https://qiita-image-store.s3.amazonaws.com/0/102004/b0a29c56-c4cd-c429-93ba-819670040268.png)

### methods
![jacoco3.png](https://qiita-image-store.s3.amazonaws.com/0/102004/52d31b4b-c425-c78d-ff40-1b1de1e75152.png)

packages -> classes -> methods の順に細かくなっていきます。

### 詳細
![jacoco4.png](https://qiita-image-store.s3.amazonaws.com/0/102004/ac47d0fe-a9ae-28b8-d3b0-6267646afed8.png)

メソッド名を選択するとクラス内でどの部分がテストコードから呼び出されたかを緑背景、どこを通らなかったかを赤背景で示してくれます。非常にわかりやすいですね。

## 参考
- [Chapter 34. The JaCoCo Plugin](http://gradle.monochromeroad.com/docs/userguide/jacoco_plugin.html)

----
# [JDpend](http://clarkware.com/software/JDepend.html)
package 単位での静的解析をするツールのようです。

## 導入

```groovy:build.gradle
apply plugin: 'jdepend'
```

## 実行
```$ gradle jdependMain``` で実行します。

```:実行
$ gradle jdependMain

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jdependMain
Download https://repo1.maven.org/maven2/jdepend/jdepend/2.9.1/jdepend-2.9.1.pom
Download https://repo1.maven.org/maven2/org/apache/ant/ant-jdepend/1.9.6/ant-jdepend-1.9.6.pom
Download https://repo1.maven.org/maven2/org/apache/ant/ant-parent/1.9.6/ant-parent-1.9.6.pom
Download https://repo1.maven.org/maven2/jdepend/jdepend/2.9.1/jdepend-2.9.1.jar
Download https://repo1.maven.org/maven2/org/apache/ant/ant-jdepend/1.9.6/ant-jdepend-1.9.6.jar
[ant:jdependreport] ependMain

[ant:jdependreport] Unknown constant: 18

BUILD SUCCESSFUL

Total time: 3.719 secs
```

## レポート
レポートファイルは ```build/reports/jdepend``` に XML 形式で生成されます。

## 指摘が多すぎる場合でもビルドを失敗扱いにしない
このプラグインも ```ignoreFailures = true``` を追加すれば、どれだけ warning が出ていてもビルドが失敗扱いになりません。

```groovy:build.gradle
JDepend {
  ignoreFailures = true
```


## 参考
- [第32章 JDependプラグイン](http://gradle.monochromeroad.com/docs/userguide/jdepend_plugin.html)
- [JDependExtension](http://gradle.monochromeroad.com/docs/dsl/org.gradle.api.plugins.quality.JDependExtension.html)
- [パッケージ間の循環依存を自動で検出する](https://blog.guildworks.jp/2014/09/25/find-cyclic-dependencies/)

----
# プロジェクトレポートプラグイン
静的解析ツールとは関係ありませんが、こういうプラグインもあるらしいと知ったので、ついでに試してみます。

## 導入
build.gradle にプラグインを追記します。

```groovy:build.gradle
apply plugin: 'project-report'
```

## 実行
```$ gradle projectReport``` ですべてのレポートを生成します。

```:実行
$ gradle projectReport

:dependencyReport
:htmlDependencyReport
:propertyReport
:taskReport
:projectReport

BUILD SUCCESSFUL

Total time: 1.472 secs
```

## レポート
```build/reports/project/dependencies/root.html``` に出力されます。表示には JavaScript の実行許可が必要です。

![projectReport.png](https://qiita-image-store.s3.amazonaws.com/0/102004/afbec792-774d-583f-ce7f-50f8aad62ea9.png)


アプリケーションのコンパイル依存だけでなくプラグインの依存も表示してくれます。テキスト形式が良い場合は ```build/reports/project/dependencies.txt```に生成されていますので、そちらを参照するとよいでしょう。

## 参考
- [第41章 プロジェクトレポートプラグイン](http://gradle.monochromeroad.com/docs/userguide/project_reports_plugin.html)

----
# [License Gradle Plugin](https://github.com/hierynomus/license-gradle-plugin)
標準のプラグインではありませんが、導入が容易で役に立つと思いましたので、ついでに書いておきます。これはプロジェクトのライセンスを依存まで辿ってレポートに出力してくれるプラグインです。
会社によってはOSSライブラリの利用前や成果物リリース前にライセンスをチェックする必要があるかもしれませんが、そういう時に逐一 pom.xml を辿るのが苦痛な方は、このプラグインの導入を検討してみてもよいかもしれません。

## 導入
[gradleでdependenciesのライセンス一覧を出力する](http://blog.olivinecafe.info/post/105264504040/gradle%E3%81%A7dependencies%E3%81%AE%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9%E4%B8%80%E8%A6%A7%E3%82%92%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B) を参考にすれば、すぐ導入できます。

具体的には、 build.gradle に下記の通り追記すれば準備は完了です。

```groovy:build.gradle
apply plugin: "com.github.hierynomus.license"

......

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "gradle.plugin.nl.javadude.gradle.plugins:license-gradle-plugin:0.13.1"
  }
}
```

## 実行
```$ gradle downloadLicenses``` を実行してください。

```:実行
$ gradle downloadLicenses

:downloadLicenses

BUILD SUCCESSFUL

Total time: 10.753 secs
```

## レポート
```build/reports/license/``` フォルダに2種類の HTML と XML、合わせて4ファイルが生成されています。

| ファイル名 | 説明
|:---|:---
| license-dependency | ライセンス単位でのまとめ
| dependency-license | 依存単位でのまとめ

### license-dependency
![license2.png](https://qiita-image-store.s3.amazonaws.com/0/102004/307cce5c-5a7c-7aad-e9b0-0865a652a4ba.png)

### dependency-license
![license1.png](https://qiita-image-store.s3.amazonaws.com/0/102004/b6621695-e5d0-68c8-4aac-dbccd9ebf13e.png)

GPL 系のライセンスが入っていないかをチェックするなら ```license-dependency``` が役立ちますし、個々のライセンスを調べる必要がある場合は ```dependency-license``` がよいでしょう。

## 参考
- [gradleでdependenciesのライセンス一覧を出力する](http://blog.olivinecafe.info/post/105264504040/gradle%E3%81%A7dependencies%E3%81%AE%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9%E4%B8%80%E8%A6%A7%E3%82%92%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B)

----
# まとめ
Gradle プラグインから簡単に用いることのできる静的解析ツールの使い方を紹介しました。こうしたツールは毎回コマンドを打って実行するのではなく、 CI を通して定期的に自動実行していくことが重要です。

## サンプル
- [今回のサンプルプロジェクト](https://github.com/toastkidjp/static_analysis_example/tree/qiita)

## 今回生成されたレポートのフォルダ階層

```:フォルダ階層(tree&nbsp;/f)
build
  │
  └─reports
      ├─jacoco
      │  └─test
      │      └─html
      │          │  index.html
      │          │  jacoco-sessions.html
      │          │
      │          ├─jacoco-resources
      │          │      branchfc.gif
      │          │      branchnc.gif
      │          │      branchpc.gif
      │          │      bundle.gif
      │          │      class.gif
      │          │      down.gif
      │          │      greenbar.gif
      │          │      group.gif
      │          │      method.gif
      │          │      package.gif
      │          │      prettify.css
      │          │      prettify.js
      │          │      redbar.gif
      │          │      report.css
      │          │      report.gif
      │          │      session.gif
      │          │      sort.gif
      │          │      sort.js
      │          │      source.gif
      │          │      up.gif
      │          │
      │          ├─jp.toastkid.libs.tinysegmenter
      │          │      CharacterClassifier.html
      │          │      CharacterClassifier.java.html
      │          │      index.html
      │          │      index.source.html
      │          │      ScoreMap.html
      │          │      ScoreMap.java.html
      │          │      TinySegmenter.html
      │          │      TinySegmenter.java.html
      │          │
      │          ├─jp.toastkid.ratpack
      │          │      index.html
      │          │      index.source.html
      │          │      Main.html
      │          │      Main.java.html
      │          │
      │          └─jp.toastkid.ratpack.models
      │                  index.html
      │                  index.source.html
      │                  WordCloud.html
      │                  WordCloud.java.html
      │
      ├─license
      │      dependency-license.html
      │      dependency-license.xml
      │      license-dependency.html
      │      license-dependency.xml
      │
      ├─pmd
      │      main.html
      │      main.xml
      │
      ├─project
      │  │  dependencies.txt
      │  │  properties.txt
      │  │  tasks.txt
      │  │
      │  └─dependencies
      │      │  index.html
      │      │  root.html
      │      │  root.js
      │      │
      │      ├─css
      │      │      base-style.css
      │      │      style.css
      │      │      tree.css
      │      │
      │      ├─images
      │      │      d.gif
      │      │      d.png
      │      │      throbber.gif
      │      │
      │      └─js
      │              jquery.jstree.js
      │              jquery.min-1.11.0.js
      │              script.js
      │
      └─tests
          └─test
              │  index.html
              │
              ├─classes
              │      jp.toastkid.ratpack.models.WordCloudTest.html
              │
              ├─css
              │      base-style.css
              │      style.css
              │
              ├─js
              │      report.js
              │
              └─packages
                      jp.toastkid.ratpack.models.html
```